I have the following stored procedure that takes one parameter and I need to use that in my IN clause, but that does not work. I get this error when trying.
Conversion failed when converting the varchar value '1,2' to data type int
Here is my stored procedure..
CREATE PROCEDURE [dbo].[p_GetSegment]
#SegmentIds nVarChar(20)
AS
BEGIN
SET NOCOUNT ON;
SELECT dbo.Segment.Name
FROM dbo.tbl_Category
INNER JOIN dbo.Segment ON dbo.tbl_Category.SegmentId
WHERE (dbo.Segment.Id IN (#SegmentIds))
I pass in "1,2". How can I make this work?
In SQL Server 2016+, you can use string_split():
WHERE dbo.Segment.Id IN (SELECT value FROM STRING_SPLIT(#SegmentIds, ','))
You can use any string split function for this purpose. You can also just use `like:
where ',' + #SegmentIds + ',' like '%,' + convert(varchar(255), dbo.Segment.Id) + ',%'
Related
I have a dynamic stored procedure in SQL Server that works well to pivot a table:
CREATE PROCEDURE dbo.DynamicPivotTableInSql
#ColumnToPivot NVARCHAR(255),
#ListToPivot NVARCHAR(255),
#SurveyID INT=10
AS
BEGIN
DECLARE #SqlStatement NVARCHAR(MAX)
SET #SqlStatement = N'SELECT *
FROM
(SELECT
[resp_id], [benefit], [weight]
FROM Segment_Responses) myResults
PIVOT
(SUM([weight])
FOR [' + #ColumnToPivot + ']
IN (' + #ListToPivot + ')) AS PivotTable';
EXEC (#SqlStatement)
END
and I call it like this
EXEC DynamicPivotTableInSql
#ColumnToPivot = 'benefit',
#ListToPivot = '[OBSERVABILITY], [COST], [EASE OF USE], [SERVICE]'
Here is where I run into problems. You'll notice I have hardcoded #SurveyID = 10 and if I try to add that as a where statement in the stored procedure like this:
FROM Segment_Responses
WHERE survey_id = ' + #SurveyID + '
and run the stored procedure again I get this error:
Conversion failed when converting the nvarchar value '
SELECT * FROM (
SELECT
[resp_id],
[benefit],
[weight]
FROM Segment_Responses where survey_id=' to data type int.
I've tried to solve this many ways (e.g., passed the Int variable instead of hard coding it) but always get the same result. Any ideas what is going on?
Just to try to add some clarity, when you add together two different types, SQL Server will (where it can) implicitly convert one to the other - the result must be a single type after all.
It decides which one to convert "to the other" based on an order of precedence.
So where you are trying to concatenate a varchar with an int, the int has the higher order of precedence. This is also a common cause of errors and bugs when using a case expression when mixing types in different execution paths of the expression.
You need to be explicit and cast the int to a varchar.
Ideally you would use a parameterised query which would also reuse the cached execution plan - this may be beneficial if the cardinality of the data is similar but sometimes making the value part of the query dynamically can be advantagous, it depends on the use-case.
This is why the syntax EXEC (#SQL) is strongly suggested against. Use sys.sp_executesql and parametrise your statement:
SET #SQL = N'SELECT ...
FROM ...
WHERE survey_id = #SurveyID ...;';
EXEC sys.sp_executesql #SQL, N'#SurveyID int',SurveyID;
The + only works with strings. If you use a number TSQL assumes you are trying to use the addition operator, and tries to convert the string argument to int.
eg this
select 1 + '2'
works and returns 3.
Use CONCAT instead of +, or use an explicit conversion on the int.
eg
WHERE survey_id = ' + cast(#SurveyID as varchar(20)) + '
This question already has answers here:
SQL Server dynamic PIVOT query?
(9 answers)
Closed 3 years ago.
I wrote a function that will be passed 1 string parameter. Inside that function it is supposed to get that string as you can see but its not working because parameter I transfer is string. The receiver of parameter suppose to get column name if I write column name as its format it works fine but I need to get passed.
This is the string I pass:
[Where], [University], [BeginDate], [GraduateDate], [Major]
Now this is function
DROP FUNCTION NewTable
GO
CREATE FUNCTION NewTable
(#PassParameter NVARCHAR(MAX))
RETURNS TABLE
AS
RETURN
SELECT *
FROM
(SELECT O.RowIndex, O.OptionValue, T.TypeValue
FROM Options O
LEFT OUTER JOIN Types T ON T.TypeID = O.TypeID
GROUP BY O.RowIndex, O.OptionValue, T.TypeValue) d
PIVOT
(
MAX(OptionValue)
FOR [TypeValue] IN (#PassParameter) <-- this is tricky part this will not work but I put this [Where], [University], [BeginDate], [GraduateDate], [Major] this is gonna work
) PIV
GO
Also I can't use a stored procedure because using a function is my requirement.
You cannot have dynamic sql within a user defined function. If you want to have this kind of functionality, you can define a CLR user defined function.
Instead, You can define a stored procedure with dynamic sql and INSERT the output of stored procedure into the tabletype.
I have given sample for your reference.
First defined a user defined table type
CREATE TYPE RowIndex as
Table
(
RowIndex INT,
optionValue VARCHAR(20),
TypeValue VARCHAR(20)
);
Next define stored procedure with dynamic sql content.
CREATE PROCEDURE NewTable
(#PassParameter NVARCHAR(MAX))
AS
BEGIN
DECLARE #sql NVARCHAR(MAX);
SET #sql =
'
SELECT *
FROM
(SELECT O.RowIndex, O.OptionValue, T.TypeValue
FROM Options O
LEFT OUTER JOIN Types T ON T.TypeID = O.TypeID
GROUP BY O.RowIndex, O.OptionValue, T.TypeValue) d
PIVOT
(
MAX(OptionValue)
FOR [TypeValue] IN '+ #PassParameter +'
) PIV
'
EXEC sp_Executesql #sql
END
GO
Now, Insert the output of the stored procedure into the table type.
DECLARE #RowIndex RowIndex
INSERT INTO #RowIndex
EXEC NewTable 'Test'
SELECT * FROM #RowIndex
This question already has answers here:
Dynamic SQL Not Converting VARCHAR To INT (shouldn't anyway)
(2 answers)
Closed 4 years ago.
I have a dynamic SQL query inside a stored procedure that works and gives me the correct results. But it is taking too long-because I have to compare as varchar instead of int. I believe #query variable in SQL server requires the statement to be a unicode.
Here is the dynamic sql part
ALTER PROCEDURE [dbo].[sp_GetRows]( #Id varchar(64))
AS
BEGIN
DECLARE #Query nvarchar(4000),
#Comp varchar(256)
SELECT #Comp
= STUFF((
SELECT DISTINCT ',' + char(39)+
tci.Component +char(39)
FROM TCI tci WITH(NOLOCK)
JOIN CDetail cd WITH(NOLOCK)
ON tci.ParentCId = cd.CIdentifier
WHERE tci.ParentCId = #Id
AND cd.ParentBranch IS NULL
FOR XML PATH('')),1,1,'')
SET #Query
= 'WITH CTE AS
(
SELECT '+#Id+' as ParentCId, CIdentifier as ChildCId,
a.Comp as Comp
from dbo.CD cd WITH(NOLOCK)
INNER JOIN
(SELECT DISTINCT ChildCId,Comp
FROM TCI tc WITH(NOLOCK)
WHERE ParentCId = '+ #Id + '
) a
ON cd.CIdentifier= a.ChildCId
);
EXEC (#Query)
END;
Here is the comparison-
SELECT CIdentifier FROM #tempTable temp WITH(NOLOCK)
WHERE temp.CIdentifier < '+#Id+'....
This compares as CIdentifier =1122233 instead of CIdentifier ='1122233' because dynamic SQL is not allowing me to pass it as an int. I keep getting the 'cannot convert varchar to int error'
So I used parameterized query - hoping that would enable me to pass int values.Here is the query part
SET #Query
= N';WITH CTE AS
(
......
(SELECT DISTINCT ChildCId,Comp
FROM TCI tc WITH(NOLOCK)
WHERE ParentCId = #Id
AND ChildCId + tc.Comp
NOT IN
(SELECT ChildId + Comp FROM dbo.TCI WITH(NOLOCK)
WHERE ParentId IN (SELECT CIdentifier FROM #tempTable WITH(NOLOCK)
WHERE temp.CIdentifier < #Idn
AND Comp IN ( #Comp))
)
)
)a
ON cd.CIdentifier= a.ChildId
)
SELECT * FROM CTE;'
EXEC sp_executeSQL #Query,'#Id VARCHAR(64),#Idn INT,#comp VARCHAR(256)',#Id=#Id,#Idn=#Idn,#comp =#comp
This gives me incorrect results and when I saw the execution using a trace - saw that values are not being passed onto the query. How can I get the query to pick up the variables?
Just change WHERE ParentCId = '+ #Id + ' to WHERE ParentCId = '+ cast(#Id as varchar(16)) + ' in the first query. The problem is SQL Server see's + as addition when the value is a numeric type, or date, and concatenation when it isn't. This is where you get the error from. However, when you do this, it will not make SQL Server compare it as a string literal so you don't have to worry about that. You can see this if you use PRINT (#Query) at the end instead of EXEC (#Query)
Note, this needs to be changed at the other locations you have any NUMERIC data type, like in the SELECT portion, SELECT '+ cast(#Id as varchar(16)) +'
Also, you code doesn't show where #Id value comes from, so be cautious of SQL injection here.
I have a stored proc in the following format
create PROCEDURE [dbo].[test proc]
#identifier varchar(20),
#issuerName varchar(max),
#max_records int=1000
AS
BEGIN
declare #select nvarchar(30)
SELECT #identifier as '#identifier'
, (
SELECT
MoodysOrgID as '#MoodysOrgID'
,ReportDate as '#ReportDate'
,m.UpdateTime as '#UpdateTime'
,m.FileCreationDate as '#FileCreationDate'
from mfm_financial_ratios m
inner join mfm_financial_ratios_coa c on c.AcctNo = m.AcctNo
where ReportDate in (select distinct top (#max_records) reportdate from mfm_financial_ratios where MoodysOrgID = m.MoodysOrgID)
and m.MoodysOrgID=(select top 1 IssuerID_Moodys as id from loans where LIN=#identifier or LoanXID=#identifier
and ParentName_Moodys=#issuerName and IssuerID_Moodys is not null)
order by ReportDate desc
FOR XML PATH('FinRatios'), TYPE
)
FOR XML PATH('FinRatiosHistory')
END
but i would like to make by query execute as dynamic sql
and my stored proc looks like
create PROCEDURE [dbo].[test proc]
#identifier varchar(20),
#issuerName varchar(max),
#max_records int=1000
AS
BEGIN
declare #select nvarchar(30)
set #select = N'SELECT #identifier as '#identifier'
, (
SELECT
MoodysOrgID as '#MoodysOrgID'
,ReportDate as '#ReportDate'
,m.UpdateTime as '#UpdateTime'
,m.FileCreationDate as '#FileCreationDate'
from mfm_financial_ratios m
inner join mfm_financial_ratios_coa c on c.AcctNo = m.AcctNo
where ReportDate in (select distinct top (#max_records) reportdate from mfm_financial_ratios where MoodysOrgID = m.MoodysOrgID)
and m.MoodysOrgID=(select top 1 IssuerID_Moodys as id from loans where LIN=#identifier or LoanXID=#identifier
and ParentName_Moodys=#issuerName and IssuerID_Moodys is not null)
order by ReportDate desc
FOR XML PATH('FinRatios'), TYPE
)
FOR XML PATH('FinRatiosHistory')'
exec #select
END
The following stored proc gives issues because of the comma used in it .Can someone let me know what you be the correct way of doing it
The problem are not the commas. You mostly have two problems: one, you're not escaping the quotes correctly. And two, you're not concatenating your variables correctly. Here's an example of both:
For concatenating variables: In your first select line, you cannot do this:
SELECT #identifier as '#identifier'
because sql does not know what to do with #identifier that way. You should concatenate the variable this way:
SELECT #identifier as ' + #identifier + '.. everything else goes here
Also, when you will have to concatenate max_records, since it's an int variable you should cast it to varchar first, like this:
select distinct top (' + cast(#max_records as varchar(10) + ') ....
Whenever you're using a variable in the middle of the string (such as #max_records) you HAVE to concatenate it in order for SQL to know it's a variable and not just a string. You didn't do it with max_records, #issuerName, etc.
For escaping quotes: You need to escape your single quotes when you don't want your select string to unexpectedly end. For example here:
FOR XML PATH('FinRatiosHistory')'
You should escape them with double quotes (google escaping single quotes sql if you don't get it)
FOR XML PATH(''FinRatiosHistory'')'
I need to write a procedure where I have to sum an unknown column name.
The only information I have access to is the column position.
I am able to get the column name using the following:
SELECT #colName = (SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='TABLENAME' AND ORDINAL_POSITION=#colNum)
I then have the following:
SELECT #sum = (SELECT SUM(#colName) FROM TABLENAME)
I then receive the following error:
Operand data type varchar is invalid for sum operator
I am confused about how to make this work. I have seen many posts on convert and cast, but I cannot cast to an float, numeric, etc because this is a name.
I would appreciate any help.
Thank you
This is not possible. You will have to assemble the SQL query and then execute it. Something like this:
SET #sqlquery = 'SELECT SUM(' + #colName + ') FROM TABLENAME'
EXECUTE ( #sqlquery )
Adjust accordingly.