T-SQL: Add 1 second to subsequent fields in SQL Server 2005 - tsql

I want to add 1 second to a column on every row so that each row have a unique time value.
My code works fine in SQL Server 2012, but the client has SQL Server 2005 and it fails there.
What workarounds are there?
Error on line as indicated is:
Must declare the scalar variable "#MyVar"
Code:
CREATE TABLE #Temp_Times(MyTime datetime)
INSERT INTO #Temp_Times
SELECT GETDATE()
FROM Tasks
DECLARE #MyVar datetime = GETDATE();
--Add 1 second to every value
UPDATE #LinkFaultAuditTrace_Temp
SET #MyVar = MyTime = DATEADD(s, 1, #MyVar); --Here is the problem

have you tried:
DECLARE #MyVar datetime;
Set #Myvar = GETDATE();

Related

In DB2, how can I declare a variable to use in multiple declared global temporary tables within the function..?

In DB2 for i v7r3m0, how can I declare a variable to use in multiple declared global temporary tables which follow within the same function..?
Below is a sample of my code. The full version has multiple DGTTs which do complex calculations and are then joined at the end. I would like to define the variable FIRSTDAY as shown, but this causes the following error:
SQL Error [42618]: [SQL0312] Variable FIRSTDAY not defined or not usable.
This seems like a context issue; the variable can't be seen in the context of the DGTT definition. If this were an independent SQL script, I could use DECLARE VARIABLE and it would work. Also, I could certainly duplicate the equation for FIRSTDAY multiple times, but I'd rather not do that.
CREATE OR REPLACE FUNCTION F_CERTOB.CertoNewPackageSheetsF1 ()
RETURNS TABLE( DAACCT CHAR(5),
DAIDAT NUMERIC(8),
DAINV NUMERIC(15),
QTY NUMERIC(5)
)
LANGUAGE SQL
MODIFIES SQL DATA
NOT DETERMINISTIC
NO EXTERNAL ACTION
BEGIN
DECLARE FIRSTDAY NUMERIC(8) DEFAULT 0 ;
SET FIRSTDAY = (YEAR(CURDATE() - 4 MONTHS) * 10000) + (MONTH(CURDATE() - 4 MONTHS) * 100) ;
DECLARE GLOBAL TEMPORARY TABLE SESSION.NPS_DATA0 -- CREATE INITIAL MAIN DATA SET
AS ( SELECT DAACCT AS DAACCT,
DAIDAT AS DAIDAT,
DAINV# AS DAINV,
DAQTY AS QTY
FROM F_CERTOB.DAILYT
WHERE DAIDAT = FIRSTDAY
-- WHERE DAIDAT = 20190501 -- THIS WORKS
) WITH DATA WITH REPLACE ;
-- DGTT 2 also uses FIRSTDAY
-- DGTT 3 also uses FIRSTDAY
RETURN SELECT * FROM SESSION.NPS_DATA0 ;
END #
SELECT * FROM TABLE(F_CERTOB.CertoNewPackageSheetsF1()) #
DROP FUNCTION F_CERTOB.CertoNewPackageSheetsF1() #
DROP TABLE SESSION.NPS_DATA0 #
Seems, that it's not allowed to use variables in DDL statements.
Try to split the table declaration and data insertion steps like below:
DECLARE GLOBAL TEMPORARY TABLE SESSION.NPS_DATA0 -- CREATE INITIAL MAIN DATA SET
AS ( SELECT DAACCT AS DAACCT,
DAIDAT AS DAIDAT,
DAINV# AS DAINV,
DAQTY AS QTY
FROM F_CERTOB.DAILYT
-- WHERE DAIDAT = FIRSTDAY
WHERE DAIDAT = 20190501 -- THIS WORKS
) WITH NO DATA WITH REPLACE ;
INSERT INTO SESSION.NPS_DATA0
SELECT DAACCT AS DAACCT,
DAIDAT AS DAIDAT,
DAINV# AS DAINV,
DAQTY AS QTY
FROM F_CERTOB.DAILYT
WHERE DAIDAT = FIRSTDAY;

MSTSQL: Can a SP return both an out param and a result set

