Foxhound 1.2 is now available...
Easier management of up to 100 Monitor sessions.
Faster scrolling through performance history.
Better support for adhoc reporting.

Friday, June 3, 2011

The USE Statement In SQL Anywhere

Question: How do I code "USE database" in SQL Anywhere? I'm trying to write a batch file to update several databases on the same server.

Answer: Use (pun intended) the CONNECT and SET CONNECTION statements in your SQL file, then run that SQL file in batch mode via dbisql.

Here is a simple example of how CONNECT can establish named connections to three different databases, and then switch back and forth between those connections via SET CONNECTION:


CONNECT TO ddd1 DATABASE ddd1 AS ddd1_con USER dba IDENTIFIED BY sql;
CONNECT TO ddd2 DATABASE ddd2 AS ddd2_con USER dba IDENTIFIED BY sql;
CONNECT TO ddd3 DATABASE ddd3 AS ddd3_con USER dba IDENTIFIED BY sql;

SET CONNECTION ddd1_con;
SET CONNECTION ddd2_con;
SET CONNECTION ddd3_con;
Caution: This stuff doesn't fully work in dbisql's GUI mode. I don't know why, but there you go... in batch mode the CONNECT statement can be used to create and maintain a named connection that can be reused via SET CONNECTION. However, in GUI mode the second CONNECT closes the first connection even if you gave that one a name. Yup, that's a bummer... but you can use CONNECT to switch back and forth between databases in GUI mode if you don't mind only having one connection open at a time, so maybe it doesn't matter to you.
There are two different forms of CONNECT; the format shown above is for shared memory connections, and CONNECT USING can be used with TCPIP connections:

CONNECT USING 'SERVER=ddd1;DBN=ddd1;UID=dba;PWD=sql;LINKS=TCPIP;CON=ddd1_con';
CONNECT USING 'SERVER=ddd2;DBN=ddd2;UID=dba;PWD=sql;LINKS=TCPIP;CON=ddd2_con';
CONNECT USING 'SERVER=ddd3;DBN=ddd3;UID=dba;PWD=sql;LINKS=TCPIP;CON=ddd3_con';

SET CONNECTION ddd1_con;
SET CONNECTION ddd2_con;
SET CONNECTION ddd3_con;
Caution: CONNECT USING is a SQL statement so don't use "double quotes" around the connection string, use 'single quotes' ...and don't forget the CON= connection parameter; you have to give the connection a name if you want to use the SET CONNECTION statement.
For the skeptical among you, here's proof that it works. First, here a Windows command file to create and start three separate databases, then run dbisql in batch mode to run a SQL script:

"%SQLANY12%\bin32\dbinit.exe" ddd1.db
"%SQLANY12%\bin32\dbinit.exe" ddd2.db
"%SQLANY12%\bin32\dbinit.exe" ddd3.db

"%SQLANY12%\bin32\dbspawn.exe" -f "%SQLANY12%\bin32\dbeng12.exe" -x none ddd1.db
"%SQLANY12%\bin32\dbspawn.exe" -f "%SQLANY12%\bin32\dbeng12.exe" -x none ddd2.db
"%SQLANY12%\bin32\dbspawn.exe" -f "%SQLANY12%\bin32\dbeng12.exe" -x none ddd3.db

"%SQLANY12%\bin32\dbisql.com" READ ENCODING Cp1252 "06s script demonstrate_set_connection.sql"

Here's what the SQL script "06s script demonstrate_set_connection.sql" contains:

----------------------------------------------------------------------------
-- Establish 3 connections from one dbisql session.

CONNECT TO ddd1 DATABASE ddd1 AS ddd1_con USER dba IDENTIFIED BY sql;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ),
' CONNECT TO ', PROPERTY ( 'Name' ),
' DATABASE ', DB_PROPERTY ( 'Name' ),
' AS ', CONNECTION_PROPERTY ( 'Name' ) ) TO CONSOLE;

CONNECT TO ddd2 DATABASE ddd2 AS ddd2_con USER dba IDENTIFIED BY sql;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ),
' CONNECT TO ', PROPERTY ( 'Name' ),
' DATABASE ', DB_PROPERTY ( 'Name' ),
' AS ', CONNECTION_PROPERTY ( 'Name' ) ) TO CONSOLE;

CONNECT TO ddd3 DATABASE ddd3 AS ddd3_con USER dba IDENTIFIED BY sql;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ),
' CONNECT TO ', PROPERTY ( 'Name' ),
' DATABASE ', DB_PROPERTY ( 'Name' ),
' AS ', CONNECTION_PROPERTY ( 'Name' ) ) TO CONSOLE;

----------------------------------------------------------------------------
-- INSERT a row on each connection.

