T-SQL Querying a table using a variable - sql

I have been tasked with updating a stored procedure and I'm trying to figure out the most efficient way of performing the select. Here is the current code, vaultID and clientID are input parameters:
SELECT
#siteID = Site.siteID,
#siteGroupID = Site.siteGroupID,
#customerID = Customer.customerID
FROM
Customer
INNER JOIN
Site ON Customer.siteID = Site.siteID
WHERE
Site.phoneNumberIVR = #vaultID
AND Site.production = 1
AND Customer.clientID = #clientID
The update I'm working on has to do with the #clientID variable. If a record has a specific #siteGroupID, the clientID needs to be passed in as it was received. If the record has a different type of #siteGroupID, the #clientID variable needs to be appended with a specific prefix. That prefix is also going to be stored on the site table.
I realize I can make a call to the site table initially to get the prefix, and then modify the #clientID variable, but I'm trying to figure out if there is a way to do this with just one call. I've been trying different case statements but I'm not sure this is even feasible.

If I understand your issue correctly, then you should be able to throw a CASE in your SELECT with your condition to do the appending:
SELECT
#siteID = Site.siteID,
#siteGroupID = Site.siteGroupID,
#customerID = Customer.customerID,
#clientID =
CASE
WHEN Site.siteGroupID = 1234 THEN Site.Prefix + #clientID
ELSE #clientID
END
FROM
Customer
inner join Site on Customer.siteID = Site.siteID
WHERE
Site.phoneNumberIVR = #vaultID
and Site.production = 1
and Customer.clientID = #clientID
Of course, depending on the datatypes of #clientID and Site.Prefix, you might have to do something other than a simple + to do the appending. For example if both were integer datatypes, you can append then with some CONVERT calls:
#clientID = CONVERT(integer, CONVERT(varchar, Site.Prefix) + CONVERT(varchar, #clientID))

Related

Using Case When to Determine whether to update values or select values

