Using variable in SELECT query inside IN comparison - sql-server

Here is a simple example:
Why does this work:
DECLARE #v as varchar(75)
SET #v = 'xxx-xxxx'
SELECT * FROM tbl_skus WHERE SKU = #v
But this does not work:
DECLARE #v as varchar(75)
SET #v = 'xxx-xxxx,yyy-yyyy'
SELECT * FROM tbl_skus WHERE SKU IN ( #v )
Both SKUs 'xxx-xxxx' and 'yyy-yyyy' are in the table. The first query pulls 1 result, and the second pulls 0 results; no errors.

Because your query is looking for the literal 'xxx-xxxx,yyy-yyyy', it means that it's just one string, with a comma in it, not 2 strings separated by a comma.
Your query translates to:
SELECT * FROM tbl_skus WHERE SKU IN ('xxx-xxxx,yyy-yyyy')
And for it to work as you want, it shoul be:
SELECT * FROM tbl_skus WHERE SKU IN ('xxx-xxxx','yyy-yyyy')

You cannot assign two values to a single variable. You will have to do something like this:
DECLARE #v as varchar(75)
DECLARE #a as varchar(75)
SET #v = 'xxx-xxxx'
SET #a = 'yyy-yyyy'
SELECT * FROM tbl_skus
WHERE SKU IN (#v, #a)

You should use a cursor like this (for example):
DECLARE #MyCursor CURSOR
SET #MyCursor = CURSOR FAST_FORWARD
FOR
SELECT Table_Training_Detalis.DateExpires,Table_Training_Detalis.Worker_ID
FROM Table_Courses
OPEN #MyCursor
FETCH NEXT FROM #MyCursor
INTO #ColExpir,#ColWorkid
WHILE ##FETCH_STATUS = 0
BEGIN
update Table_Workers set WHIMIS= #ColExpir where Worker_ID=#ColWorkid
FETCH NEXT FROM #MyCursor
INTO #ColExpir,#ColWorkid
END
CLOSE #MyCursor
DEALLOCATE #MyCursor

Related

How to use cursor with update statment?

My aim is to update some records with range of numbers (4987-4993) the first record should be with the number 4987 the next 4988..etc' and when the loop condition is #a=4993 it should stop, I tried using SQL cursor but I updated every thing with the same number (4992).... what am I missing?
DECLARE #a AS INT;
DECLARE #b AS INT;
select #a = 4987
declare myCursor cursor for
select modelcode from model
where try_cast(modelcode as int) > 1600 and try_cast(modelcode as int) <1700
open myCursor
fetch next from myCursor into #b
while #a < 4993
begin
update model
set ModelCode = #a
where try_cast(modelcode as int) < 1659
select #a = #a+1
fetch next from myCursor into #b
end;
close myCursor
DEALLOCATE myCursor;
Your update statement is independent from #b. You need to do something like this:
update model
set ModelCode = #a
where modelcode = #b;

Don't know how to use varchar variable in select clause of query

I''m trying to use a varchar variable in my select, but its registering as a string and outputting just the string itself instead of treating it like an actual column.
Not very many solutions online, as it seems like this isn't a problem very many run into.
Declare #counter INT = 0
Declare #totalcol INT
Declare #col VARCHAR(50)
select #totalcol = count(*)
FROM [Loyalty_DW].information_schema.columns
WHERE table_name = 'Transactions'
while (#counter < #totalcol)
begin
select #col = COLUMN_NAME
from [Loyalty_DW].information_schema.columns
where table_name = 'Transactions'
order by (select null)
offset #counter rows
fetch next 1 rows only
select distinct(#col)
from [Loyalty_DW].dbo.Transactions
set #counter += 1
end
The output is just a string with no actual data returned. The same as if I were to say select 'asdf' from tablename where ... it would just output 'asdf'.
You can use CURSOR statement rather than WHILE statement, as Gordon says you need to use dynamic SQL:
DECLARE #columName AS NVARCHAR(50);
DECLARE #sqlText AS NVARCHAR(1000);
DECLARE cursor_name CURSOR FOR
SELECT COLUMN_NAME
FROM [Loyalty_DW].INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Transactions'
ORDER BY(SELECT NULL)
OPEN cursor_name
FETCH NEXT FROM cursor_name INTO #columName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sqlText = N'SELECT DISTINCT ' + #columName + ' FROM [Loyalty_DW].dbo.Transactions'
EXEC (#sqlText)
FETCH NEXT FROM cursor_name INTO #columName
END
CLOSE cursor_name
DEALLOCATE cursor_name

Replacing cursor with set based query

I want to find count of set of tables. The table names are values in another table.
--like
select count(*) from tablename
--tablename is obtained from
select tablename from table1
--table1 has around 171 tablenames
I was using cursor to get each table name and select count for each, but it is taking time. Can you please help how to replace cursor code with set based solution?
Below is my cursor code
SET NOCOUNT ON;
if( OBJECT_ID('tempdb..#temptablenew') IS NOT NULL )
BEGIN
DROP table #temptablenew
END
select * into #temptablenew from table1
declare #srccount int
declare #tablename nvarchar(max);
declare #q2 nvarchar(max);
declare #id int;
declare my_cursor cursor
local static read_only forward_only
for
select id,tablename from #temptablenew
open my_cursor
fetch next from my_cursor
into #id,#tablename
while ##fetch_status = 0
begin
set #q2 =N'select #srccount= count(*) from '+#tablename+' with (nolock)';
execute sp_executesql #q2,#PARAMS = N'#srccount INT OUTPUT',
#srccount = #srccount OUTPUT
select #srccount,#id,#tablename
fetch next from my_cursor
into #id,#tablename
end
close my_cursor;
deallocate my_cursor;
Thanks in advance
Try this,
SET NOCOUNT ON;
declare #q2 nvarchar(max) = '';
SELECT #q2 = #q2 + 'SELECT COUNT(*) AS cnt, ''' + tablename + ''' AS TableName FROM ' + tablename + ' (NOLOCK); '
FROM table1
--Print #q2
execute sp_executesql #q2

Adding Column to stored procedure conditionally

I have the following (simplified) stored procedure:
CREATE FUNCTION [dbo].[UDF_FulfilmentBatch](#FulfilmentID INT) RETURNS
#Result TABLE (
[sequence] INT,
membershipid BIGINT,
membershipNo VARCHAR(255)
)
AS
BEGIN
DECLARE #_sequence INT
DECLARE #_membershipid BIGINT
DECLARE #_membershipNo VARCHAR(255)
SET #_sequence = 1
IF #FulfilmentID = 4
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_HH
END
IF #FulfilmentID = 3
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_ID
END
ELSE IF #FulfilmentID = 2
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_Art
END
ELSE
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_Tha
OPEN FulfilCursor
FETCH NEXT FROM FulfilCursor INTO #_membershipid, #_membershipNo
WHILE ##FETCH_STATUS = 0 BEGIN
INSERT INTO #Result
VALUES (#_sequence, #_membershipid, #_membershipNo)
SET #_sequence = #_sequence + 1
FETCH NEXT FROM FulfilCursor INTO #_membershipid, #_membershipNo
END
CLOSE FulfilCursor
DEALLOCATE FulfilCursor
RETURN
END
GO
My problem is, that when FulfilmentID = 4, I wan to add an extra field - 'Delivery'
If have tried the following:
CREATE FUNCTION [dbo].[UDF_FulfilmentBatch](#FulfilmentID INT) RETURNS
#Result TABLE (
[sequence] INT,
membershipid BIGINT,
membershipNo VARCHAR(255)
IF #FulfilmentID = 4
BEGIN
,Delivery VARCHAR(255)
END
)
AS
BEGIN
DECLARE #_sequence INT
DECLARE #_membershipid BIGINT
DECLARE #_membershipNo VARCHAR(255)
IF #FulfilmentID = 4
BEGIN
DECLARE #_Delivery VARCHAR(255)
END
SET #_sequence = 1
IF #FulfilmentID = 4
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_HH
END
IF #FulfilmentID = 3
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_ID
END
ELSE IF #FulfilmentID = 2
BEGIN
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_Art
END
ELSE
DECLARE FulfilCursor CURSOR FAST_FORWARD FOR
SELECT * from VW_FulfilmentExtract_Tha
OPEN FulfilCursor
FETCH NEXT FROM FulfilCursor INTO #_membershipid, #_membershipNo
WHILE ##FETCH_STATUS = 0 BEGIN
INSERT INTO #Result
VALUES (#_sequence, #_membershipid, #_membershipNo IF #FulfilmentID=4 BEGIN #_Delivery )
SET #_sequence = #_sequence + 1
FETCH NEXT FROM FulfilCursor INTO #_membershipid, #_membershipNo
END
CLOSE FulfilCursor
DEALLOCATE FulfilCursor
RETURN
END
GO
But this did not work (Please excuse any syntax errors, this is a rough typing for SO)
Form searching the web there does not seem to be much on this. Can it be done?
There are lots of issues in your code:
use SELECT *
use Cursor
...
In the end, it is overly complicated and looks at lot like Application code (C#, java, ...)
What you want to do should be done with a single Select (ie. on a set of data). Columns names should also be listed between SELECT and FROM.
One option is:
CREATE FUNCTION [dbo].[UDF_FulfilmentBatch](#FulfilmentID INT) RETURNS TABLE
AS
RETURN (
SELECT sequence = ROW_NUMBER() Over(Order By (Select 1))
, _membershipid, membershipNo, delivery
FROM VW_FulfilmentExtract_HH
WHERE #FulfilmentID = 4
UNION ALL
SELECT sequence = ROW_NUMBER() Over(Order By (Select 1))
, _membershipid, membershipNo, delivery = NULL
FROM VW_FulfilmentExtract_ID
WHERE #FulfilmentID = 3
UNION ALL
SELECT sequence = ROW_NUMBER() Over(Order By (Select 1))
, _membershipid, membershipNo, delivery = NULL
FROM VW_FulfilmentExtract_Art
WHERE #FulfilmentID = 2
UNION ALL
SELECT sequence = ROW_NUMBER() Over(Order By (Select 1))
, _membershipid, membershipNo, delivery = NULL
FROM VW_FulfilmentExtract_Tha
WHERE #FulfilmentID = not in (2, 3, 4)
);
Here I use ROW_NUMBER to generate your sequence number.
I added the Delivery column and set it to NULL when it is not needed.
You must update columns name. I just guess them.
By the way, this is not a Stored Procedure but a Inline User-Defined Functions

Using a Table of Column Definitions to Create an Insert Query

I have a table called raw_data that contains a column with a large string of data fields formatted in fixed length sub-strings. I also have a table table_1 that specifies the column name and the data range in the string for each value. I need to create a SQL INSERT statement to move data from raw_data into a table called table_2 with all the columns. table_1 has about 600 rows, so I am wondering if I can loop through each record to create the SQL statement that inserts the data into table_2.
Table_1
Name Start Length
AAA 1 2
BBB 3 3
CCC 6 1
I haven't learned how to use cursors; the below query could be incorrect. There will be 3 tables involved in this task. table_1 to look up the name, start, length values. table_2 will be the table I need to insert the data into. The third table raw_data has the column with the sub-strings of each needed value.
DECLARE #SQL VARCHAR(200)
DECLARE #NAME VARCHAR(200)
DECLARE #START VARCHAR(200)
DECLARE #LENGTH VARCHAR(200)
SET #NAME = ''
DECLARE Col_Cursor CURSOR FOR
SELECT Name, Start, Length FROM ODS_SIEMENS_LAYOUT WHERE RecordType = '1'
OPEN Col_Cursor
FETCH NEXT FROM Col_Cursor INTO #NAME, #START, #LENGTH
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQL = #NAME + '=' + 'SUBSTRING(RAW_DATA,' + #START + ',' + #LENGTH + ')'
FETCH NEXT FROM Col_Cursor INTO #NAME, #START, #LENGTH
END
CLOSE Col_Cursor
DEALLOCATE Col_Cursor
I need to generate something like the below query:
INSERT INTO TABLE_2
'AAA' = SUBSTRING(RAW_DATA,1,2)
'BBB' = SUBSTRING(RAW_DATA,3,3)
'CCC' = SUBSTRING(RAW_DATA,5,2)
........
Can I loop through each column to form the SQL Statement instead of manually coding 600 columns?
At the risk of sounding like Clippy... it looks like you're trying to import a flat file. Is your RAW_DATA coming from a flat file somewhere? If so you might look into using bulk insert:
Use a Format File to Bulk Import Data
If you are just asking how can you build your sql statement using the data from your column definition table... then the code you have is very close. You want something like this:
DECLARE #COLUMNS varchar(max)
DECLARE #SUBCOLUMNS varchar(max)
DECLARE #NAME VARCHAR(200)
DECLARE #START VARCHAR(200)
DECLARE #LENGTH VARCHAR(200)
SET #NAME = ''
DECLARE Col_Cursor CURSOR FOR
SELECT Name, Start, Length FROM ODS_SIEMENS_LAYOUT WHERE RecordType = '1'
OPEN Col_Cursor
FETCH NEXT FROM Col_Cursor INTO #NAME, #START, #LENGTH
set #SUBCOLUMNS = ''
set #COLUMNS = ''
WHILE ##FETCH_STATUS = 0
BEGIN
SET #COLUMNS = #COLUMNS + #NAME + ','
SET #SUBCOLUMNS = #SUBCOLUMNS + 'SUBSTRING(RAW_DATA,' + #START + ',' + #LENGTH + '),'
FETCH NEXT FROM Col_Cursor INTO #NAME, #START, #LENGTH
END
CLOSE Col_Cursor
DEALLOCATE Col_Cursor
set #COLUMNS = LEFT(#COLUMNS, len(#COLUMNS)-1) --get rid of last comma
set #SUBCOLUMNS = LEFT(#SUBCOLUMNS, len(#SUBCOLUMNS)-1) --get rid of last comma
print 'INSERT INTO TABLE_2 ' + '(' + #COLUMNS + ') SELECT ' + #SUBCOLUMNS + ' FROM RawDataTable'
You can take the text that prints and insert that SQL statement into your procedure that does the actual inserts.
Ahh I think I am beginning to unravel what you are trying to do. There is no need for a cursor or dynamic sql here at all. You just need to use a select statement as the values for your insert. Something like this maybe??
INSERT INTO TABLE_2(AAA, BBB, CCC)
SELECT SUBSTRING(RAW_DATA,1,2)
, SUBSTRING(RAW_DATA,3,3)
, SUBSTRING(RAW_DATA,5,2)
FROM ODS_SIEMENS_LAYOUT
WHERE RecordType = '1'

Resources