SET CONNECTION ddd1_con;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' SET CONNECTION ddd1_con;' ) TO CONSOLE;
BEGIN
DROP TABLE t1;
EXCEPTION WHEN OTHERS THEN
END;
CREATE TABLE t1 ( pkey INTEGER NOT NULL PRIMARY KEY );
INSERT t1 VALUES ( 111 );
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' INSERT t1 VALUES ( 111 );' ) TO CONSOLE;

WAITFOR DELAY '00:00:02';

SET CONNECTION ddd2_con;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' SET CONNECTION ddd2_con;' ) TO CONSOLE;
BEGIN
DROP TABLE t2;
EXCEPTION WHEN OTHERS THEN
END;
CREATE TABLE t2 ( pkey INTEGER NOT NULL PRIMARY KEY );
INSERT t2 VALUES ( 222 );
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' INSERT t2 VALUES ( 222 );' ) TO CONSOLE;

WAITFOR DELAY '00:00:02';

SET CONNECTION ddd3_con;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' SET CONNECTION ddd3_con;' ) TO CONSOLE;
BEGIN
DROP TABLE t3;
EXCEPTION WHEN OTHERS THEN
END;
CREATE TABLE t3 ( pkey INTEGER NOT NULL PRIMARY KEY );
INSERT t3 VALUES ( 333 );
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' INSERT t3 VALUES ( 333 );' ) TO CONSOLE;

WAITFOR DELAY '00:00:02';

----------------------------------------------------------------------------
-- ROLLBACK, then INSERT a different row.

SET CONNECTION ddd1_con;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' SET CONNECTION ddd1_con;' ) TO CONSOLE;
ROLLBACK;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' ROLLBACK;' ) TO CONSOLE;
INSERT t1 VALUES ( 1 );
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' INSERT t1 VALUES ( 1 );' ) TO CONSOLE;

WAITFOR DELAY '00:00:02';

SET CONNECTION ddd2_con;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' SET CONNECTION ddd2_con;' ) TO CONSOLE;
ROLLBACK;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' ROLLBACK;' ) TO CONSOLE;
INSERT t2 VALUES ( 2 );
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' INSERT t2 VALUES ( 2 );' ) TO CONSOLE;

WAITFOR DELAY '00:00:02';

SET CONNECTION ddd3_con;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' SET CONNECTION ddd3_con;' ) TO CONSOLE;
ROLLBACK;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' ROLLBACK;' ) TO CONSOLE;
INSERT t3 VALUES ( 3 );
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' INSERT t3 VALUES ( 3 );' ) TO CONSOLE;

WAITFOR DELAY '00:00:02';

----------------------------------------------------------------------------
-- COMMIT, then show final row.

SET CONNECTION ddd1_con;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' SET CONNECTION ddd1_con;' ) TO CONSOLE;
COMMIT;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' COMMIT;' ) TO CONSOLE;
BEGIN
DECLARE @pkey INTEGER;
SELECT t1.pkey INTO @pkey FROM t1;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' t1.pkey = ', @pkey ) TO CONSOLE;
END;

WAITFOR DELAY '00:00:02';

SET CONNECTION ddd2_con;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' SET CONNECTION ddd2_con;' ) TO CONSOLE;
COMMIT;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' COMMIT;' ) TO CONSOLE;
BEGIN
DECLARE @pkey INTEGER;
SELECT t2.pkey INTO @pkey FROM t2;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' t2.pkey = ', @pkey ) TO CONSOLE;
END;

WAITFOR DELAY '00:00:02';

SET CONNECTION ddd3_con;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' SET CONNECTION ddd3_con;' ) TO CONSOLE;
COMMIT;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' COMMIT;' ) TO CONSOLE;
BEGIN
DECLARE @pkey INTEGER;
SELECT t3.pkey INTO @pkey FROM t3;
MESSAGE STRING ( CURRENT TIMESTAMP, ' ', CONNECTION_PROPERTY ( 'Name' ), ' t3.pkey = ', @pkey ) TO CONSOLE;
END;

Here's what the dbisql batch session displays as it runs:

Connected to "ddd1" on "ddd1".
Connected to "ddd2" on "ddd2".
Connected to "ddd3" on "ddd3".
1 row(s) inserted
1 row(s) inserted
1 row(s) inserted
1 row(s) inserted
1 row(s) inserted
1 row(s) inserted
1 row(s) affected
1 row(s) affected
1 row(s) affected
Execution time: 18.14 seconds

Here's the MESSAGE output as it appeared in the three separate server console windows for ddd1, ddd2 and ddd3:

2011-06-02 12:04:46.978 ddd1_con CONNECT TO ddd1 DATABASE ddd1 AS ddd1_con
2011-06-02 12:04:47.110 ddd1_con SET CONNECTION ddd1_con;
2011-06-02 12:04:47.602 ddd1_con INSERT t1 VALUES ( 111 );
2011-06-02 12:04:54.776 ddd1_con SET CONNECTION ddd1_con;
2011-06-02 12:04:54.807 ddd1_con ROLLBACK;
2011-06-02 12:04:54.824 ddd1_con INSERT t1 VALUES ( 1 );
2011-06-02 12:05:01.114 ddd1_con SET CONNECTION ddd1_con;
2011-06-02 12:05:01.144 ddd1_con COMMIT;
2011-06-02 12:05:01.168 ddd1_con t1.pkey = 1

