views:

3231

answers:

1

Disclaimer: This is an "asked-and-answered question" posted in accordance with the FAQ statement that it's "perfectly fine to ask and answer your own programming question". Its purpose is to encourage members of the SQL Anywhere programming community to use StackOverflow by seeding the "sqlanywhere" tag with some real-world content. Edits are welcome, as are other answers, and it has been marked "community wiki" to facilitate that, as well as to avoid claims of gaming the reputation system.

I'm writing a stored procedure for SQL Anywhere 9.0.2, here's some code:

...
declare
@v_d datetime, @v_d1 datetime, @v_d2 datetime
....
select @v_d1 = @v_d, @v_d2 = dateadd(dd, 1, @v_d1)
...

it turns out that @v_d2 will not be set as expected. if I modify it to:

...
declare
@v_d datetime, @v_d1 datetime, @v_d2 datetime
....
select @v_d1 = @v_d
select @v_d2 = dateadd(dd, 1, @v_d1)
...

nothing happens, all the same. finally, I changed it to :

...
declare
@v_d datetime, @v_d1 datetime, @v_d2 datetime
....
begin
   select @v_d1 = @v_d
end
begin
   select @v_d2 = dateadd(dd, 1, @v_d1)
end
...

now it works fine, looks kind of stupid though. my question is: is it a known issue? or maybe I could do it more neatly? any comments will be appreciated. thanks!

+3  A: 

You are looking for spreadsheet-style automatic recalculation for host variable assignments in a Transact-SQL SELECT list. I am curious about whether Microsoft SQL Server or Sybase ASE do it, but this is SQL Anywhere...

From the behavior of your original code, it looks like references to host variables (the reference to @v_d1 in the call to dateadd) always refer to the values that existed when the statement started (null), not the recalculated value (the value from @v_d):

CREATE PROCEDURE p AS
declare
@v_d datetime, @v_d1 datetime, @v_d2 datetime
SELECT @v_d = CURRENT TIMESTAMP
select @v_d1 = @v_d, @v_d2 = dateadd(day, 1, @v_d1)
SELECT @v_d, @v_d1, @v_d2
GO

SELECT * FROM p();

@v_d,@v_d1,@v_d2
'2009-05-08 15:13:43.964','2009-05-08 15:13:43.964',(NULL)

You report that your second version (separate SELECT statements) does not work, but the following works for me:

DROP PROCEDURE p;

CREATE PROCEDURE p AS
declare
@v_d datetime, @v_d1 datetime, @v_d2 datetime
SELECT @v_d = CURRENT TIMESTAMP
select @v_d1 = @v_d
select @v_d2 = dateadd(dd, 1, @v_d1)
SELECT @v_d, @v_d1, @v_d2
GO

SELECT * FROM p();

@v_d,@v_d1,@v_d2
'2009-05-08 15:12:54.339','2009-05-08 15:12:54.339','2009-05-09 15:12:54.339'

The spreadsheet-style recalculation you are looking for DOES apply to select list items coded "expression AS identifier" (but that's not exactly what you want)...

DROP PROCEDURE p;

CREATE PROCEDURE p AS
declare @v_d datetime
SELECT CURRENT TIMESTAMP INTO @v_d
select @v_d AS v_d, dateadd(day, 1, v_d) AS v_d1, dateadd(day, 1, v_d1) AS v_d2
GO

SELECT * FROM p();

v_d,v_d1,v_d2
'2009-05-08 15:14:27.292','2009-05-09 15:14:27.292','2009-05-10 15:14:27.292'

If you want to spreadsheet-style recalculation AND you want host variable assignments, I suggest you switch to the Watcom-SQL dialect so you can use the INTO list:

DROP PROCEDURE p;

CREATE PROCEDURE p() BEGIN
   DECLARE @v_d  datetime;
   DECLARE @v_d1 datetime;
   DECLARE @v_d2 datetime;
SET @v_d = CURRENT TIMESTAMP;
SELECT @v_d AS v_d, 
       dateadd(day, 1, v_d) AS v_d1, 
       dateadd(day, 1, v_d1) AS v_d2
  INTO @v_d,
       @v_d1,
       @v_d2;
SELECT @v_d,
       @v_d1,
       @v_d2;
END;

SELECT * FROM p();

@v_d,@v_d1,@v_d2
'2009-05-08 15:27:09.808','2009-05-09 15:27:09.808','2009-05-10 15:27:09.808'

The behavior is the same in SQL Anywhere versions 9.0.2 and 11.0.1.

Breck

Breck Carter
WTF? You asked the question and then immediately posted the answer? Try to be a little less transparent in your attempt at gaming the system for badges.
Pesto
What are you doing if not reputation whoring? If you want to have a general SQL Anywhere question, it should be community wiki and not full of very specific code samples. If you want an answer, why post one immediately after asking? It seems like you already have an answer to your question and are posting it to gain some reputation.
Welbog
This practice is not only allowed, @welblog and @Pesto, but it's encouraged.
George Stocker
@Gortok: When the question, answer and samples are general enough to apply to nearly any situation, sure. I agree completely. This specific situation is far from the encouraged practice. Even if it were CW it still seems iffy to me.
Welbog
Page one of the FAQ says "It's also perfectly fine to ask and answer your own programming question"In the Google Techtalk at http://www.youtube.com/watch?v=NWHfY_lvKIQ Joel Spolsky says the primary purpose of StackOverflow is to be a repository for canonical questions and answers about programming.The main reason I'm doing this is to encourage other SQL Anywhere users to come over to StackOverflow with their questions, by increasing the count for the "sqlanywhere" tag. Badges don't matter. Reputation points are a means to an end (ability to post comments, etc).
Breck Carter
Perhaps in the future I will wait for a while before posting an answer to my own question. Or mark it as Community Wiki. Or both. It's not about the competition, it's about getting real-world answers to real-world questions out on the web. This one, for example, is a copy from an recent question on an NNTP support forum.
Breck Carter
Breck Carter
As they say in the financial world, "I've locked in my (rep) losses"... by marking it CW... shoulda done that up front, my profound apologies to all who were offended! (but I am going to keep posting asked-and-answered questions, no apologies there)
Breck Carter
I don't even understand the question ;)
Ryan Emerle