From: Ian Boyd on
>> It is important to note that whenever you write a statement that contains
>> ';' due to "substatements" you need to make sure the statement delimiter
>> (what you know as "go" I think) is set to a value other than ';' (imagine
>> placing 'go' after each line in a T-SQL procedure.. same confusion).
>
> i've never had to use a "go" in T-SQL. All the text i submit is one batch.
> There is no ; needed at the end of every statement.

i think i see the confusion. SQL Server has no "substatements". And
statements don't have to be separated by semi-colons.
If i were to give the OLE DB Provider for Microsoft SQL Server the following
string, as one long string (and this example is taken from the SQL Server
documentation):

string myQuery = "DECLARE @MyMsg VARCHAR(50)
SELECT @MyMsg = 'Hello, World.'

-- Yields an error because @MyMsg not declared in this batch.
PRINT @MyMsg

SELECT @@VERSION;
-- Yields an error: Must be EXEC sp_who if not first statement in
-- batch.
EXECUTE sp_who"

Connection.Execute(myQuery);

This will just run. The entire set of all the statments are sent over to SQL
Server as one "batch", and SQL Server runs them.

Additionally, there is a standard feature built into the query tools, and
that is the use of the keyword "go". It is not a T-SQL keyword, it is a word
only recognized by Microsoft's query tools.

If you entered the following into Microsoft's Query Analyzer;

<quote>
DECLARE @MyMsg VARCHAR(50)
SELECT @MyMsg = 'Hello, World.'
GO -- @MyMsg is not valid after this GO ends the batch.

-- Yields an error because @MyMsg not declared in this batch.
PRINT @MyMsg
GO

SELECT @@VERSION;
-- Yields an error: Must be EXEC sp_who if not first statement in
-- batch.
sp_who
</quote>

The query tool will now send 3 individual batches to SQL Server. Each batch
is separate from the others. You are free to send over all the text in one
batch, or you can have the tool send it over the multiple batches. But as it
indicated in the example query, variables declared in one batch will no
longer exist in the next batch.



So, when i'm trying to do something in DB2-SQL, e.g.:

DECLARE UserID integer
SET UserID =
( SELECT application_ID()
FROM sysibm.sysdummy1
)
update MyTable
SET UserID = UserID
WHERE UserID IS NULL
delete from MyTable
WHERE UserID = 3
select * from MyTable


i expect all that text to be sent to to DB2, i expect DB2 to run the query,
and return me what it is supposed to return me. But DB2 doesn't just read
the SQL it's given. DB2 seems to require semicolons to separate each
statment. e.g.:

DECLARE UserID integer;
SET UserID =
( SELECT application_ID()
FROM sysibm.sysdummy1
);
update MyTable
SET UserID = UserID
WHERE UserID IS NULL;
delete from MyTable
WHERE UserID = 3;
select * from MyTable;

Which is fine. It would be nicer if it didn't need semicolons, but okay,
i'll live with it.
But now, in addition, this apparently isn't enough. Just because i've given
DB2 some statements to run, doesn't mean that it will run them. For some
reason, i have to tell it that the SQL it just received really is all
together in one "batch" (to steal a MSSQL term)

BEGIN ATOMIC
DECLARE UserID integer;
SET UserID =
( SELECT application_ID()
FROM sysibm.sysdummy1
);
update MyTable
SET UserID = UserID
WHERE UserID IS NULL;
delete from MyTable
WHERE UserID = 3;
select * from MyTable;
END

But not only that, i have to actually begin the batch with the keywords
BEGIN ATOMIC and end the batch with END. So as i understand it, just sending
a bunch of SQL to DB2 is not enough for it to decide to run the batch, i
have to explicitly tell it that it is a batch. Fine, okay, messy, but i
think i understand.

But wait, i don't understand. Because i can send the SQL to create a stored
procedure

CREATE PROCEDURE doStuff(...)
BEGIN
...
END

and i don't have to wrap the batch in BEGIN ATOMIC..END e.g.

BEGIN ATOMIC
CREATE PROCEDURE doStuff(...)
BEGIN
...
END
END