Edit: The below question was framed incorrectly by attempting to utilize the CASE WHEN expression in place of an IF statement. Please see the answer provided by schmiel. Hopefully this helps others.
I'm making a tool/report in Report Builder. The main logic is dictated by a parameter that is manually selected with a dropdown called CheckOrUpdate.
What I'm trying to accomplish is if the CheckOrUpdate parameter is set to CHECK I want the report to run a simple Query. If set to UPDATE I want the report to run an update statement.
Here is the Query:
DECLARE #SITE AS NVARCHAR(30)
DECLARE #Password AS NVARCHAR (30)
DECLARE #CheckOrUpdate AS NVARCHAR(30)
--SET #Password = 'Resend'
--SET #SITE = 'SRVCS'
--SET #CASE = '123456'
--SET #CheckOrUpdate = 'CHECK'
SELECT
CASE
WHEN #CheckOrUpdate = 'CHECK' --Just check to verify that records have been updated
THEN
(SELECT
order_num
,is_extracted
,interface_batch
,trans.item_num
,item.desc_1
,item.desc_2
FROM trans
INNER JOIN item on item.item_num=trans.item_num
WHERE order_num=#CASE AND site_code = #SITE AND is_extracted = 1 AND #Password='Resend')
WHEN #CheckOrUpdate = 'UPDATE' --Run the update
THEN
(UPDATE trans
SET is_extracted = 0 , interface_batch = NULL
WHERE order_num=#CASE AND site_code = #SITE AND is_extracted = 1 AND #Password='Resend')
--ELSE NOTHING
END
I understand that the syntax should go SET > Select > CASE WHEN. Just trying to understand how to go about running a query or running an update.
There is only one dataset in the report I'm making and the dataset is using the query above.
The commented out portion is where I was testing the logic in SQL Server.
Any ideas or references someone can point me too? Should I create another dataset and split the two? I couldn't find much in the way of what I'm looking to do.
Background: Application didn't interface info for this record due to interface outage or error and queueing stuff to be resent. Now this is being done manually just creating a tool to speed the process up for end users.
As suggested in the comments by Dan Guzman and droebi you should use a if statement like:
if #CheckOrUpdate = 'CHECK' --Just check to verify that records have been updated
begin
(SELECT
order_num
,is_extracted
,interface_batch
,trans.item_num
,item.desc_1
,item.desc_2
FROM trans t
INNER JOIN item i
on i.item_num=t.item_num
WHERE order_num=#CASE
AND site_code = #SITE
AND is_extracted = 1
AND #Password='Resend')
end
else if #CheckOrUpdate = 'UPDATE'
begin
(UPDATE trans
SET is_extracted = 0 , interface_batch = NULL
WHERE order_num=#CASE AND site_code = #SITE AND is_extracted = 1 AND #Password='Resend')
end
Or you can use else instead of else if if you only have two options.
And maybe you don't need the begin and end statement but that's the way I'm writing if statements :)

SQL Server : Optional Parameter Behavior Logic

I am implementing a stored procedure in SQL Server 2014, with two parameters: #CLIENTID and #CONTRACTID. One of the parameters is optional, so, when the stored procedure receives only the Client ID, it should return all the information related to that client, and when it receives both Client ID and Contract ID, it should return only the information related to that particular contract, from that particular client.
Here's some example code...
CREATE PROCEDURE SP_EXAMPLE_STACKOVERFLOW
#CLIENTID INT,
#CONTRACTID INT = NULL
AS
SELECT
*
FROM
Table T
WHERE
T.CLIENTID = #CLIENTID
AND (T.CONTRACTID = #CONTRACTID OR ISNULL(#CONTRACTID, 0) = 0)
The code above works, however my first attempt was to make the last line like this:
AND T.CONTRACTID = ISNULL(#CONTRACTID, T.CONTRACTID)
However this didn't work... It basically considered this last line to be evaluated to FALSE all the time.
I can't figure out why... And I'd appreciate some help
I think you want:
SELECT T.*
FROM Table T
WHERE T.CLIENTID = #CLIENTID AND
(#CONTRACTID IS NULL OR T.CONTRACTID = #CONTRACTID)
This will return all contract for a client if #CONTRACTID is NULL. It will return only the specified contract, if it is not NULL.
The fact that this doesn't work as expected:
T.CONTRACTID = ISNULL(#CONTRACTID, T.CONTRACTID)
suggests that T.CONTRACTID can be NULL. That is the only value that would not be equal to itself.

Send an email with trigger, when I got the email the values were wrong

My question is same as in question heading and below is the code what I have tried.
ALTER TRIGGER [dbo].[Entrega_Insert]
ON [dbo].[Entrega]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #DataEntrega DATETIME, #IdEncomenda INT, #QTDEncomenda INT
DECLARE #IdVisita INT
SELECT #DataEntrega = DataEntrega, #IdEncomenda = b.IdEncomenda
FROM [dbo].[Entrega] AS a
INNER JOIN [dbo].[Encomenda] AS b ON a.[IdEncomenda] = b.[IdEncomenda]
INNER JOIN [dbo].[Visita] AS c ON b.[IdVisita] = c.[IdVisita]
--INNER JOIN
DECLARE #BigBody VARCHAR(500) = CAST(#DataEntrega AS VARCHAR(100)) + ' ' + CAST(#IdEncomenda AS VARCHAR(100))
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Dc'
,#recipients = 'danny17kx#gmail.com'
,#subject = 'A sua encomenda foi processada e aceite.'
,#body = #BigBody
,#importance ='HIGH'
,#body_format='HTML'
END
I would strongly discourage your from attempting to send email through a trigger. Just the fact that you don't even know to use inserted suggests that you are not familiar enough with how SQL works. You are going to be locking the table (or part of it) while the email is attempted.
What can you do? The simplest is to write a stored procedure to send email and do the insert at the same time. This gives you more control over email failures.
The more "professional" solution would probably involve message queues. You would do the insert, then insert a message into a queue. At the other end, a listener would send the email and handle any issues with email failures.
You got the wrong values because your query is targeting the main table without any filtering, so you'll get a random values from the table.
You should use inserted table instead, which will store the last inserted values.
so your query should be like this :
SELECT TOP 1 #DataEntrega = DataEntrega, #IdEncomenda=b.IdEncomenda
FROM inserted AS a
INNER JOIN [dbo].[Encomenda] AS b ON a.[IdEncomenda]= b.[IdEncomenda]
INNER JOIN [dbo].[Visita] AS c ON b.[IdVisita] = c.[IdVisita]
Not sure if the INNER JOINs are useful here, but if IdEncomenda is already defined in Entrega table, then I think you'll be better off these joins.
Remember your method will only get one row, so if you insert multiple rows, you won't get all of them via email. So, you'll need to use other methods such as XML, COALESCE, or STUFF to concrete the results into #BigBody.

Assigne a string to a variable in a case statement in the THEN clause

Here's what I have. I have tried quotes instead of =, I have removed the variable and tried just the select statement wrapped in quotes. Loosing my mind trying to figure this out.
Yes, it is homework, I'm not asking for you to write it for me, just let me know why I can't seem to get it to work and what I'm doing wrong.
The Case is about 7 Whens long, But I can't get passed the first one.
Please HELP.
I know people don't like doing homework, so think of this as teaching me instead. Thank you,
CREATE PROC usr_spChooseReport(#ReportNum int)
AS
declare #sqlString nvarchar(500)
SELECT CASE(#ReportNum)
WHEN 1 THEN #sqlString =''select book.Title, Book_Copies.No_of_Copies, Library_Branch.BranchName from Book inner join Book_Copies on book.BookID=Book_Copies.BookID inner join Library_Branch on Book_Copies.BranchID=Library_Branch.BranchID where ONVERT(NVARCHAR(MAX),Library_Branch.BranchName) = 'Sharptown'
and CONVERT(NVARCHAR(MAX), Book.Title) ='The Lost Tribe'''
ELSE 'Unknown'
END
But if I try this,
CREATE PROC usr_spChooseReport(#ReportNum int)
AS
SELECT CASE(#ReportNum)
WHEN 1 THEN (select book.Title, Book_Copies.No_of_Copies, Library_Branch.BranchName from Book inner join Book_Copies on book.BookID=Book_Copies.BookID inner join Library_Branch on Book_Copies.BranchID=Library_Branch.BranchID where CONVERT(NVARCHAR(MAX),Library_Branch.BranchName) = 'Sharptown'
and CONVERT(NVARCHAR(MAX), Book.Title) ='The Lost Tribe')
ELSE 'Unknown'
END
I get this error:
Only one expression can be specified in the select list when the
subquery is not introduced with EXISTS.
After reading your question a second time I think I understand. They want you to use a case statement to set a variable #sqlString to a string which is the select statement. Then at some point they will EXEC (#sqlString)
You need to follow your first example for the remaining cases.
WHEN 2 THEN #sqlString = 'SELECT * FROM Somewhere'
WHEN 3 THEN #sqlString = 'SELECT * FROM SomewhereElse'
The difference between your first example and the second is that in the first they are assigning a string value to a variable #sqlString. In your second example you are running a query that returns multiple expressions. Two totally different things.
First off, this is a funky problem. If you follow this pattern, will you have a completely different query for each of the 7 numbers?
I would hope it's all the same query with simply different parameters passed. Then I would just create a lookup table like this:
DECLARE #LookUpTable TABLE (ID INT PRIMARY KEY, LibraryBranch VARCHAR(25), Book_Name VARCHAR(25))
INSERT INTO #LookUpTable
VALUES (1,'Sharptown','The Lost Tribe'),
(2,'Other Branch','Other book');
DECLARE #ReportNum INT = 1;
select book.Title, Book_Copies.No_of_Copies, Library_Branch.BranchName
FROM Book
inner join Book_Copies
on book.BookID=Book_Copies.BookID
inner join Library_Branch
on Book_Copies.BranchID=Library_Branch.BranchID
inner join #LookUpTable LT
on Library_Branch.BranchName = LT.LibraryBranch
AND Book.Title = LT.Book_Name
WHERE LT.ID = #ReportNum
BUT if you actually do have different queries for each case, then either try Jchao's method and EXEC(#sqlString) at the end OR you could use if statements. Note: ELSE IF means it will run only one of the queries so once it finds a match it will run that one query and then be done, but if NO match is found then the ELSE at the end will run
DECLARE #ReportNum INT = 1;
IF (#ReportNum = 1)
BEGIN
SELECT 1 --query 1
END
ELSE IF (#ReportNum = 2)
BEGIN
SELECT 2 --query 2
END
--etc to 7
ELSE
BEGIN
SELECT 'Unknown' --query 8 for unknown
END

SQL Server 2000 stored procedure branching with parameters

I want to create a stored procedure. If the parameter is -1 then there should not be a where clause on that column else there should be a WHERE clause. What's the best way to do it without a lot of IF branching?
I checked the archive. There are a few similar questions but not exactly the same.
CREATE PROCEDURE report
(
#site int,
#promo int,
#type int
)
AS
SET NOCOUNT ON
-- I want to avoid this:
IF #site = -1 AND #promo = -1 and #type = -1
BEGIN
SELECT * from table
END
IF #site > -1 AND #promo = -1 and #type = -1
BEGIN
SELECT * from table WHERE site = #site;
END
... -- other cases
ELSE -- all parameters are > -1
BEGIN
SELECT * from table
WHERE site = #site AND promo = #promo AND type = #type
END
This works in many cases, (despite what the comments will say without trying it) because the optimiser will ignore the ISNULL bit. Only works for non-null columns
SELECT #site = NULLIF(#site, -1) ...
SELECT * from table
WHERE site = ISNULL(#site, site) ..
Otherwise, conditional WHERE which is usually bad because OR can not be optimised
SELECT * from table
WHERE (#site = -1 OR site = #site) AND (...
Or separate stored procedures (don't think you want that either)
Or use sp_executesql (avoids dynamic SQL)
How about:
SELECT * FROM table WHERE
((site = #site) OR (#site = -1)) AND
((promo = #promo) OR (#promo = -1)) AND
((type = #type) OR (#type = -1))
One caveat, though, you may find that SQL is not very intelligent in optimizing this sort of query.
why fight against the obvious, simplest solution?
seriously, the branching solution make the intent clear, and can easily be understood by others.