SQL session/connection variables - sql

I'm trying to find some equivalent to session variables in SQL. I want to be able to store and retrieve just a number but each connection to the database has a different number. It needs to persist from one batch to the next on the same connection.
I did have a solution that used a global cursor like this.
IF (SELECT CURSOR_STATUS('global','ChangeSet')) >= 0
BEGIN --Close and deallocate the cursor
Close ChangeSet
DEALLOCATE ChangeSet
END
--Create a new cursor
DECLARE ChangeSet CURSOR GLOBAL STATIC FOR
SELECT ChangeSet = #ChangeSet
--Open the cursor
OPEN ChangeSet
Each connection would have a different cursor so it worked, but this is not usable inside of a view. I guess if somebody can show me how to read this in a view that would be cool too.
I'm using MS SQL Server btw.

The CONTEXT_INFO property may be what you're looking for - it enables you to set and read a connection-specific binary value.
You could encode your numeric value to binary and store it in this property.

Starting from SQL 2016
EXEC sys.sp_set_session_context #key = N'language', #value = 'English';
SELECT SESSION_CONTEXT(N'language');

A temporary table survives a batch (including go). It's still connection specific:
create table #temp (val float)
insert #temp values (3.14)
go
select * from #temp

Related

DB2 Select Statement error after for loop in stored procedure

I've written a stored procedure which uses a for loop to execute a query for a list of views. It generates a dynamic sql statement for each view inside the for loop and then executes it, which inserts output into a declared temporary table.
The for loop works perfectly and it runs without errors, however if I add a select statement after the END FOR; to get the final output from the temporary table I get the error below. Does anyone have any ideas please?
Error 16/07/2018 10:43:41 0:00:00.007 DB2 Database Error: ERROR [42601] [IBM][DB2/AIX64] SQL0104N An unexpected token "select *" was found following "1; END FOR; ". Expected tokens may include: "<call>". LINE NUMBER=31. SQLSTATE=42601
SQL Code:
BEGIN
DECLARE SQLTEXT varchar(500);
DECLARE GLOBAL TEMPORARY TABLE SESSION.AS_USAGE_RESULTS(
temp table columns
);
FOR v as cur1 cursor for
select distinct viewname,viewschema
from syscat.VIEWS
DO
SET SQLTEXT = 'Dynamic Insert into temp table here'
PREPARE s1 FROM SQLTEXT;
EXECUTE s1;
END FOR;
select *
from SESSION.AS_USAGE_RESULTS;
DROP TABLE SESSION.AS_USAGE_RESULTS;
END
Your mistake is that if you wish to return a result-set from session.as_usage_results, then you must declare a cursor for its select, and open that cursor then end the sproc. This is a FAQ. There are examples in the IBM Db2 Server SAMPLES directory and in the Db2 Knowledge Center.
Inside the sproc, you can either use SELECT ... INTO, or use a select within a cursor, or use a SELECT as part of a SET statement.
You should not drop the session table in the procedure in case the result-set won't be consumed before the table gets dropped. Either drop the session table elsewhere or use an alternative design.
In your example you don't need cursor cur1, so below I show a stilted artificial example of what your might mean. It is artificial because you can see that the session table is also redundant for this example, but it shows the use of the cursor for the result-set.
--#SET TERMINATOR #
create or replace procedure dynproc1
language sql
specific dynproc1
dynamic result sets 1
BEGIN
DECLARE v_sqltext varchar(2000);
DECLARE c1 cursor with return to client for s1;
DECLARE GLOBAL TEMPORARY TABLE SESSION.AS_USAGE_RESULTS ( viewname varchar(128), viewschema varchar(128) );
insert into session.as_usage_results(viewname, viewschema) select viewname, viewschema from syscat.views;
set v_sqltext = 'select * from session.as_usage_results';
prepare s1 from v_sqltext;
open c1;
END
#

Access data within a SQL Server cursor

