I have this query:
DECLARE #holdIds VARCHAR(MAX)
SET #holdIds = '1,2,3'
DECLARE #flagNames NVARCHAR(MAX);
SELECT
#flagNames = COALESCE(#flagNames + ',', '') + FlagName
FROM
BurnHoldStatus
WHERE
BurnHoldStatusID in (#holdIds);
SELECT #flagNames AS FlagName;
In this example the variable '#holdIds' has values '1,2,3' but could have just one value '1'.
When I run the query, an error appears:
Msg 245, Level 16, State 1, Line 6
Conversion failed when converting the varchar value '1,2,3' to data type int.
I try convert the value of '#holdIds' but not work.
Any idea?
Thanks.
[UPDATE]
I found the answer:
DECLARE #holdIds NVARCHAR(MAX);
SET #holdIds = '1,2,3';
DECLARE #holdIdList TABLE(id INT);
INSERT INTO #holdIdList
SELECT * FROM Split(#holdIds, ',');
DECLARE #flagNames NVARCHAR(MAX);
SELECT
#flagNames = COALESCE(#flagNames + ',', '') + FlagName
FROM
BurnHoldStatus, #holdIdList h
WHERE
BurnHoldStatusID = h.id;
SELECT #flagNames AS FlagName;
In this code I use an function 'Split' to split a string passing the divisor (i.e: ',').
Split function code:
ALTER FUNCTION [dbo].[Split]
(
#RowData nvarchar(MAX),
#SplitOn nvarchar(MAX)
)
RETURNS #RtnValue table
(
Data nvarchar(MAX)
)
AS
BEGIN
Declare #Cnt int
Set #Cnt = 1
While (Charindex(#SplitOn,#RowData)>0)
Begin
Insert Into #RtnValue (data)
Select
Data = ltrim(rtrim(Substring(#RowData,1,Charindex(#SplitOn,#RowData)-1)))
Set #RowData = Substring(#RowData,Charindex(#SplitOn,#RowData)+1,len(#RowData))
Set #Cnt = #Cnt + 1
End
Insert Into #RtnValue (data)
Select Data = ltrim(rtrim(#RowData))
Return
END
Thanks for Vercelli by show other post.
Thanks guys :)
The comment made by swe is correct. You could make the query dynamic, then insert #holdIds See below for a workaround:
DECLARE #holdIds VARCHAR(MAX)
SET #holdIds = '1,2,3'
SET #holdIds = (CHAR(39) + (REPLACE(#holdIds, ',', ''',''') + CHAR(39)))
You can do this, then set the entire query above as a varchar variable, then execute. There are certainly other workarounds as well but dynamic SQL will work.
Related
I would like to use T-SQL while loop to get var_1, var_2, var_3 individually at each loop. But, it returns error message "Must declare the scalar variable "#var_1","#var_2","#var_3". Could please help me out. Thank you. I attached my code below:
declare #var_1 varchar(max)
set #var_1 = 'abcdef'
declare #var_2 varchar(max)
set #var_2 = 'ghijk'
declare #var_3 varchar(max)
set #var_3 = 'lmnopq'
declare #counter tinyint
set #counter = 1
declare #termName varchar(max)
while #counter<=3
begin
set #termName = '#var_' + CONVERT(varchar(10), #counter)
print #termName
declare #sql_code varchar(max)
set #sql_code = '
print '+ #termName+';
'
print #sql_code
exec (#sql_code)
set #counter = #counter + 1
end
When you use EXEC with a string, the command is carried out in a new session, so variables cannot be used pass arguments or get results. However, you could create a temporary table, put the arguments in it and use this table inside the dynamic statement:
create table #T (val_1 varchar(10), val_2 varchar(10), val_3 varchar(10));
insert into #T values ('abcef', 'ghijk', 'lmnopq');
declare #counter tinyint
set #counter = 1
while #counter<=3
begin
declare #sql_code varchar(max)
set #sql_code = '
declare #v varchar(10);
select #v = val_' + CONVERT(varchar(10), #counter) + ' FROM #T;
print #v;
'
print #sql_code
exec (#sql_code)
set #counter = #counter + 1
end
This is my procedure:
create proc spasdf
#sdate int,
#edate int
as
DECLARE #LoopCounter INT = #sdate
WHILE #LoopCounter <= #edate)
BEGIN
SET #LoopCounter = #LoopCounter + 1
declare #value varchar(30)
set #value = '['+#LoopCounter+']'
select UserID, UserName, #value
from vwfinal
END
I run it using:
spasdf 1,5
My expected result is:
#value=[1],[2],[3],[4],[5]
When I passing parameter to my stored procedure it shows this error
Msg 245, Level 16, State 1, Procedure spasdf, Line 40
Conversion failed when converting the varchar value '[' to data type int.
Does anyone know why?
If you want to get all the #LoopCounter values as a string. Declare the #value outside while loop and put the select statement after the while loop.
create proc spasdf
#sdate int,
#edate int
as
DECLARE #value varchar(30)=''
DECLARE #LoopCounter INT = #sdate
WHILE ( #LoopCounter <= #edate)
BEGIN
SET
#LoopCounter = #LoopCounter + 1
set #value=#value + ',' + QUOTENAME(#LoopCounter)
END
set #value=STUFF(#value,1,1,'')
select UserID,UserName,#value from vwfinal
The above code will append all the #LoopCounter variable as a string along with a comma at first.
using set #value=STUFF(#value,1,1,'') we replace the first comma with a empty space.
You are getting a conversion error because #LoopCounter is of type INT and you are trying to append it to varchar. If you want to do so, you have to CONVERT or CAST the #LoopCounter variable to varchar
If you have an older version of SQL Server you can go for traditional way of appending and creating the required string format as below:
set #value=#value + ',[' + CONVERT(VARCHAR(100),#LoopCounter) + ']'
to get expected result [1],[2],[3],[4],[5] you need something like:
create proc spasdf
#sdate int,
#edate int
as
declare #value varchar(300) = ''
DECLARE #LoopCounter INT = #sdate
WHILE ( #LoopCounter <= #edate)
BEGIN
SET #LoopCounter = #LoopCounter + 1
set #value= #value + ',['+ CAST(#LoopCounter AS VARCHAR(50)) +']'
END
select UserID,UserName,STUFF(#value,1,1,'') as Value from vwfinal
Considering your output, consider declaring #value and select statement outside the while loop.
Try replacing the line:
set #value='['+#LoopCounter+']'
With this:
set #value= CONCAT(#value,'['+cast(#LoopCounter as varchar)+'],')
And to remove the last comma from value, you can use something like:
Select UserID,UserName, substring(#value, 1, (len(#value) - 1)) as Value
I am trying to create a dynamic query in SQL Server.
Input: #value= abc,def,en,
Output: MAX(abc) as abc, MAX(def) as def, MAX(en) as en
My efforts so far took me no where.
With CONVERT() and REPLACE() I achieved a bit but finding it difficult. Need help!
Try this:
declare #value varchar(50) = 'abc,def,en'
declare #result varchar(100) = ''
select #result = replace(#value,'abc', 'MAX(''abc'') as abc')
select #result = replace(#result,'def', 'MAX(''def'') as def')
select #result = replace(#result,'en', 'MAX(''en'') as en')
select #result
You can also do the replacements in one line by nesting the expressions.
EDIT: If you have variable values in #value, you can take the below approach:
Use a splitter function to get the individual values in the string as a list. You can take a look at this article for implementations.
Insert this list to a temp table.
Update the temp table as shown above.
Concatenate the values into a single string using STUFF like so:
select stuff((select ',' + val from #temp for xml path('')),1,1,'')
Try this:
DECLARE #Value VARCHAR(200) = 'abc,def,en'
DECLARE #Template VARCHAR(100) = 'MAX(''##'') as ##'
DECLARE #Result VARCHAR(1000) = ''
DECLARE #Data VARCHAR(100) = ''
WHILE LEN(#Value) > 0
BEGIN
SET #Data = REPLACE(LEFT(#Value, ISNULL(NULLIF(CHARINDEX(',', #Value),0), LEN(#Value))),',','')
SET #Result = #Result + REPLACE(#Template, '##', #Data)
IF CHARINDEX(',', #Value) > 0
BEGIN
SET #Result = #Result + ','
SET #Value = REPLACE(#Value,#Data + ',','')
END
ELSE
SET #Value = REPLACE(#Value,#Data,'')
END
SELECT #Result
Have a look at SQL User Defined Function to Parse a Delimited String
So you can do like
Declare #Value varchar(200) = 'abc,def,en'
Declare #Item varchar(20) = null
declare #Str varchar(1000)=''
WHILE LEN(#Value) > 0
BEGIN
IF PATINDEX('%,%',#Value) > 0
BEGIN
SET #Item = SUBSTRING(#Value, 0, PATINDEX('%,%',#Value))
-- SELECT #Item
IF(LEN(#Str)>0)
SET #Str = #Str + ', SELECT MAX('+#Item+') as ' +#Item
ELSE
SET#Str = #Str + ' SELECT MAX('+#Item+') as ' +#Item
SET #Value = SUBSTRING(#Value, LEN(#Item + ',') + 1, LEN(#Value))
END
ELSE
BEGIN
SET #Item = #Value
SET #Value = NULL
SET #Str = #Str + 'SELECT MAX('+#Item+') as ' + #Item
END
END
select #Str
See the fiddle sample here
I have a table that stores SQL queries. I retrieve a query according to a condition and store it in a variable:
---------------------------------------------------------
ID | Query
---------------------------------------------------------
1 | 'Select Id,Name from Student'
2 | 'Select Id,Name,Father_Name from Student'
3 | 'Select Id,Name,Email from Student_Detail'
....
---------------------------------------------------------
For example, a variable #sql might have the first query from above:
Declare #sql nvarchar(500)
set #sql = 'Select Id,Name from Student'
I execute this query using:
Exec(#sql)
The problem is, how do I know which columns are used in that query? I'm trying to achieve something like what ColdFusion does with query.ColumnList, which returns the column list used in that query.
Try this:
SELECT SUBSTRING(query,8,CHARINDEX('from',query)-9) AS ColumnList
FROM YourTable
this is a variant of mehdi lotfi solution but is equally weak in the sense that only gives you whatever is in between the select and from statements so if you have aliases or calculations or 'case' statements it will not work properly; it does work if the column list is straight forward comma separated columns:
SELECT LEFT(REPLACE(#SQL,'Select ',''), CHARINDEX(' from',REPLACE(#SQL,'Select ',''))) AS ColumnList
Finally i managed to solve at my own using this solution.
Declare #sql varchar(1000)
Declare #valueList nvarchar(500)
Declare #tbl Table(Name varchar(100))
Declare #selectPos Int
Declare #fromPos Int
Declare #len Int
Declare #pos Int
Declare #prevpos Int
Declare #Delimeter varchar(2)
set #sql = 'Select Id,Name,Father_Name from Student'
set #selectPos = CHARINDEX('Select ', #sql, 1)+7
set #fromPos = CHARINDEX('From ', #sql, 1)
set #len = #fromPos - #selectPos
set #valueList = SUBSTRING(#sql, #selectPos, #len)
set #Delimeter = ', '
set #pos = 1
set #prevpos = 0
while #pos > 0
Begin
set #pos = charIndex(#Delimeter, #valueList, #pos)
If #pos = 0
Begin
Insert into #tbl
Select SUBSTRING(#valueList,#prevPos + 1,LEN(#valueList) - #prevpos)
Break;
End
Insert into #tbl
Select SUBSTRING(#valueList,#prevPos + 1,#pos-#prevpos - 1)
set #prevpos = #pos
set #pos = #pos + 1
End
select * from #tbl
I wonder why recently I create functions but SQL Server returns error in calling them, in a case they get added to the functions list of the database.
For example for the following function I get such a error:
declare #cats nvarchar(1000)
set #cats = 'a|b|c|d|e'
SELECT dbo.fncSplit(#Cats, '|')
Error:
Cannot find either column "dbo" or the user-defined function or aggregate "dbo.fncSplit", or the name is ambiguous.
Sample Function:
CREATE FUNCTION [dbo].fncSplit
(
#RowData NVARCHAR(MAX),
#Delimeter NVARCHAR(MAX)
)
RETURNS #RtnValue TABLE
(
ID INT IDENTITY(1,1),
Data NVARCHAR(MAX)
)
AS
BEGIN
DECLARE #Iterator INT
SET #Iterator = 1
DECLARE #FoundIndex INT
SET #FoundIndex = CHARINDEX(#Delimeter,#RowData)
WHILE (#FoundIndex>0)
BEGIN
INSERT INTO #RtnValue (data)
SELECT
Data = LTRIM(RTRIM(SUBSTRING(#RowData, 1, #FoundIndex - 1)))
SET #RowData = SUBSTRING(#RowData,
#FoundIndex + DATALENGTH(#Delimeter) / 2,
LEN(#RowData))
SET #Iterator = #Iterator + 1
SET #FoundIndex = CHARINDEX(#Delimeter, #RowData)
END
INSERT INTO #RtnValue (Data)
SELECT Data = LTRIM(RTRIM(#RowData))
RETURN
END
Any suggestion or solution would be highly appreciated.
This is table-value function. The syntax is
declare #cats nvarchar(1000)
set #cats = 'a|b|c|d|e'
SELECT * from dbo.fncSplit(#Cats, '|')