So perhaps because it is a CREATE PROCEDURE, or CREATE TRIGGER, or CREATE
TABLE, etc that i can omit the BEGIN ATMIC...END around the statement in
those batches. Perhaps it is because a CREATE PROCEDURE, CREATE TRIGGER,
CREATE TABLE itself is a single statement that it doesn't need to be
wrapped. Maybe batches that only consist of a single statement don't need to
be wrapped. No, that's not true either:

DECLARE myValue int;

fails also. Maybe Create XXXXX statements are just special like that.

But now, to throw another level of confusion into it, inside a CREATE
TRIGGER, you DO have to have BEGIN ATOMIC...END, but not inside a CREATE
PROCEDURE.



So, if you read this, please try not to respond to things in detail.
Hopefully you can see my confusion, and this must be because i have a
different mental picture of how SQL Server is given and runs T-SQL and how
DB2 is given and runs T-SQL. If you can see the error in my understanding,
and point out exactly where my thinking is wrong - that would be great. It
would be nice to have an understanding, rather than hoping understanding
will come after being exposed to dozens of disprate examples.


From: Dave Hughes on
Hi Ian,

I must admit I'm not at all familiar with T-SQL, but from your posts I
get the impression that it allows procedural type stuff (like declaring
variables) *outside* a procedure or trigger.

Up until fairly recently, this was impossible in DB2 (if you wanted
procedural logic, you either used a stored procedure inside the
database, or an external application to manipulate the data). However,
more recent versions (I think it first appeared in version 7 or
thereabouts) have introduced a limited version of this capability with
the BEGIN ATOMIC statement. Here's an example from a command line
session under Linux:

$ db2 -td!
(c) Copyright IBM Corporation 1993,2002
Command Line Processor for DB2 SDK 8.2.0
...
[boring help snipped]
...
db2 => BEGIN ATOMIC
db2 (cont.) => DECLARE SAVEDUSERID INTEGER;
db2 (cont.) => END!
DB20000I The SQL command completed successfully.

This construct is like declaring a stored procedure in that each
statement within the block must be terminated with semi-colon, while
the block as a whole counts as a single SQL statement and must be
terminated with some alternate character (hence why I used the -td!
switch in the example above to set the statement terminator to bang).

Where it differs from a stored procedure is that the ATOMIC keyword
after BEGIN is mandatory. ATOMIC indicates that the entire block of
instructions will be executed in a single transaction (hence "atomic").
Therefore, you can't use COMMIT / ROLLBACK within the block (only
outside it).

However, I suspect mere syntactic differences are not the major problem
here. You're thinking of SQL in a procedural manner (which I guess is
perfectly fine for SQL Server but will complicate things for you
horribly in DB2). You need to think of SQL as a "functional" language,
not an "imperative" (procedural) language.

Therefore, instead of writing something like this:

BEGIN ATOMIC
DECLARE var1 INTEGER;
DECLARE var2 INTEGER;
SET var1 = (SELECT afield FROM table1);
SET var2 = (SELECT anotherfield FROM table2 WHERE yetanotherfield =
var1);
INSERT INTO table3 VALUES (var2);
END!

It'd be considered a lot more "normal" (at least, under DB2) to write
something like this:

INSERT INTO table3
SELECT anotherfield
FROM table2
WHERE yetanotherfield = (SELECT afield FROM table1);

If you're familiar with functional programming (Lisp, Haskell, ML,
etc.), note the similarities:

* No variable declarations
* Expressions wrapped within each other (SELECT in a SELECT in an
INSERT) instead of separate statements executed in an explicit order
* Execution order determined "naturally" (i.e. evaluation of the
outer
most expression implicitly evaluates inner expressions)

If you want to become comfortable with DB2's implementation of SQL, you
need to start thinking in this "functional" manner. That's not to say
it's all like this; as you've already discovered, there are stored
procedures, triggers and such like which are fairly procedural in their
nature.

You might be able to get away with the BEGIN ATOMIC statement mentioned
above for a lot of things, but I'd encourage you to avoid it wherever
possible. As Knut mentioned in his post the DB2 optimizer will work a
lot better without procedural logic (again, this ties into the
functional programming analogy).

Don't give up on the VALUES expression either. The VALUES expression
allows you to generate a constant set (scalar or vector) within SQL.
For example:

db2 => VALUES 1;

1
-----------
1

1 record(s) selected.