I wish to know whether it's feasible to have a TSQL stored procedure return both a result set and the output parameter like so.
create procedure uspReadMyXmlInformation(#myXmlDoc xml, #myProductNum varchar(18) output) as
begin
set nocount on;
declare #myXmlContent table(MyOrderId varchar(12) not null
,CreatedAt datetime not null)
insert into #myXmlContent
select x.c.value('MyOrderID[1]', 'varchar(12)')
x.c.value('CreatedAt[1]', 'datetime')
from #myXmlDoc.nodes('MyRootNodeName/MyChildNodeName') x(c)
set #myProductNum='MyProductNum'
select *
from #myXmlContent
return;
end
So, what happens here is that I can either obtain the result set, when I remove the output parameter, or I obtain the output parameter and the result set is always empty (0=count(*)).
Is there anyway I can obtain both with the same stored procedure or I'd better split them?
I think it's doable from this post in Oracle. I'd like to achieve the same in SQL Server, although constrained to the 2008 version.
Oracle stored procedure: return both result set and out parameters
What I like from doing it using the same SP is that both the result set and the output parameter represent information I read from the XML document. So, the name of the SP says it all, somehow.
EDIT
As some think it might be a duplicate of:
Possible to return an out parameter with a DataReader
I don't think it is as answers there are related as to how the DataReader behaves more than how it could be achieved with TSQL.
The fact is that I get the the value from the output parameter, but I don't get it from the result set at all, it's always returning null.
So, I'm on a SQL Server only project and I'd need that. Otherwise, I'll split it in two, if I can't achieve it in a timely fashion.
Here's how it's used:
declare #xmlInformationData table(MyOrderId varchar(12) not null
,CreatedAt datetime not null)
insert into #xmlInformationData
execute uspReadMyXmlInformation #myXmlDoc, #myProductNum output
while 0<(select count(*) from #xmlInformationData)
begin
-- This will never be executed because I have no rows in #xmlInformationData
-- And yet, before the loop, I have my out param value!
end
The following is a trivial demonstration of using both an output parameter and result set. Try running it a few times and the results should vary.
create procedure Arthur( #TheAnswer as Int Output ) as
begin
-- Set the value of the output parameter.
set #TheAnswer = 42;
-- Generate a single row most of the time.
select GetDate() as NextVogonPoetryReading
where DatePart( millisecond, GetDate() ) < 750;
end;
go 1
-- Declare the variables for the test.
declare #HHGTTU as Table ( HHGTTUId Int Identity, NextVogonPoetryReading DateTime );
declare #SixTimesNine as Int;
-- Execute the SP once so that the while loop might.
insert into #HHGTTU ( NextVogonPoetryReading )
execute Arthur #TheAnswer = #SixTimesNine Output;
-- See what happens.
while exists ( select Pi() from #HHGTTU )
begin
-- See where we are at.
select #SixTimesNine as SixTimesNine, Max( HHGTTUId ) as MaxHHGTTUId, Max( NextVogonPoetryReading ) as MaxNextVogonPoetryReading
from #HHGTTU;
-- Reset.
delete from #HHGTTU;
set #SixTimesNine = 54;
select #SixTimesNine as SixTimesNineAfterReset;
waitfor delay '00:00:00.100';
-- Execute the SP again.
insert into #HHGTTU ( NextVogonPoetryReading )
execute Arthur #TheAnswer = #SixTimesNine Output;
end;
Aside: My apologies for the trauma introduced into your life by my mention of a DataReader. I was merely attempting to pass on my experience in a C# application without getting into the weeds of exactly what sort of connection to the database you are using, which driver(s) might be involved, ... .

User Defined Function Returns Different Result When Called from Inside Stored Procedure

I'm working in a client's SQL Server 2005 database and I'm seeing some odd behavior. I have a little experience with 2008, but this is my first battle with 2005, so I'm hoping this turns out to be something simple related to my inexperience.
What am I trying to do? I am developing a sales dashboard in SSRS 2005. One of the report parameters is a multi-value parameter which I need to pass to a stored procedure. I found a work around in some blogs, as well as here on SO, and implemented a function which splits a comma delimited varchar, and returns a table. I need this function to return the correct values from within the procedure, since I am calling stored procedures for the SSRS datasets.
My Problem: When I execute the function directly from within SSMS for a given value, I receive a table with 7 rows (as expected). When I execute a procedure that calls that function, with the same values passed, it only returns 1 row in the table. The user executing the function and the procedure is also the owner of both objects.
I've done a lot of homework to get to this point prior to posting the question, so I hope I've done my due diligence here. The client hasn't given me privileges to work with SQL Profiler, so I haven't been able to dig in that direction.
I thought perhaps this could be a permissions issue, but the fact that the function is still executed and does return 1 row instead of 7 confused me. It appears to only return the first number from the comma dilimitted string.
My Question: What the heck is causing the behavior outlined below? Please let me know if I should provide any additional information.
Executed from SSMS:
declare
#SiteID varchar(max);
set #SiteID = '1,2,3,4,5,6,7';
BEGIN
exec usp_function_test #SiteID;
select * from udf_rpt_multivalueparamtotable(#SiteID,',',1)
END
Output from Procedure:
Val
---
1
Output from select statement:
Val
---
1
2
3
4
5
6
7
Function Code:
CREATE FUNCTION [dbo].[udf_RPT_MultiValueParamToTAble](
#String VARCHAR(max), /* input string */
#Delimeter char(1), /* delimiter */
#TrimSpace bit ) /* kill whitespace? */
RETURNS #Table TABLE ( [Val] VARCHAR(4000) )
AS
BEGIN
DECLARE #Val VARCHAR(4000)
WHILE LEN(#String) > 0
BEGIN
SET #Val = LEFT(#String,
ISNULL(NULLIF(CHARINDEX(#Delimeter, #String) - 1, -1),
LEN(#String)))
SET #String = SUBSTRING(#String,
ISNULL(NULLIF(CHARINDEX(#Delimeter, #String), 0),
LEN(#String)) + 1, LEN(#String))
IF #TrimSpace = 1 Set #Val = LTRIM(RTRIM(#Val))
INSERT INTO #Table ( [Val] )
VALUES ( #Val )
END
RETURN
END
Test Procedure Code:
CREATE PROCEDURE usp_function_test (#SiteID varchar)
AS
SET NOCOUNT ON
BEGIN
select * from udf_rpt_multivalueparamtotable(#SiteID,',',1)
END
Try defining a scale for the SP parameter -
CREATE PROCEDURE usp_function_test (#SiteID varchar(max))
When you declare a varchar parameter without a scale, it defaults to a scale of 1 - your input value was being silently truncated.
Reference here - http://msdn.microsoft.com/en-us/library/ms176089.aspx

Getting value from stored procedure in another stored procedure

Sorry, lots of code coming up..
I saw another question like this that used output parameters. I'm using the RETURN statement to return the value I want to use.
I have one stored procedure InsertMessage that looks like this:
ALTER PROCEDURE dbo.InsertNewMessage
(
#messageText text,
#dateTime DATETIME,
#byEmail bit,
#bySMS bit
)
AS
DECLARE #NewId int
BEGIN
BEGIN TRANSACTION
INSERT INTO MessageSet VALUES (#byEmail, #bySMS, #dateTime, #messageText)
SET #NewId = SCOPE_IDENTITY()
COMMIT
END
RETURN #NewId
which another stored procedure uses:
ALTER PROCEDURE dbo.InsertMessageFromUserToGroup
(
#userEmail nvarchar(256),
#groupId int,
#messageText text,
#bySMS bit,
#byEmail bit
)
AS
--Inserts a new message to a group
DECLARE #messageId int
DECLARE #dateTime DATETIME = GETDATE()
--First check if user is a part of the group
IF NOT EXISTS (SELECT userEmail FROM UserToGroupSet WHERE userEmail = #userEmail AND groupId = #groupId)
RETURN 'User not part of group'
ELSE --User is a part of the group, add message
BEGIN
BEGIN TRANSACTION
SET #messageId = [dbo].[InsertNewMessage](#messageText, #dateTime, #bySMS, #byEmail)
INSERT INTO MessageToUser VALUES(#userEmail, #messageId)
INSERT INTO MessageToGroup VALUES(#messageId, #groupId)
COMMIT
END
The row that causes the trouble and of which I'm unsure how to handle is this one:
SET #messageId = [dbo].[InsertNewMessage](#messageText, #dateTime, #bySMS, #byEmail)
The syntax seems ok because I can save it. When I run it I get the error message:
Running [dbo].[InsertMessageFromUserToGroup] ( #userEmail = test#test.com, #groupId = 5, #messageText = sdfsdf, #bySMS = false, #byEmail = true ).
Cannot find either column "dbo" or the user-defined function or aggregate "dbo.InsertNewMessage", or the name is ambiguous.
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 0, current count = 1.
No rows affected.
(0 row(s) returned)
#RETURN_VALUE =
Finished running [dbo].[InsertMessageFromUserToGroup].
It seems as if the other stored procedure can't be found. I've tried different ways of calling the procedure but everything else fails as well. Any suggestions?
Try changing
SET #messageId = [dbo].[InsertNewMessage](#messageText, #dateTime, #bySMS,
#byEmail)
to
EXEC #messageId = [dbo].[InsertNewMessage] #messageText, #dateTime, #bySMS,
#byEmail
Notice that SET has been changed to EXEC, and the parentheses have been removed from the parameters.
See the example in the MSDN documenation at the end of the article for more information.

Array-like access to variables in T-SQL

In my stored procedure I have multiple similar variables #V1, #V2 ... #V20 (let's say 20 of them) FETCHED from a record. How would I use dynamic SQL to make 20 calls to another stored procedure using those variables as parameters?
Of course #V[i] syntax is incorrect, but it expresses the intent
fetch next from maincursor into #status, #V1, #V2, ...
while #i<21
begin
-- ??? execute sp_executesql 'SecondSP', '#myParam int', #myParam=#V[i]
-- or
-- ??? execute SecondSP #V[i]
set #i = #i+1
end
As others have said, set up a temporary table, insert the values that you need into it. Then "iterate" through it executing the necessary SQL from those values. This will allow you to have 0 to MANY values to be executed, so you don't have to set up a variable for each.
The following is a complete sample of how you may go about doing that without cursors.
SET NOCOUNT ON
DECLARE #dict TABLE (
id INT IDENTITY(1,1), -- a unique identity column for reference later
value VARCHAR(50), -- your parameter value to be passed into the procedure
executed BIT -- BIT to mark a record as being executed later
)
-- INSERT YOUR VALUES INTO #dict HERE
-- Set executed to 0 (so that the execution process will pick it up later)
-- This may be a SELECT statement into another table in your database to load the values into #dict
INSERT #dict
SELECT 'V1Value', 0 UNION ALL
SELECT 'V2Value', 0
DECLARE #currentid INT
DECLARE #currentvalue VARCHAR(50)
WHILE EXISTS(SELECT * FROM #dict WHERE executed = 0)
BEGIN
-- Get the next record to execute
SELECT
TOP 1 #currentid = id
FROM #dict
WHERE executed = 0
-- Get the parameter value
SELECT #currentvalue = value
FROM #dict
WHERE id = #currentid
-- EXECUTE THE SQL HERE
--sp_executesql 'SecondSP', '#myParam int', #myParam =
PRINT 'SecondSP ' + '#myParam int ' + '#myParam = ' + #currentvalue
-- Mark record as having been executed
UPDATE d
SET executed = 1
FROM #dict d
WHERE id = #currentid
END
Use a #TempTable
if you are at SQL Server 2005 you can create a #TempTable in the parent stored procedure, and it is available in the child stored procedure that it calls.
CREATE TABLE #TempTable
(col1 datatype
,col2 datatype
,col3 datatype
)
INSERT INTO #TempTable
(col1, col2, col3)
SELECT
col1, col2, col3
FROM ...
EXEC #ReturnCode=YourOtherProcedure
within the other procedure, you have access to #TempTable to select, delete, etc...
make that child procedure work on a set of data not on one element at a time
remember, in SQL, loops suck performance away!
Why not just use the table variable instead, and then just loop through the table getting each value.
Basically treat each row in a table as your array cell, with a table that has one column.
Just a thought. :)
This seems like an odd request - will you always have a fixed set of variables? What if the number changes from 20 to 21, and so on, are you constantly going to have to be declaring new variables?
Is it possible, instead of retrieving the values into separate variables, to return them each as individual rows and just loop through them in a cursor?
If not, and you have to use the individual variables as explained, here's one solution:
declare #V1 nvarchar(100)
set #V1 = 'hi'
declare #V2 nvarchar(100)
set #V2 = 'bye'
declare #V3 nvarchar(100)
set #V3 = 'test3'
declare #V4 nvarchar(100)
set #V4 = 'test4'
declare #V5 nvarchar(100)
set #V5 = 'end'
declare aCursor cursor for
select #V1
union select #V2 union select #V3
union select #V4 union select #V5
open aCursor
declare #V nvarchar(100)
fetch next from aCursor into #V
while ##FETCH_STATUS = 0
begin
exec TestParam #V
fetch next from aCursor into #V
end
close aCursor
deallocate aCursor
I don't really like this solution, it seems messy and unscalable. Also, as a side note - the way you phrased your question seems to be asking if there are arrays in T-SQL. By default there aren't, although a quick search on google can point you in the direction of workarounds for this if you absolutely need them.