loop to add value in dynamic OR statement - sql-server

I broke this query down to the most basic. I need to add an OR statement dynamically, which includes a variable. I need to get any id and its corresponding id with an underscore. So, my resulting #SQL to execute would be:
create table #Test (OrganizationId varchar(100), OrigID varchar(50))
insert into #Test(OrganizationId,OrigID)
Values ('5','31'),
('5','31_00000'),
('5','33'),
('5','33_00000'),
('5','25'),
('5','25_00000'),
('5','HD_00000'),
('5','HD')
--
DECLARE
#OrganizationId int = 5,
#OriginId nvarchar(256) = N'31,25,33'
create table #inVars(id int NOT NULL IDENTITY PRIMARY KEY, origins varchar(256))
insert into #inVars(origins)
Values ('31'),
('33'),
('25')
DECLARE #SQL NVARCHAR(MAX),
#ParamDefinition NVARCHAR(MAX)
SET #ParamDefinition = N'#OrganizationId int,
#OriginId nvarchar(256)'
SET #SQL= 'SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId'
IF ISNULL(#OriginId,'') <> ''
SET #SQL = #SQL + ' AND OrigID in (''' + #OriginId + ''') '
DECLARE #counter INT = 1, #max INT = 0, #Origin nvarchar(50), #SQL_2 nvarchar(max)
SELECT #max = COUNT(id) FROM #inVars
WHILE #counter <= #max
BEGIN
SET #Origin = '_%'
SET #Origin = (select origins from #invars where id = CAST(#counter as varchar(10))) + #Origin
SET #SQL_2 = N' OR OrigID LIKE ''' + #Origin + ''' '
SET #SQL_2 = #SQL + #SQL_2
print(#SQL_2)
SET #counter = #counter + 1
END
EXEC sp_executesql #SQL_2,#ParamDefinition,#OrganizationId,#OriginId
drop table #inVars
drop table #Test
Here is how my query is executing now:
SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId AND OrigID in ('31,25,33') OR OrigID LIKE '31_%'
SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId AND OrigID in ('31,25,33') OR OrigID LIKE '33_%'
SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId AND OrigID in ('31,25,33') OR OrigID LIKE '25_%'
This is my desired result:
SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId AND OrigID in ('31,25,33') OR OrigID LIKE '31_%'
OR OrigID LIKE '33_%'
OR OrigID LIKE '25_%'

A few problems: You can't concatenate a NULL with a string EVER; the result is always NULL (please look at the IF #Origin IS NOT NULL line). In your loop, you should be updating #SQL, not #SQL_2. Lastly, you should wrap ORs in parens so the logic is always explicit.
SET NOCOUNT ON
create table #Test (OrganizationId varchar(100), OrigID varchar(50))
insert into #Test(OrganizationId,OrigID)
Values ('5','31'),
('5','31_00000'),
('5','33'),
('5','33_00000'),
('5','25'),
('5','25_00000'),
('5','HD_00000'),
('5','HD')
DECLARE
#OrganizationId int = 5,
#OriginId nvarchar(256) = N'31,25,33'
create table #inVars(id int NOT NULL IDENTITY PRIMARY KEY, origins varchar(256))
insert into #inVars(origins)
Values ('31'),
('33'),
('25')
DECLARE #SQL NVARCHAR(MAX),
#ParamDefinition NVARCHAR(MAX)
SET #ParamDefinition = N'#OrganizationId int,
#OriginId nvarchar(256)'
SET #SQL= 'SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId'
IF ISNULL(#OriginId,'') <> ''
SET #SQL = #SQL + ' AND (OrigID in (''' + #OriginId + ''') '
DECLARE #counter INT = 1, #max INT = 0, #Origin nvarchar(50), #SQL_2 nvarchar(max)
SELECT #max = COUNT(id) FROM #inVars
WHILE #counter <= #max
BEGIN
SET #Origin = '_%'
SET #Origin = (select origins from #invars where id = CAST(#counter as varchar(10))) + #Origin
IF #Origin IS NOT NULL
BEGIN
SET #SQL_2 = N' OR OrigID LIKE ''' + #Origin + ''' '
SET #SQL = #SQL + #SQL_2
END
SET #counter = #counter + 1
END
SET #SQL=#SQL+')'
print #SQL
drop table #inVars
drop table #Test

It is not very clear what you want here but I think you are making it harder on yourself than you need to. There is no need to use the IN because you are also finding all values that begin with the same value. And you have hard coded the same values into your temp table. Using a string splitter this is about a million times less complicated. Just split your #OriginID on the commas and use LIKE in the join.
I am using the DelimitedSplit8k which you can find here
I am pretty sure this should get you the information you are looking for. I would recommend avoiding loops whenever possible.
create table #Test (OrganizationId varchar(100), OrigID varchar(50))
insert into #Test(OrganizationId,OrigID)
Values ('5','31'),
('5','31_00000'),
('5','33'),
('5','33_00000'),
('5','25'),
('5','25_00000'),
('5','HD_00000'),
('5','HD')
DECLARE
#OrganizationId int = 5,
#OriginId nvarchar(256) = N'31,25,33'
select *
from #Test t
join DelimitedSplit8K(#OriginID, ',') x on t.OrigID like x.Item + '%'
drop table #Test

I solved this.Thanks all who replied.
create table #Test (OrganizationId varchar(100), OrigID varchar(50))
insert into #Test(OrganizationId,OrigID)
Values ('5','31'),
('5','31_00000'),
('5','33'),
('5','33_00000'),
('5','25'),
('5','25_00000'),
('5','HD_00000'),
('5','HD')
DECLARE
#OrganizationId int = 5,
#OriginId nvarchar(256) = N'31,25,33'
create table #inVars(id int NOT NULL IDENTITY PRIMARY KEY, origins varchar(256))
insert into #inVars(origins)
Values ('31'),
('33'),
('25')
DECLARE #SQL NVARCHAR(MAX),
#ParamDefinition NVARCHAR(MAX)
SET #ParamDefinition = N'#OrganizationId int,
#OriginId nvarchar(256)'
SET #SQL= 'SELECT OrganizationId,OrigID
FROM #Test
WHERE OrganizationId=#OrganizationId'
IF ISNULL(#OriginId,'') <> ''
BEGIN
SET #SQL = #SQL +' AND (OrigID in (''' + #OriginId + ''')) '
END
IF ISNULL(#OriginId,'') <> ''
DECLARE #counter INT = 1, #max INT = 0, #Origin nvarchar(50), #SQL_2 nvarchar(max)
SELECT #max = COUNT(id) FROM #inVars
WHILE #counter <= #max
BEGIN
SET #Origin = (select origins from #invars where id = CAST(#counter as varchar(10)))
SET #Origin = #Origin+'_%'
SET #SQL_2 = N' OR (OrigID LIKE ''' + #Origin + ''') '
SET #SQL = #SQL + #SQL_2
SET #counter = #counter + 1
END
print(#SQL)
EXEC sp_executesql #SQL,#ParamDefinition,#OrganizationId,#OriginId
drop table #inVars
drop table #Test

Related

Have this problem with calling stored procedure unknown object type

I am trying to write a query that needs to call a stored procedure. But it always throws an error:
Unknown object type 'TABLEIXICHistoricalData' used in a CREATE, DROP, or ALTER statement.
This is query:
USE ETLCourse
DECLARE #LOOP TABLE
(
ID INT IDENTITY(1,1),
TableName NVARCHAR(100)
)
INSERT INTO #LOOP (TableName)
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '%_Stocks%'
DECLARE #b INT = 1, #m INT, #t NVARCHAR(100)
SELECT #m = MAX(ID) FROM #LOOP
WHILE #b <= #m
BEGIN
SELECT #t = TableName
FROM #LOOP
WHERE ID = #b
EXECUTE [dbo].[stp_BuildNormalizedTable] #t
SET #b = #b + 1
END
and here is the procedure:
ALTER PROCEDURE [dbo].[stp_BuildNormalizedTable]
#table NVARCHAR(100)
AS
BEGIN
DECLARE #cleanTable NVARCHAR(100),
#s NVARCHAR(MAX)
SET #cleanTable = REPLACE(#table, '_Stocks', 'HistoricalData')
SET #s = 'CREATE TABLE' + #cleanTable + '(ID INT IDENTITY(1,1), Price DECIMAL(13, 4), PriceDate DATE)
INSERT INTO' + #cleanTable + '(Price,PriceDate) SELECT [Adj Close],[Date] FROM'
+ #table + ' ORDER BY Date ASC'
--PRINT #s
EXECUTE sp_executesql #s
END
It should copy two specific column and create a new table by using #Loop table and procedure
You need to add 'space' after 'create table' and 'insert into' and 'from'
declare #s nvarchar(max)
declare #cleantable nvarchar(100)
declare #table nvarchar(100)
set #cleantable = 'aaa'
set #table = 'bbb'
SET #s = 'CREATE TABLE' + #cleanTable + '(ID INT IDENTITY(1,1),Price Decimal(13,4),PriceDate DATE)
Insert into' + #cleanTable
+ '(Price,PriceDate) SELECT [Adj Close],[Date] FROM'
+ #table + ' ORDER BY Date ASC'
print #s
Output:
CREATE TABLEaaa(ID INT IDENTITY(1,1),Price Decimal(13,4),PriceDate DATE)
Insert intoaaa(Price,PriceDate) SELECT [Adj Close],[Date] FROMbbb ORDER BY Date ASC
Use 'print' to check your query.

Loop with dynamic table name and where clause stored procedure

I am trying to update records and insert their audits to audit table.
For this purpose stored procedure waiting for above variables.
#m_obj_id INT,
#m_obj_code NVARCHAR(250),
#m_f_code NVARCHAR(250),
#m_nv NVARCHAR(4000),
#m_last_mod_by INTEGER,
#table_name SYSNAME,
--#where_clause NVARCHAR(4000)
Stored procedure formatting these variables as;
UPDATE #table_name SET #m_f_code=#m_nv WHERE id=#m_obj_id
And at last part inserting into audit.
I can use it with doing SELECT CONCAT and copying all the rows then execute.
But my goal is here not expecting #m_obj_id from user and replace it #where_clause. And use this #where_clause to get ids inside.
So far I tried;
DECLARE #Sql NVARCHAR(MAX)
DECLARE #RecordId int = 0
BEGIN
SET #SQL = N'
SELECT #RecordId = MIN(id)
FROM ' + #table_name + '
WHERE id > #RecordId AND (' + #where_clause + ')
IF #RecordId IS NULL BREAK
SET #m_obj_id = #RecordId'
Exec sp_executesql #sql
But couldnt get far with it.
Then I tried something like;
DECLARE #RowsToProcess int
DECLARE #CurrentRow int
DECLARE #SelectCol1 int
DECLARE #sql NVARCHAR(MAX)
SET #sql = N'
DECLARE #table1 TABLE (RowID int not null primary key identity(1,1), col1 int )
INSERT into #table1 (col1) SELECT id FROM ' + #table_name + ' Where ' + #where_clause + '
SET #RowsToProcess=##ROWCOUNT'
EXEC sp_executesql #sql,
N'#RowsToProcess INT OUTPUT', #RowsToProcess OUTPUT
SET #CurrentRow=0
WHILE #CurrentRow<#RowsToProcess
BEGIN
SET #CurrentRow=#CurrentRow+1
DECLARE #sql2 NVARCHAR(MAX)
SET #sql2 = N'
SET #m_obj_id =
(SELECT col1
FROM #table1
WHERE RowID=#CurrentRow)'
EXEC sp_executesql #sql2
But still no luck.
Can I achieve this any how? I am trying to do this for more than it should be.
Thanks all.
The non-dynamic way to implement dynamic filtering on sql is the following:
where id=#m_obj_id or #m_obj_id is null
For a LOT of more details on how to choose between dynamic and non-dynamic sql on this, I recommend this article by Erland Sommarskog
I found a solution. Thanks everyone for responding.
I used a temp table like
DECLARE #RowsToProcess INTEGER
DECLARE #CurrentRow INTEGER
DECLARE #SelectCol1 INTEGER
CREATE TABLE #tmp (RowID INTEGER NOT NULL PRIMARY KEY IDENTITY(1,1), col1 int)
DECLARE #sql NVARCHAR(MAX)
SET #sql = N'
INSERT into #tmp (col1) SELECT id FROM ' + #table_name + ' Where ' + #where_clause + '
SET #RowsToProcess=##ROWCOUNT'
INSERT INTO #tmp
EXEC sp_executesql #sql,
N'#RowsToProcess INT OUTPUT', #RowsToProcess OUTPUT
SET #CurrentRow=0
WHILE #CurrentRow<#RowsToProcess
BEGIN
SET #CurrentRow=#CurrentRow+1
SET #m_obj_id =
(SELECT col1
FROM #tmp
WHERE RowID=#CurrentRow)
Do stuff....

TSQL data types incompatible in the subtract operator

I'm using a while loop to iterate through some tables and carry out a replace on a field, to remove all the hyphens. All of the fields are varchar.
DECLARE #Table TABLE (TableName VARCHAR(max),Id int identity(1,1))
INSERT INTO #Table
Select distinct table_name From INFORMATION_SCHEMA.COLUMNS
DECLARE #max int
DECLARE #SQL VARCHAR(max)
DECLARE #TableName VARCHAR(max)
DECLARE #id int = 1
select #max = MAX(Id) from #Table
WHILE (#id <= #max)
BEGIN
SELECT #TableName = TableName FROM #Table WHERE Id = #id
SET #SQL = 'update '+ #TableName +' set colA = replace(colA,'-','');'
EXEC(#SQL)
SET #id = #id +1
END
the error I receive is:
The data types varchar(max) and varchar are incompatible in the subtract operator.
I've tried changing the varchar variables to fixed lengths or all to max, but nothing seems to work.
You need to use two single quotes when creating a single quote inside of a string:
DECLARE #Table TABLE (TableName VARCHAR(max),Id int identity(1,1))
INSERT INTO #Table
Select distinct table_name From INFORMATION_SCHEMA.COLUMNS
DECLARE #max int
DECLARE #SQL VARCHAR(max)
DECLARE #TableName VARCHAR(max)
DECLARE #id int = 1
select #max = MAX(Id) from #Table
WHILE (#id <= #max)
BEGIN
SELECT #TableName = TableName FROM #Table WHERE Id = #id
SET #SQL = 'update '+ #TableName +' set colA = replace(colA,''-'','''');'
EXEC(#SQL)
SET #id = #id +1
END

Table Name Variable in select statement in sql server

I want to use tablename variable in select statement, but it is giving error
- Must declare the table variable "#table"
alter PROCEDURE testTblName
(
#id int,
#name varchar(50)
)
AS
BEGIN
declare #table varchar(50)
declare #add varchar(150)
set #table = 'DBTest..testMaster'
select #add = address from #table where id=#id and name=#name
END
This is a snap shot of my code
You need to use dynamic sql for this:
alter PROCEDURE testTblName
(
#id int,
#name varchar(50)
)
AS
BEGIN
declare #table varchar(50)
declare #add varchar(150)
set #table = 'DBTest..testMaster'
DECLARE #sql NVARCHAR(MAX)
SELECT #sql = 'select #add = address from ' + #table + ' where id= ' + #id + ' and name= ' + #name
EXEC sp_executesql #sql
END
You can't use a variable for your table name. When you do select address from #table SQL expects #table to be a variable of the table type, not a scalar.
You're looking to do something like this:
ALTER PROCEDURE testTblName
(
#id INT,
#name VARCHAR(50)
)
AS
BEGIN
DECLARE #table VARCHAR(50),
#add VARCHAR(150),
#params VARCHAR(200),
#sql VARCHAR(200);
SET #params = '#add VARCHAR(50) OUTPUT';
SET #table = 'DBTest..testMaster'
SET #sql = 'SELECT #add = address FROM ' + #table + ' WHERE id=' + #id + ' AND name=' + #name
EXEC sp_executesql #sql, #params, #add OUTPUT;
...
...
END
I think, u will have to give something like this.
alter PROCEDURE testTblName
(
#id int,
#name varchar(50)
)
AS
BEGIN
declare #table varchar(50)
declare #add varchar(Max)
set #table = 'DBTest..testMaster'
Set #add = 'Select address from ' + #table + ' where id = ' + CAST(#id AS VARCHAR(10)) + ' and name = ' + #name
Exec(#add)
END

Passing negative values into stored procedure

I am trying to insert ID values in stored procedure from .net and the int value for ID is inserting negative value in the stored procedure.
But when a negative value is passed its giving me an error incorrect syntax near '*'.
Please help me.
Here is my stored procedure
ALTER PROCEDURE [dbo].[HotlinePlusAdministration_ArticleMigrator]
#Id AS INT,
--#CategoryID AS INT,
--#Title AS Varchar(200),
--#ArticleDate AS datetime,
#DestLinkServer AS VARCHAR(50),
#UserID AS VARCHAR(8),
#ReturnMsg AS VARCHAR(1000) OUTPUT
AS
BEGIN
DECLARE #Query AS NVARCHAR(4000)
DECLARE #Log AS VARCHAR(8000)
DECLARE #ArticleID as int
DECLARE #NewArticleID as int
DECLARE #ArticleKeyExists as int
DECLARE #Title as varchar(200)
DECLARE #CategoryID as INT
DECLARE #ArticleDate as varchar(30)
DECLARE #ParmDefinition nvarchar(500);
SET XACT_ABORT ON -- Required for nested transaction
BEGIN TRAN
-- Check if ArticleID exists in Destination Server
SET #Query = N' SELECT #ArticleKeyExists = COUNT(*)
FROM ' + #DestLinkServer + '.HL2_61.dbo.Article' + ' where ArticleKey = ' + str(#Id)
SET #ParmDefinition = N' #ID int, #ArticleKeyExists int OUTPUT';
EXECUTE sp_executesql #Query , #ParmDefinition, #ID, #ArticleKeyExists OUTPUT;
--EXECUTE sp_executesql 1234,'BRHLSQL8','BRWSQLDC',#return = retnmsg
IF ##ERROR <> 0
BEGIN
ROLLBACK TRANSACTION
SET #ReturnMsg = #Log + '<span style="color:red;">ERROR: <br></span>'
RETURN -1
END
--Delete existing Articles for select page
set #Query = 'DELETE FROM ' + #DestLinkServer +
'.HL2_61.dbo.Article ' +
'WHERE ArticleKey = ' + CONVERT(VARCHAR, #Id)
--'WHERE CategoryID = ' + CONVERT(VARCHAR, #CategoryID) + ' and Title = ''' + #Title + ''' and ArticleDate = ''' + #ArticleDate + ''''
Print #Query
EXEC(#Query)
When I am executing the code as below I am getting the error.
DECLARE #return_value int,
#ReturnMsg varchar(1000)
EXEC #return_value = [dbo].[Migrator]
#Id = -1591276581,
#DestLinkServer = N'SQLDC',
#UserID = N'10c1',
#ReturnMsg = #ReturnMsg OUTPUT
SELECT #ReturnMsg as N'#ReturnMsg'
SELECT 'Return Value' = #return_value
GO
Please someone help me..
Thanks
When you convert an int to a varchar, you have to specify the size:
Try this:
CONVERT(VARCHAR(50), #Id)
and avoid using str(#Id)

Resources