db2 => VALUES 1, 2;

1
-----------
1
2

2 record(s) selected.

db2 => VALUES ('A', 1), ('B', 2), ('C', 3);

1 2
- -----------
A 1
B 2
C 3

3 record(s) selected.

To answer your question about changing the names of the fields
generated by the VALUES expression:

SELECT *
FROM (
VALUES ('A', 1), ('B', 2), ('C', 2)
) AS TEMP(LETTER, NUMBER);

LETTER NUMBER
------ -----------
A 1
B 2
C 2

3 record(s) selected.

VALUES itself has no way of controlling the names of the fields of the
set it creates, but the fields can be aliased by the enclosing
expression (in this case a SELECT expression).

The above example could also be written using "common table
expressions" (something introduced in ANSI SQL-99, and implemented in
DB2 v6 (?) if I recall correctly):

WITH TEMP(LETTER, NUMBER) AS (
VALUES ('A', 1), ('B', 2), ('C', 2)
)
SELECT * FROM TEMP;

LETTER NUMBER
------ -----------
A 1
B 2
C 2

3 record(s) selected.

Common table expressions can make a query involving a lot of
sub-SELECTs a hell of a lot more readable by defining all the
sub-SELECTs before the main body of the query.

Ahh, I've just read that common table expressions have been added to
the latest version of SQL Server (2005?), so maybe you're familiar with
them already?

Incidentally, the VALUES expression as detailed above, and common table
expressions are not available on DB2 for z/OS, just the Linux / Unix /
Windows version. Weird.


Anyway, hopefully the above will be enough to get one or two (perhaps
even three!) lines of SQL working in DB2 :-)

HTH,

Dave.
From: Stefan Momma on
Ian Boyd wrote:

> i'm trying to get a super-primer on DB2-SQL, so i can get something up and
> running.

My favourite reference for DB2 SQL is Graeme Birchall's
DB2 SQL Cookbook, which is available from this website:

http://mysite.verizon.net/Graeme_Birchall/id1.html

hope this helps,

-- stefan
From: Serge Rielau on
OK.. 9 days of labour.. some children appear to cause more trouble than
others ;-)

Procedural statements are not supported as independent statements by DB2.

That is you can do:
CREATE..., DROP.., GRANT, REVOKE, ALTER
DECLARE cursors, FETCH, CLOSE (and implied SELECT, VALUES cursors from CLP)
UPDATE,DELETE, INSERT, MERGE
CALL
BEGIN ATOMIC .. END

That's it!

DECLARE variable, SET statement, etc are not 'real' SQL statement. They
must be NESTED in a procedure, trigger, function or said BEGIN ATOMIC

So if you want to run a script with logic from the client you have to
use BEGIN ATOMIC .. END.

Now talking of semicolons. The DB2 engine knows semicolon only inside of
procedures. However semicolon is often also used by query tools as 'go'.
So what happens is that the query tools is chopping up the procedure (or
trigger ...) and sends pieces of the statement, which of course cause
-104 syntax error (unexpected end of statement)

Now I'm somewhat unclear on what query tool you are using.
E.g. the IBM provided tools such as the JDBC Type 4 driver (AFAIK)
detect the BEGIN ATOMIC, an CREATE PROCEDURE keywords and suppress the
batching.
Could it be you are using some MS driver which is ignorant to DB2?

Cheers
Serge
--
Serge Rielau
DB2 Solutions Development
IBM Toronto Lab
From: Serge Rielau on
Stefan Momma wrote:
> Ian Boyd wrote:
>
>> i'm trying to get a super-primer on DB2-SQL, so i can get something up
>> and running.
>
> My favourite reference for DB2 SQL is Graeme Birchall's
> DB2 SQL Cookbook, which is available from this website:
>
> http://mysite.verizon.net/Graeme_Birchall/id1.html
>
> hope this helps,
>
> -- stefan
BTW, when looking for DB2 looks (or IBM published books in general) this
is the place to go:
http://www.redbooks.ibm.com/
The books are free for download as PDF.

Cheers
Serge
--
Serge Rielau
DB2 Solutions Development
IBM Toronto Lab
First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5 6 7 8 9 10 11 12 13 14
Prev: SQL0901N Error.
Next: Convert DECIMAL to DATE