Is it possible to access the temp data created within a SQL Server cursor? I would like to set some conditions within the cursor but those depends on the data that the cursor has example:
Cursor declaration.....
if (#Column = (SELECT MAX(ID) from cursor_name/table where Rid = #Rid))
begin
....
I'm actually doing this using a table variable that is being read by the cursor but I wonder if there's a better way to achieve this, any suggestions?
Thanks

sp_executesql with user defined table type not working with two databases [duplicate]

I'm using SQL Server 2008.
How can I pass Table Valued parameter to a Stored procedure across different Databases, but same server?
Should I create the same table type in both databases?
Please, give an example or a link according to the problem.
Thanks for any kind of help.
In response to this comment (if I'm correct and that using TVPs between databases isn't possible):
What choice do I have in this situation? Using XML type?
The purist approach would be to say that if both databases are working with the same data, they ought to be merged into a single database. The pragmatist realizes that this isn't always possible - but since you can obviously change both the caller and callee, maybe just use a temp table that both stored procs know about.
I don't believe it's possible - you can't reference a table type from another database, and even with identical type definitions in both DBs, a value of one type isn't assignable to the other.
You don't pass the temp table between databases. A temp table is always stored in tempdb, and is accessible to your connection, so long as the connection is open and the temp table isn't dropped.
So, you create the temp table in the caller:
CREATE TABLE #Values (ID int not null,ColA varchar(10) not null)
INSERT INTO #Values (ID,ColA)
/* Whatever you do to populate the table */
EXEC OtherDB..OtherProc
And then in the callee:
CREATE PROCEDURE OtherProc
/* No parameter passed */
AS
SELECT * from #Values
Table UDTs are only valid for stored procs within the same database.
So yes you would have to create the type on each server and reference it in the stored procs - e.g. just run the first part of this example in both DBs http://msdn.microsoft.com/en-us/library/bb510489.aspx.
If you don't need the efficency you can always use other methods - i.e. pass an xml document parameter or have the s.p. expect a temp table with the input data.
Edit: added example
create database Test1
create database Test2
go
use Test1
create type PersonalMessage as TABLE
(Message varchar(50))
go
create proc InsertPersonalMessage #Message PersonalMessage READONLY AS
select * from #Message
go
use Test2
create type PersonalMessage as TABLE
(Message varchar(50))
go
create proc InsertPersonalMessage #Message PersonalMessage READONLY AS
select * from #Message
go
use Test1
declare #mymsg PersonalMessage
insert #mymsg select 'oh noes'
exec InsertPersonalMessage #mymsg
go
use Test2
declare #mymsg2 PersonalMessage
insert #mymsg2 select 'oh noes'
exec InsertPersonalMessage #mymsg2
Disadvantage is that there are two copies of the data.
But you would be able to run the batch against each database simultaneously.
Whether this is any better than using a table table is really down to what processing/data sizes you have - btw to use a temp table from an s.p. you just access it from the s.p. code (and it fails if it doesn't exist).
Another way to solve this (though not necessarily the correct way) is to only utilize the UDT as a part of a dynamic SQL call.
USE [db1]
CREATE PROCEDURE [dbo].[sp_Db2Data_Sync]
AS
BEGIN
/*
*
* Presumably, you have some other logic here that requires this sproc to live in db1.
* Maybe it's how you get your identifier?
*
*/
DECLARE #SQL VARCHAR(MAX) = '
USE [db2]
DECLARE #db2tvp tableType
INSERT INTO #db2tvp
SELECT dataColumn1
FROM db2.dbo.tblData td
WHERE td.Id = ' + CAST(#YourIdentifierHere AS VARCHAR) '
EXEC db2.dbo.sp_BulkData_Sync #db2tvp
'
EXEC(#SQL)
END
It's definitely not a purist approach, and it doesn't work for every use case, but it is technically an option.

solution for generating a running sequence number by using stored procedure in sql server 2008

how to generate a running sequence number from 0001 to 9999 by through using a function in sql server, if u call that function in sql server, it should to be provide a running sequence number when ever if it reach 9999 again it should to be reset 0001
can any help on this please to perform this above task
There are plenty of good articles about that. Try Google.
For instance see here and there
A function can't update, insert or delete, so you can't store the variable and check it's value next time you call the function. So there is no way of doing this using a function.
You can simply get the sequence number using following procedure:
CREATE PROCEDURE proc_GetSeqNumber
AS
BEGIN
DECLARE #idt INT
SET #idt = 0
WHILE (#idt < 9999)
BEGIN
SELECT #idt = #idt + 1
PRINT #idt
END
END
The only way a database can remember a value is if it is stored in a table (in Oracle, you could use a sequence, but SQL Server doesn't use those.) So I would create a single table with a single value and the function would read the value, increment it, and if need be reset it.
if #ItemsCount=0
begin
set #generatedSeNumber=1
end
else
begin
SET #sql= 'insert into Senumber values(('+#SeNumber+'))'
Exec (#sql)

How to remove a record from a table valued parameter?

I would like to know how to remove a value from a Table Valued Parameter in SQL?
Is this even possible? If not, what would be the workaround?
Please see my code below and note the comments. The comments portion is where I would like to insert a line that would allow me to remove a record from the TVP #Record_NumList
Once that record is removed, I then proceed to insert a new one (basically, I don't want to execute the stored procedure on an existing record).
DECLARE #RecordID int
DECLARE #RecordID_NumList as Le_NumberList
DECLARE cur_DelRec CURSOR
FOR
SELECT DBRecordID from <<table_name>>
OPEN cur_DelRec
FETCH NEXT from cur_DelRec into #RecordID
INSERT into #RecordID_NumList(#RecordID)
WHILE ##FETCH_STATUS = 0
BEGIN
exec <<stored_procedure>> #RecordID_NumList
/* I'm stuck here: */
/* Need to remove from the existing record
from #RecordID_NumList */
FETCH NEXT FROM cur_DelRec into #RecordID
INSERT into #RecordID_NumList(#RecordID)
END
CLOSE cur_DelRec
DEALLOCATE cur_DelRec
On a more general level, is a TVP a collection? Let's say I chose not to delete it from #Record_NumList. What would happen in that case?
I apologize, but I'm still learning SQL and any help would be greatly appreciated!
Ray
Table valued parameters works just like a regular table. You should be able to just do something like this:
delete from #Record_numList where [field] = [value]