How to add generic condition to sp select? - sql

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;

Related

Getting multi-part identifier "column name" could not be bound error in SQL Server of newer version

I have this code for my stored procedure:
create or alter procedure udpReservationFilter
#FName nvarchar(160),
#LName nvarchar(160),
#Category nvarchar(160),
#Number int,
#TotalCount int OUT,
#ColumnName nvarchar(100) = 'M.Id',
#SortDesc bit = 0,
#Page int = 1,
#PageSize int = 2
as
begin
declare #sqlWhere nvarchar(max) = ''
declare #whereParams nvarchar(1000) = N' #FName nvarchar(160),
#LName nvarchar(160),
#Category nvarchar(160),
#Number int, #OffsetRows int, #PageSize int'
declare #countParams nvarchar(1000) = N' #FName nvarchar(160),
#LName nvarchar(160),
#Category nvarchar(160),
#Number int,
#TotalCount int OUT'
if len(trim(#FName)) > 0
set #sqlWhere += ' AND c.FName like ''%'' + #FName + ''%'' '
if len(trim(#LName)) > 0
set #sqlWhere += ' AND c.LName like #LName '
if len(trim(#Category))> 0
set #sqlWhere += ' AND r.Category like #Category '
if (#Number > 0)
set #sqlWhere += ' AND r.Number = #Number '
---------------- counting total results -------------------
declare #sqlCount nvarchar(1000) = N' select #TotalCount = count(*) from Reservations M '
if len(#sqlWhere) > 0
set #sqlCount = #sqlCount + ' where ' + (SUBSTRING(#sqlWhere, 5 , 60))
exec sp_executesql #sqlCount,
#countParams,
#FName = #FName,
#LName = #LName,
#Category = #Category,
#Number = #Number,
#TotalCount = #TotalCount OUT
declare #sql nvarchar(max) = N' select M.*, c.*, r.Category, r.Number, r.Price, r.Status
from Reservations M, Client c, Rooms r
where M.ClientId=c.ID and M.RoomId=r.Id'
+ #sqlWhere
+ ' order by ' + #ColumnName
+ ' offset #OffsetRows rows fetch next #PageSize rows only'
--M.*, c.*, r.Number, r.category, r.Price, r.status
declare #Offset int = (#Page-1)*#PageSize
if #Offset < 0
set #Offset = 0
exec sp_executesql #sql,
#whereParams,
#FName = #FName,
#LName =#LName,
#Category = #Category,
#Number = #Number,
#OffsetRows = #Offset,
#PageSize = #PageSize
end
I'm getting this error:
The multi-part identifier "column_name" could not be bound.
when executing the query.
declare #cnt int
exec udpReservationFilter
#FName = null,
#LName = null,
#Category = null,
#Number = null,
#TotalCount = #cnt OUT,
#PageSize = 3
When I provide parameters it is above error and gives the matched result this error stops my asp.net core app and if there is no parameters provided its compiling without error
Here is more detailed error :
Msg 4104, Level 16, State 1, Line 5
The multi-part identifier "c.FName" could not be bound.
(1 row affected)

Error Pass from nested MSSQL procedure to parent procedure

I have one parent stored procedure and one nested stored procedure. Parent Stored procedure calls the nested stored procedure on loop. Now when there is certain condition matches I have raised the error. When this error is raised I want to stop all the process and return the error.
CREATE Proc [dbo].[Usp_GenSalarySheet](#SalData [HRM].UTDT_SalaryData ReadOnly)
AS
set nocount on
DECLARE #SMT NVARCHAR(MAX)
SET #SMT = 'Create Table ##SalarySheet (StaffID INT,FullName NVARCHAR(1024),PresentDays NVARCHAR(1024),Absent NVARCHAR(1024),Department NVARCHAR(1024),Designation NVARCHAR(1024),'
DECLARE #HopName nvarchar(max)
Declare HOPCursor cursor for select ID from HRM.tbl_HOP
OPEN HOPCursor
FETCH NEXT FROM HOPCursor INTO #HopName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SMT = #SMT + ' [' + #HopName + '] DECIMAL(19,7),'
FETCH NEXT FROM HOPCursor into #HopName
END
SET #SMT = #SMT + '[Total] DECIMAL(19,7))'
CLOSE HOPCursor
DEALLOCATE HOPCursor
print (#smt)
exec (#SMT)
select * into #temp from #SalData
Declare #TopID INT
While (Select Count(*) From #Temp) > 0
Begin
Select Top 1 #TopID = StaffID From #temp
Declare #StaffID INT =(select top 1 StaffID from #temp)
Declare #StaffName NVARCHAR(1024) = (SELECT TOP 1 FullName FROM #temp)
Declare #WorkingDays Int = (SELECT top 1 WorkingDays from #temp)
Declare #Leave INT = (SELECT top 1 [Absent] from #temp)
INSERT INTO ##SalarySheet(StaffID,FullName,[Absent]) values(#StaffID,#StaffName,#Leave)
DECLARE #HOPType INT
DECLARE #Value Decimal(19,7)
DECLARE #CalcVal DECIMAL(19,7) = 0
DECLARE #Formula NVARCHAR(MAX)
DECLARE #Total DECIMAL(19,7)
DECLARE #PayEvery INT
DECLARE #Round Int
Declare HOPList Cursor for SELECT ID,HOPType,Value,Formula,RoundOff,PayEvery FROM HRM.Tbl_HOP order by Schedule
open HOPList
FETCH NEXT FROM HOPList INTO #HopName,#HOPType,#Value,#Formula,#Round,#PayEvery
WHILE ##FETCH_STATUS = 0
BEGIN
if exists(select * from HRM.[Tbl_ContractHOPDetails] where PersonalDetailsID = #StaffID and HOPID = #HopName)
print('select * from HRM.[Tbl_ContractHOPDetails] where PersonalDetailsID = ' + convert(varchar(max), #StaffID) + ' and HOPID =' + convert(varchar(max),#HopName))
begin
if(#HOPType=51)
begin
exec HRM.Usp_GetSalaryValueFromFormula #StaffID,#Formula,#HOPType,#Leave,#WorkingDays,#Value output
set #HOPType= 50
end
if(#HOPType=50)
begin
set #CalcVal = #value
END
IF(#HOPType=38)
BEGIN
SET #CalcVal = #Value - ((#Value/#WorkingDays) * #Leave)
END
if(#PayEvery= 40)
begin
set #CalcVal = ((#CalcVal * #WorkingDays) - (#CalcVal * #Leave))
end
if(#Round = 45)
begin
set #CalcVal = round(#CalcVal,2)
end
else if(#Round = 46)
begin
set #CalcVal = CEILING(#CalcVal)
end
else if(#Round = 47)
begin
set #CalcVal = FLOOR(#CalcVal)
end
set #SMT ='UPDATE ##SalarySheet SET [' + #HopName + '] = ' + cast(#CalcVal as nvarchar(max)) + ' where StaffID = ' + cast(#StaffID as nvarchar(max))
exec (#smt)
end
SET #CalcVal = 0
FETCH NEXT FROM HOPList INTO #HopName,#HOPType,#Value,#Formula,#Round,#PayEvery
END
close HOPList
DEALLOCATE HOPList
set #SMT ='UPDATE ##SalarySheet SET [Total] = ' + cast(#Total as nvarchar(max)) + ' where StaffID = ' + cast(#StaffID as nvarchar(max))
exec (#smt)
Delete #temp Where StaffID = #TopID
end
select * from ##SalarySheet
drop table ##SalarySheet
This is my parent Stored Procudere and nested procedure is as follow:
CREATE proc [HRM].[Usp_GetSalaryValueFromFormula](#StaffID INT,#val nvarchar(max),#HOPType INT,#Leave INT,#WorkingDays INT, #GetResult Decimal(19,7) output)
as
set nocount on
Declare #Formula Varchar(max)
declare #initial INT =0
declare #final INT =0
Declare #DataVal NVARCHAR(MAX) -- set the value from HOP table
declare #FieldVal nvarchar(max)
declare #cnt int = 0
Declare #Complete Int =CHARINDEX ('[',#val,0)
while (#Complete <> 0)
begin
set #initial = CHARINDEX ('[',#val,0)
set #final = CHARINDEX(']',#val,0)
set #FieldVal = SUBSTRING(#val,#initial,(#final-#initial) + 1)
if len(#FieldVal)<>0
begin
select #HOPType = HOPType, #DataVal= ( case when HOPType = 51 then [Formula] else cast([Value] as nvarchar(max)) end) from HRM.Tbl_ContractHOPDetails where PersonalDetailsID = #StaffID and HOPID in(select ID from HRM.tbl_HOP where HOPName = replace(replace(#fieldVal,'[',''),']',''))
if (#DataVal is null or #DataVal ='')
begin
RAISERROR ('Nested HOP is not defined.',11,1)
RETURN
end
print(#DataVal)
if ISNUMERIC(#DataVal)=1
begin
if(#HOPType = 38)
begin
SET #DataVal = cast(#DataVal as decimal(19,7)) - ((cast(#DataVal as decimal(19,7))/#WorkingDays) * #Leave)
end
end
set #val = replace(#val,#fieldVal,#DataVal)
set #fieldVal= ''
set #DataVal = ''
end
set #Complete = CHARINDEX ('[',#val,0)
set #fieldVal =''
set #final =0
set #initial = 0
end
SET #Complete =CHARINDEX ('{',#val,0)
while (#Complete <> 0)
BEGIN
set #initial = CHARINDEX ('{',#val,0)
set #final = CHARINDEX('}',#val,0)
set #FieldVal = SUBSTRING(#val,#initial+1,(#final-#initial)-1)
if len(#FieldVal)<>0
begin
set #DataVal = isnumeric((SELECT 0 FROM [HRM].Tbl_StaffTag where CValue = #FieldVal and StaffID = #StaffID))
set #FieldVal = '{' + #FieldVal + '}'
set #val = replace(#val,#fieldVal,#DataVal)
set #fieldVal= ''
set #DataVal = ''
end
set #Complete = CHARINDEX ('{',#val,0)
set #final =0
set #initial = 0
END
DECLARE #RetrunVal DECIMAL(19,7)
declare #ParmDefinition Nvarchar(512) = '#GetVal decimal(19,7) OUTPUT'
Declare #SMT NVARCHAR(MAX) = ' SET #GetVal = ' + #val
EXECUTE sp_executeSQL #Smt, #ParmDefinition, #GetVal =#RetrunVal OUTPUT
set #GetResult = #RetrunVal
But in current situation it raises error and again from the main procedure it runs next step of loop. But I want to terminate the complete process after this raiserror
Kindly help me
My guess is that RaiseError throws the control back to the caller, which might make the Return statement unreachable. The caller (loop) continues with next iteration.

Using Variable as part of column name in Dynamic 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

How to split and replace with stored procedure?

I want to replace all e_Mail column where in #tablename with my users table (my main table).
For example:
#tablename
[name] [eMail] // columns
------------------------------------------------------
name surname blahblah#gmail.com
My users table
[name] [eMail]
----------------------------------------
name surname blahblah#hotmail.com
I want to update this row's eMail column as 'blahblah#hotmail.com' in #tablename.
What will procedure do?
1- Get first value of eMail column from #tablename
2- Split value (split char: #) and get first value (for example, if value blahblah#gmail.com, get gmail.com)
3- Search first value in users table
4- When the find value in users table, (Code must find blahblah#hotmail.com) Update eMail as blahblah#hotmail.com in #tablename
5- Get second value of eMail column from #tablename
.
.
.
So, I write a stored procedure. But this procedure is not working. Where is the problem?
Create Proc update_eMail
(#tablename nvarchar(50),
#columnname nvarchar(50))
AS
Begin
Declare #get_oldeMail nvarchar(100)
Declare #get_eMail nvarchar(100)
Declare #get_SplitValue nvarchar(100)
Declare #get_oldSplitValue nvarchar(100)
Declare #rowNumber int
Declare #users_rowNumber int
Declare #i int
Declare #j int
Declare #q_getRowNumber NVARCHAR(MAX)
Declare #q_getoldeMail NVARCHAR(MAX)
Declare #q_UpdateQuery NVARCHAR(MAX)
SET #q_getRowNumber = N'SELECT Count(ID)
FROM ' + QUOTENAME(#tablename)
EXECUTE #rowNumber = sp_executesql #q_getRowNumber
/*Set #rowNumber = (Select Count(ID) from #tablename)*/
Set #users_rowNumber = (Select Count(ID) from tblusers)
Set #i = 1
Set #j = 1
While(#i <= #rowNumber)
BEGIN
Set #q_getoldeMail = '(SELECT Lower(#columnname) FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY ID) AS rownumber
,ID
,[Name]
,[Description]
,[Status]
,[AssignedTo]
,[AssignedToMail]
,[CC]
FROM' + #tablename + '
) AS ar
WHERE rownumber = #i)'
EXECUTE #get_oldeMail = sp_executesql #q_getoldeMail
Set #get_oldeMail = REPLACE(#get_oldeMail,'ı','i')
WHILE LEN(#get_oldeMail) > 0
BEGIN
IF CHARINDEX('#',#get_oldeMail) > 0
SET #get_oldSplitValue = SUBSTRING(#get_oldeMail,0,CHARINDEX('#',#get_oldeMail))
ELSE
BEGIN
SET #get_oldSplitValue = #get_oldeMail
SET #get_oldeMail = ''
END
SET #get_oldeMail = REPLACE(#get_oldeMail,#get_oldSplitValue + '#' , '')
END
While(#j <= #users_rowNumber)
BEGIN
Set #get_eMail = (SELECT Replace(Lower(eMail),'ı','i') FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY ID) AS rownumber
,eMail
FROM tblusers) AS ar
WHERE rownumber = #j)
WHILE LEN(#get_eMail) > 0
BEGIN
IF CHARINDEX('#',#get_eMail) > 0
SET #get_SplitValue = SUBSTRING(#get_eMail,0,CHARINDEX('#',#get_eMail))
ELSE
BEGIN
SET #get_SplitValue = #get_eMail
SET #get_eMail = ''
END
SET #get_eMail = REPLACE(#get_eMail,#get_SplitValue + '#' , '')
END
if(#get_splitValue = #get_oldSplitValue)
begin
Set #q_UpdateQuery = 'Update ar Set ' + #columnname + ' = ' + #get_email + ' Where rownumber = ' +#i
EXECUTE sp_executesql #q_UpdateQuery
break
end
SET #j = #j+1
END
SET #i = #i+1
END
End
Thanks in advance.

SQL Update command with various variables

I have table like:
Items
ID(int)
Name(varchar)
Date(DateTime)
Value(int)
I would like to write SQL Command which will update only these values, which are not null
Pseudo code of what I would like to do:
UPDATE Items
SET
IF #NewName IS NOT NULL
{
Items.Name = #NewName
}
IF #NewDate IS NOT NULL
{
Items.Date = #NewDate
}
IF #newValue IS NOT NULL
{
Items.Valie = #NewValue
}
WHERE Items.ID = #ID
Is it possible to write query like this?
UPDATE Items
SET Name = ISNULL(#NewName,Name),
[Date] = ISNULL(#NewDate,[Date]),
Value = ISNULL(#NewValue,Value)
WHERE ID = #ID
You cannt use if statement in update you can use below query for update on condition
'UPDATE Items
SET
Items.Name = (case when #NewName is not null then #NewName else end) ,
Items.Date = (case when #NewDate is not null then #newDate else end ),
Items.Valie = (case when #Valie is not null then #Valie else end )
WHERE Items.ID = #ID'
You can make something like this:
declare #sql varchar(1000)
set #sql = 'UPDATE Items SET '
IF #NewName IS NOT NULL
#sql = #sql + 'Items.Name = ' + #NewName
IF #NewDate IS NOT NULL
#sql = #sql + 'Items.Date = ' + #NewDate
IF #newValue IS NOT NULL
#sql = #sql + 'Items.Valie = ' + #NewValue
#sql = #sql + 'WHERE Items.ID = ' + #ID
exec(#sql)