SQL Update command with various variables - sql

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)

Related

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.

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;

Multiple conditional Where clause

I currently have a query that will pull a bunch of information from my database based on whatever where condition that I want to use.
declare #CaseNum char(7),
#ImportId char,
#FormatId char,
#SessionId char(5)
set #CaseNum = '' --I can place the value that I want to search by in here
set #ImportId = ''
set #FormatId = ''
set #SessionId = ''
--------------------
query in here
--------------------
where
gr.[CaseNum] = #CaseNum --currently I have to comment the ones I'm not using out
--im.[ImportId] = #ImportId
--fr.[FormatId] = #FormatId
--se.[SessionId] = #SessionId
I want to be able to take the comment portion out and simply display all rows if the parameter = ''
For example if I use set #CaseNum = '1234567' then it will search by that parameter and if I use #FormatId = '12' it will search by that one.
I have tried using the following and a few other attempts but I am getting nowhere fast.
where
gr.[CaseNum] = '%' + #CaseNum + '%'
and im.[ImportId] = '%' + #ImportId + '%'
and fr.[FormatId] = '%' + #FormatId + '%'
and se.[SessionId] = '%' + #SessionId + '%'
With help from the link that #Norman posted I figured it out. I wanted to post my solution for others to see.
declare #CaseNum varchar(MAX),
#ImportId varchar(MAX)
set #CaseNum = ''
set #ImportId = ''
----------------------------------------------------------------------------
If(#CaseNum = '') --Sets the parameter to NULL for COALESCE to work
Begin
Select #CaseNum = NULL
End
If(#ImportId = '') --Sets the parameter to NULL for COALESCE to work
Begin
Select #ImportId = NULL
End
--------------------
query in here
--------------------
where
gr.[CaseNum] = COALESCE(#CaseNum, gr.[CaseNum])
and im.ImportId = COALESCE(#ImportId, im.ImportId)
This solution allows the query to use just a single parameter or all at the same time.
You might want to look into building your query.
DECLARE #Number varchar(10)
DECLARE #Where varchar(max)
DECLARE #Query varchar(max)
SET #Query = 'SELECT * FROM TestTable'
SET #Where = ''
SET #Number = '3'
IF ISNULL(#Number, '') != ''
BEGIN
SET #Where = #Where + 'and testNumber = ' + #Number
END
IF LEN(#Where) > 0
BEGIN
SET #Where = SUBSTRING(#Where, 4, LEN(#Where))
END
if ISNULL(#Where, '') != ''
BEGIN
SET #Query = #Query + ' WHERE ' + #Where
END
EXEC(#Query)
Check out this gentleman's article for reference: https://social.msdn.microsoft.com/forums/sqlserver/en-US/1ec6ddd9-754b-4d78-8d3a-2b4da90e85dc/dynamically-building-where-clauses

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.