2011-06-02 12:04:47.052 ddd2_con CONNECT TO ddd2 DATABASE ddd2 AS ddd2_con
2011-06-02 12:04:49.739 ddd2_con SET CONNECTION ddd2_con;
2011-06-02 12:04:50.171 ddd2_con INSERT t2 VALUES ( 222 );
2011-06-02 12:04:56.946 ddd2_con SET CONNECTION ddd2_con;
2011-06-02 12:04:56.958 ddd2_con ROLLBACK;
2011-06-02 12:04:56.971 ddd2_con INSERT t2 VALUES ( 2 );
2011-06-02 12:05:03.281 ddd2_con SET CONNECTION ddd2_con;
2011-06-02 12:05:03.294 ddd2_con COMMIT;
2011-06-02 12:05:03.304 ddd2_con t2.pkey = 2

2011-06-02 12:04:47.105 ddd3_con CONNECT TO ddd3 DATABASE ddd3 AS ddd3_con
2011-06-02 12:04:52.286 ddd3_con SET CONNECTION ddd3_con;
2011-06-02 12:04:52.743 ddd3_con INSERT t3 VALUES ( 333 );
2011-06-02 12:04:59.059 ddd3_con SET CONNECTION ddd3_con;
2011-06-02 12:04:59.071 ddd3_con ROLLBACK;
2011-06-02 12:04:59.083 ddd3_con INSERT t3 VALUES ( 3 );
2011-06-02 12:05:05.386 ddd3_con SET CONNECTION ddd3_con;
2011-06-02 12:05:05.398 ddd3_con COMMIT;
2011-06-02 12:05:05.408 ddd3_con t3.pkey = 3

When you take the MESSAGE output and sort it by timestamp, you can see how one dbisql session was able to switch back and forth between three separate connections; not only that, but it could do that without disturbing the transactions that were running on each of those connections:

2011-06-02 12:04:46.978 ddd1_con CONNECT TO ddd1 DATABASE ddd1 AS ddd1_con

2011-06-02 12:04:47.052 ddd2_con CONNECT TO ddd2 DATABASE ddd2 AS ddd2_con

2011-06-02 12:04:47.105 ddd3_con CONNECT TO ddd3 DATABASE ddd3 AS ddd3_con

2011-06-02 12:04:47.110 ddd1_con SET CONNECTION ddd1_con;
2011-06-02 12:04:47.602 ddd1_con INSERT t1 VALUES ( 111 );

2011-06-02 12:04:49.739 ddd2_con SET CONNECTION ddd2_con;
2011-06-02 12:04:50.171 ddd2_con INSERT t2 VALUES ( 222 );

2011-06-02 12:04:52.286 ddd3_con SET CONNECTION ddd3_con;
2011-06-02 12:04:52.743 ddd3_con INSERT t3 VALUES ( 333 );

2011-06-02 12:04:54.776 ddd1_con SET CONNECTION ddd1_con;
2011-06-02 12:04:54.807 ddd1_con ROLLBACK;
2011-06-02 12:04:54.824 ddd1_con INSERT t1 VALUES ( 1 );

2011-06-02 12:04:56.946 ddd2_con SET CONNECTION ddd2_con;
2011-06-02 12:04:56.958 ddd2_con ROLLBACK;
2011-06-02 12:04:56.971 ddd2_con INSERT t2 VALUES ( 2 );

2011-06-02 12:04:59.059 ddd3_con SET CONNECTION ddd3_con;
2011-06-02 12:04:59.071 ddd3_con ROLLBACK;
2011-06-02 12:04:59.083 ddd3_con INSERT t3 VALUES ( 3 );

2011-06-02 12:05:01.114 ddd1_con SET CONNECTION ddd1_con;
2011-06-02 12:05:01.144 ddd1_con COMMIT;
2011-06-02 12:05:01.168 ddd1_con t1.pkey = 1

2011-06-02 12:05:03.281 ddd2_con SET CONNECTION ddd2_con;
2011-06-02 12:05:03.294 ddd2_con COMMIT;
2011-06-02 12:05:03.304 ddd2_con t2.pkey = 2

2011-06-02 12:05:05.386 ddd3_con SET CONNECTION ddd3_con;
2011-06-02 12:05:05.398 ddd3_con COMMIT;
2011-06-02 12:05:05.408 ddd3_con t3.pkey = 3

To tell you the truth, I don't know if SET CONNECTION is the same as, different from, better than or worse than the USE statement in Transact/SQL. If the SQL Server docs didn't suck so badly I would know the answer without testing... just a minute... OK, there, it's on my to do list :)


0 comments: