Using Variable as part of column name in Dynamic SQL - sql

I am trying to use a variable as part of a column name in a dynamic SQL statement.
I have 4 columns that are called Player1Action, Player2Action, Player3Action and Player4Action.
Depending on the varaible #CurrentPlayerId, I want to update the relevant player column with some data.
So for example, if CurrentPlayerId contains 1, then update column Player1Action.
I realise I could achieve this with a series of IF statements, but I would like to do it in a cleaner manner.
I have the following code, but I think my escaping is causing issues. I have re-written this a view times but I don't seem to be able to get it to work.
DECLARE
#CurrentPlayerId INT,
#CurrentPlayerBetAmount nvarchar(MAX),
#stmt nvarchar(MAX);
SET #CurrentPlayerId = 1
SET #CurrentPlayerBetAmount = 100
SET #stmt = N'UPDATE HandCurrent SET ''Player'' ''+'' #CurrentPlayerId ''+'' ''Action'' = 1 '','' ''Player'' ''+'' #CurrentPlayerId ''+'' ''ActionSize'' = #CurrentPlayerBetAmount'
EXECUTE sp_executesql #stmt
If I run this as a select I get the following returned.
UPDATE HandCurrent SET 'Player' '+' #CurrentPlayerId '+' 'Action' = 1 ',' 'Player' '+' #CurrentPlayerId '+' 'ActionSize' = #CurrentPlayerBetAmount

DECLARE
#CurrentPlayerId INT,
#CurrentPlayerBetAmount INT,
#stmt nvarchar(MAX);
SET #CurrentPlayerId = 1
SET #CurrentPlayerBetAmount = 100
SET #stmt = N'UPDATE HandCurrent SET
Player' + CAST(#CurrentPlayerId AS NVARCHAR(10)) + 'Action = 1,
Player' + CAST(#CurrentPlayerId AS NVARCHAR(10)) + 'ActionSize = '
+ CAST(#CurrentPlayerBetAmount AS NVARCHAR(10))
EXECUTE sp_executesql #stmt
Juan Carlos had it right only issue is datatypes of variables #CurrentPlayerId is an INT so you would need to cast it to NVARCHAR() https://www.mssqltips.com/sqlservertip/3014/concatenation-of-different-sql-server-data-types/.
To be consistent you should have declared #CurrentPlayerBetAmount as INT as well. If you do then you need to cast it too.
However, you could also simply DECLARE both as NVARCAHR(MAX) and then single quote the value when setting it such as:
DECLARE
#CurrentPlayerId NVARCHAR(MAX),
#CurrentPlayerBetAmount NVARCHAR(MAX),
#stmt nvarchar(MAX);
SET #CurrentPlayerId = '1'
SET #CurrentPlayerBetAmount = '100'
SET #stmt = N'UPDATE HandCurrent SET
Player' + #CurrentPlayerId + 'Action = 1,
Player' + #CurrentPlayerId + 'ActionSize = ' + #CurrentPlayerBetAmount
EXECUTE sp_executesql #stmt
Or My preference if you are going to change a record anyway would be just to do the update statement if you have 4 columns. You could also think of nth Normalizing and making the columns Rows....
DECLARE #CurrentPlayerId INT = 1
DECLARE #CurrentPlayerBetAmount INT = 100
UPDATE HandCurrent
Player1Action = CASE WHEN #CurrentPlayerId = 1 THEN 1 ELSE PlayerAction1 END
,Player1ActionSize = CASE WHEN #CurrentPlayerId = 1 THEN #CurrentPlayerBetAmount ELSE Player1ActionSize END
,Player2Action = CASE WHEN #CurrentPlayerId = 2 THEN 1 ELSE PlayerAction2 END
,Player2ActionSize = CASE WHEN #CurrentPlayerId = 2 THEN #CurrentPlayerBetAmount ELSE Player2ActionSize END
,Player3Action = CASE WHEN #CurrentPlayerId = 3 THEN 1 ELSE PlayerAction3 END
,Player3ActionSize = CASE WHEN #CurrentPlayerId = 3 THEN #CurrentPlayerBetAmount ELSE Player3ActionSize END
,Player4Action = CASE WHEN #CurrentPlayerId = 4 THEN 1 ELSE PlayerAction4 END
,Player4ActionSize = CASE WHEN #CurrentPlayerId = 4 THEN #CurrentPlayerBetAmount ELSE Player4ActionSize END
WHERE
????
Note you are actually updating the entire table is that what you desire?

dont quote the variables.
SET #stmt = N'UPDATE HandCurrent SET
Player' + #CurrentPlayerId + 'Action = 1,
Player' + #CurrentPlayerId + 'ActionSize = ' + #CurrentPlayerBetAmount

Speaking of cleanest way to do this, IMHO the best approach is to use sp_executesql with parameters, implying the #CurrentPlayerId and #CurrentPlayerBetAmount are input parameters of the given code:
Declare #sql nvarchar(256)
, #sql1 nvarchar(256) = N'update HandCurrent
Set Player1Action =#value,
Player1ActionSize =#size'
, #sql2 nvarchar(256) = N'update HandCurrent
Set Player2Action =#value,
Player2ActionSize =#size'
, #params nvarchar (128)
, #CurrentPlayerId int
;
Select #sql = case #CurrentPlayerId when 1 then #sql1 when 2 then #sql2 else '' end;
If #sql <> '' begin
set #params = N'#value int, #size int';
execute sp_executesql #sql, #params,
#value =1,
#size = #CurrentPlayerBetAmount
;
End

Related

How to add generic condition to sp select?

I really don't know what to do in this situation, so don't be too harsh.
If I have my select:
declare #Id uniqueidentifier = 'some parent guid'
declare #Type int = 1 -- can be 1, 2 or 3
declare #UserType varchar(max) --can be 0, anything else than 0, or all users at once
if(#Type = 1)
set #UserType = 'and UserType <> 0'
if(#Type = 2)
set #UserType = 'and UserType = 0'
if(#Type = 3)
set #UserType = ''
select * from users where parentId = #Id + #UserType
What to do in the situation where condition is "generic"? Do i really need to create 3 different Sp?
You can use AND/OR logic to simulate the If-else condition in where clause. Try something like this
select * from users
where
parentid= #id
and
(
(#Type = 1 and UserType <> 0)
or
(#Type = 2 and UserType = 0)
or
(#Type = 3)
)
or you can also use Dynamic sql to do this
declare #Id uniqueidentifier = 'some parent guid'
declare #Type int = 1 -- can be 1, 2 or 3
Declare #UserType varchar(max) --can be 0, anything else than 0, or all users at once
Declare #sql nvarchar(max)
if(#Type = 1)
set #UserType = ' and UserType <> 0'
if(#Type = 2)
set #UserType = ' and UserType = 0'
if(#Type = 3)
set #UserType = ''
set #sql = 'select * from users where parentId ='''+ cast(#Id as varchar(25))+''''+ #UserType
--Print #sql
Exec sp_executesql #sql
Different select statements would be most efficient since each is a fundamentally different query. If static SQL becomes unwieldly, use dynamic SQL. Below is a parameterized example using techniques from http://www.sommarskog.se/dyn-search.html.
declare #sql nvarchar(MAX) = N'select * from users where parentId = #Id';
declare #Id uniqueidentifier = 'some parent guid';
declare #Type int = 1; -- can be 1, 2 or 3
declare #UserType varchar(max); --can be 0, anything else than 0, or all users at once
SET #sql = #sql + CASE #Type
WHEN 1 THEN N' and UserType <> 0'
WHEN 2 THEN N' and UserType = 0'
WHEN 3 THEN N'' END;
EXEC sp_executesql
#sql
, N'#Id uniqueidentifier'
, #Id = #Id;

How to pass datetime in dynamic query in sql?

I have written a stored procedure like this
ALTER PROCEDURE [dbo].[spLoadPendingPaymentSheetByFilter] --'2015-04-01','2015-04-02','Select-One','Select-One','Select-One',''
#FromDate as datetime,
#ToDate as datetime,
#Status as nvarchar(50),
#Remarks as nvarchar(50),
#Paymenttype as nvarchar(50),
#BillID as nvarchar(50)
AS
Declare #Where as nvarchar(max)
set #Where = '( MenifestDate BETWEEN ''' + CONVERT(VARCHAR(10),#FromDate, 101) + ''' and ''' + CONVERT(VARCHAR(10),#ToDate, 101) + ''' )'
if(#Status <> 'Select-One')
set #Where = 'Status = '+ #Status
if(#Remarks <> 'Select-One')
set #Where = #Where + 'and Remarks = '+ #Remarks
if(#Paymenttype <> 'Select-One')
set #Where = #Where + 'and PaymentType = ' + #Paymenttype
if(#BillID <> '')
set #Where = #Where + 'and BillID = '+ #BillID
Declare #SelectString as nvarchar(1000)
set #SelectString = 'SELECT MasterID,BillID, MenifestDate, FarwardingNo,ReceverCountryName,Status,Remarks,PaymentType
FROM tblMenifest
WHERE ' + #Where
exec #SelectString
When I execute it I got this error
The name 'SELECT MasterID,BillID, MenifestDate, FarwardingNo,ReceverCountryName,Status,Remarks,PaymentType FROM tblMenifest WHERE ( MenifestDate BETWEEN '04/01/2015' and '04/02/2015' )' is not a valid identifier
The MenifestDate column datatype is datetime.
I believe that you want to put EXEC(#SelectString) rather than exec #SelectString.

How to from query escaping comma and other special character in SQL Server stored procedure

I have a function which returns the comma separate values, but when I use
COALESCE(#Jiraids + ', ', '')
I get an error.
ALTER FUNCTION [dbo].[getCommonJiraIds](
#selct varchar(100),
#whereClause varchar(100),
#id varchar(100),
#TEST_RESULT_INFO_ID varchar(20) )
RETURNS varchar(max)
AS
BEGIN
DECLARE #Jiraids VARCHAR(8000)
DECLARE #sql varchar(max)
SET #whereClause = 'dbo.SNSTestResults.JIRA_ID <> '' AND dbo.SNSTestResults.'+#whereClause+ ''+ QUOTENAME(#id,'''') + 'AND dbo.SNSTestResults.Test_result_info_ID_FK LIKE '+QUOTENAME(#TEST_RESULT_INFO_ID,'''')
SET #sql = 'Select #Jiraids = COALESCE(#Jiraids + '', '', '') + case when (#selct LIKE Jira_ID_Maped) then Jira_ID_Maped else Jira_ID end
FROM dbo.TestCaseList INNER JOIN dbo.SNSTestResults ON dbo.TestCaseList.TestCaseListID = dbo.SNSTestResults.TestCaseListID_FK'
set #sql = #sql + #WhereClause
EXEC #sql
RETURN ( select #Jiraids);
END
When I execute the above function I got this error:
Msg 203, Level 16, State 2, Procedure GetDailyCrJiraTable, Line 159
The name 'Select #Jiraids =COALESCE(#Jiraids + ', ', ') + case when (#selct LIKE Jira_ID_Maped) then Jira_ID_Maped else Jira_ID end FROM dbo.TestCaseList INNER JOIN dbo.SNSTestResults ON dbo.TestCaseList.TestCaseListID = dbo.SNSTestResults.TestCaseListID_FKdbo.SNSTestResults.JIRA_ID <> ' AND dbo.SNSTestResults.Jira_ID_Maped'UIBUG-4533'AND dbo.SNSTestResu' is not a valid identifier.
Somebody please help me to fix this issue.
SET #whereClause = 'dbo.SNSTestResults.JIRA_ID <> '''' AND dbo.SNSTestResults.'+#whereClause+ ''+ QUOTENAME(#id,'''') + 'AND dbo.SNSTestResults.Test_result_info_ID_FK LIKE '+QUOTENAME(#TEST_RESULT_INFO_ID,'''')
you need more ' after dbo.SNSTestResults.JIRA_ID <>
You have to add more ' to your COALESCE function as below
Select #Jiraids = COALESCE(#Jiraids + '', '', '''')
and as I said in comment you have to change this dbo.SNSTestResults.JIRA_ID <> ''
to dbo.SNSTestResults.JIRA_ID <> '''' AND
ALTER FUNCTION [dbo].[getCommonJiraIds](
#selct varchar(100),
#whereClause varchar(100),
#id varchar(100),
#TEST_RESULT_INFO_ID varchar(20) )
-- your four inputs
RETURNS varchar(max)
AS
BEGIN
DECLARE #Jiraids VARCHAR(8000)
DECLARE #sql varchar(max)
SET #whereClause = 'dbo.SNSTestResults.JIRA_ID <> ''
AND dbo.SNSTestResults.'+#whereClause+ ''+ QUOTENAME(#id,'''')
+ 'AND dbo.SNSTestResults.Test_result_info_ID_FK LIKE '+QUOTENAME(#TEST_RESULT_INFO_ID,'''')
you do not know it yet, but your Query does not actually have a WHERE clause written in.
I hope you are not actually expecting the programmer to write extra
code in your function everytime it is used.
SET #sql = 'Select #Jiraids = COALESCE(#Jiraids + '', '', '') + case when (#selct LIKE Jira_ID_Maped) then Jira_ID_Maped else Jira_ID end
FROM dbo.TestCaseList INNER JOIN dbo.SNSTestResults ON dbo.TestCaseList.TestCaseListID = dbo.SNSTestResults.TestCaseListID_FK
Your #selct has not been correctly identified. SQL SERVER cannot know
at compile time that it is a #variable.
Also, are you sure your function will only return one row? In some cases, being explicit about the expected occurrence (should someone actually use a '%' in their PREDICATE) can prevent a future breakdown in the code.
set #sql = #sql + #WhereClause
EXEC #sql
Thankfully, SO exists to help people out. :D
A correct version could be like the following:
ALTER FUNCTION [dbo].[getCommonJiraIds](
#selct varchar(100),
#whereClause varchar(100),
#id varchar(100),
#TEST_RESULT_INFO_ID varchar(20) )
-- your four inputs
RETURNS varchar(max)
AS
BEGIN
DECLARE #Jiraids VARCHAR(8000)
DECLARE #sql varchar(max)
SET #sql = '
Select #Jiraids = TOP 1 COALESCE(#Jiraids + '', '', '') + CASE WHEN (' + #selct + ' = Jira_ID_Maped)
THEN Jira_ID_Maped
ELSE Jira_ID END
FROM dbo.TestCaseList
INNER JOIN dbo.SNSTestResults ON dbo.TestCaseList.TestCaseListID = dbo.SNSTestResults.TestCaseListID_FK'
SET #whereClause = 'WHERE dbo.SNSTestResults.JIRA_ID <> ''
AND dbo.SNSTestResults.'+#whereClause+ ''+ QUOTENAME(#id,'''')
+ 'AND dbo.SNSTestResults.Test_result_info_ID_FK LIKE '+QUOTENAME(#TEST_RESULT_INFO_ID, '')
set #sql = #sql + #WhereClause
EXEC #sql
RETURN ( select #Jiraids);
END

Best practise custom paging SQL server 2005

I'm got trouble with paging on SQL server 2005 which run query 2 times (get data and total rows). My demo proc below which base on Northwind database. Please help me to how to get total rows without query again.
CREATE PROCEDURE [dbo].[SearchEmployees]
#search nvarchar(4000)
,#orderBy varchar(200)
,#PageSize int
,#PageIndex int
,#TotalRowsNumber int output
AS
DECLARE #PageLowerBound int
DECLARE #PageUpperBound int
SET #PageLowerBound = #PageSize * #PageIndex
SET #PageUpperBound = #PageSize + #PageLowerBound
--Default order by to first column
IF (#OrderBy is null or LEN(#OrderBy) < 1)
BEGIN
SET #OrderBy = 'EmployeeID DESC'
END
-- SQL Server 2005 Paging
declare #SQL as nvarchar(4000)
declare #SQLCOUNT as nvarchar(4000)
declare #Param as nvarchar(500)
SET #SQL = 'WITH PageIndex AS ('
SET #SQL = #SQL + ' SELECT '
IF #PageSize > 0
BEGIN
SET #SQL = #SQL + ' TOP ' + convert(nvarchar, #PageUpperBound)
END
SET #SQL = #SQL + ' ROW_NUMBER() OVER (ORDER BY ' + #OrderBy + ') as RowIndex '
SET #SQL = #SQL + ' ,EmployeeID'
SET #SQL = #SQL + ', LastName'
SET #SQL = #SQL + ', FirstName'
SET #SQL = #SQL + ', Title'
SET #SQL = #SQL + ' FROM employees'
IF Len(#Search) > 0
BEGIN
SET #SQL = #SQL + ' ' + #Search
END
SET #SQL = #SQL + ') SELECT '
SET #SQL = #SQL + ' EmployeeID'
SET #SQL = #SQL + ', LastName'
SET #SQL = #SQL + ', FirstName'
SET #SQL = #SQL + ', Title'
SET #SQL = #SQL + ' FROM PageIndex '
SET #SQL = #SQL + ' WHERE RowIndex > ' + convert(nvarchar, #PageLowerBound)
IF #PageSize > 0
BEGIN
SET #SQL = #SQL + ' AND RowIndex <= ' + convert(nvarchar, #PageUpperBound)
END
--Get Row Count
SET #SQLCOUNT = 'SELECT #TotalRowsNumber = count(EmployeeID)
FROM employees'
SET #Param = N'#Search nvarchar(2000),#TotalRowsNumber INT OUTPUT'
IF LEN(#Search) > 0
BEGIN
SET #SQLCOUNT = #SQLCOUNT + #Search
END
exec sp_executesql #SQL
exec sp_executesql #SQLCOUNT, #Param,#Search=#Search,#TotalRowsNumber = #TotalRowsNumber OUT
Thanks in advance!
Try Like this, See it as an example
CREATE Procedure usp_GetBookings
#pageIndex int,
#pageSize tinyint
as
;with CTE as
(
Select Distinct ROW_NUMBER() over( order by ssi.SSItineraryID desc) as seq ,Count(*) over() as TotalRow,ssi.SSItineraryID
from SightSeeingItinerary as ssi
)
select * from CTE
where cte.seq between (#pageIndex-1) * #pageSize+1 and ((#pageIndex-1) * #pageSize +(#pageSize))

SQL Server stored procedure

I want it to count then if #intcount > 0 it should show data or else no data found, but when I execute it gives me 'no data found' regardless, what am I doing wrong?
#FiscalYear int,
#SchoolID int,
#Status int
AS
BEGIN
SET NOCOUNT ON;
declare #sqlstr varchar(2000)
declare #intCount int
set #intCount = 0
set #sqlstr = 'Select #intCount = Count(*)
From PrivateSchool left outer join Attachment on Attachment.PrivateSchoolID = PrivateSchool.PrivateSchoolID
inner join FiscalYearPrivateSchool fp ON fp.PrivateSchoolID = PrivateSchool.PrivateSchoolID
Where (FiscalYear = '+convert(varchar, #FiscalYear)+') AND (PrivateSchool.IsActive = 1)'
IF (#SchoolID != -1)
SET #sqlstr = #sqlstr + ' AND SchoolID ='+ convert(varchar, #SchoolID)
IF (#Status = -1)
SET #sqlstr = #sqlstr + ' AND PrivateSchool.PrivateSchoolID = PrivateSchool.PrivateSchoolID'
Else IF (#Status = 1)
SET #sqlstr = #sqlstr + ' AND Attachment.PrivateSchoolID = PrivateSchool.PrivateSchoolID'
Else
SET #sqlstr = #sqlstr + ' AND Attachment.PrivateSchoolID is Null'
If (#intCount > 0)
BEGIN
set #sqlstr= 'Select SchoolName as School,
(Case when Attachment.PrivateSchoolID = PrivateSchool.PrivateSchoolID THEN ''Uploaded''
ELSE ''Not Uploaded'' END) AS Status,
COUNT(Attachment.PrivateSchoolID) AS [Count]
From PrivateSchool left outer join Attachment on Attachment.PrivateSchoolID = PrivateSchool.PrivateSchoolID
inner join FiscalYearPrivateSchool fp ON fp.PrivateSchoolID = PrivateSchool.PrivateSchoolID
Where (FiscalYear = '+convert(varchar, #FiscalYear)+') AND (PrivateSchool.IsActive = 1)'
IF (#SchoolID != -1)
SET #sqlstr = #sqlstr + ' AND SchoolID ='+ convert(varchar, #SchoolID)
IF (#Status = -1)
SET #sqlstr = #sqlstr + ' AND PrivateSchool.PrivateSchoolID = PrivateSchool.PrivateSchoolID'
Else IF (#Status = 1)
SET #sqlstr = #sqlstr + ' AND Attachment.PrivateSchoolID = PrivateSchool.PrivateSchoolID'
Else
SET #sqlstr = #sqlstr + ' AND Attachment.PrivateSchoolID is Null'
SET #sqlstr = #sqlstr + ' Group by SchoolName, Attachment.PrivateSchoolID, PrivateSchool.PrivateSchoolID'
SET #sqlstr = #sqlstr + ' Order By SchoolName'
EXEC(#sqlstr)
END
ELSE
Select 'No Data Found' as 'FileUpload'
END
You need:
EXEC sp_executesql #sqlstr, N'#intCount INT OUTPUT', #intCount = #intCount OUTPUT;
IF (#intCount > 0)
BEGIN
....
END
You'll also need to make #sqlstr NVARCHAR(2000) and add set it to N'SELECT ...' as opposed to 'SELECT ...' - that leading N can be important.
The problem is:
declare #intCount int
set #intCount = 0
...
<a bunch of code where #intcount doesn't change>
If (#intCount > 0)
It's always going to be 0.
Your issue is one of scope. The EXEC(#sqlstr) command doesn't have access to the #intcount variable in your stored procedure. I would bet if you ran this code in a query window, it would tell you to declare #intcount.
Listen to YUCK and rewrite this to avoid dynamic SQL, and then your SELECT will be able to set the #intcount variable.