Passing dynamic Variable IN WHERE statement IN SQL - sql

I have a WHERE statement where a DateOfService must be bookended between date ranges that could change. Because of this, I build an IF statement to trap the conditions and build the BETWEEN part of the statement.
Here is a Sample:
IF ISNULL(#TargetStartDate, 'N') = 'N'
BEGIN
SET #SubWhere = ' ad.EnrolledDate AND s.DateOfService'
END ELSE BEGIN
SET #SubWhere = ' #targetStartDate AND #TargetEndDate'
END
When I incorporate into WHERE clause there is no visible error. The error appears on the execution of the ALTER PROC
Here is the snippet from the WHERE clause:
AND s.DateOfService BETWEEN CAST(#SubWhere AS VARCHAR(150))
Any insight as to how to get this to work error free are much appreciated!

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 :)

Query with variable assignment not returning results

I have the below query that uses variables, however I want to be able to run this and have results shown from the Select statement. All I am getting is a Message "Commands completed Successfully" instead. I have tried tinkering with the advanced Query Options with checking the 'SET NOTEXEC' option but this did not yield results.
DECLARE #ErrorCount AS INTEGER;
DECLARE #MinErrorDateTime AS DATETIME;
SELECT #ErrorCount = COUNT(IBTRANSACTIONID)
,#MinErrorDateTime = MIN(ERRORTIMESTAMP)
FROM PSIBERR
WHERE MESSAGE_NBR <> 0
AND ERRORTIMESTAMP >= DATEADD(mi,-62,GETDATE())
This should work for you.
You need to do an additional select statement. After your query add this. Also, if this were a stored procedure you could add the variables as Output variables to return the values.
Select #ErrorCount as ErrorCount, #MinErrorDateTime as MinErrorDateTime

IF EXISTS command appears to be executing, even when condition doesn't exist?

I have the following SQL statement within a large update script:
...
PRINT N'Updating Table_01, Applying TypeReassignment from YesNoField_01 data'
IF EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'[dbo].[Table_01]')
AND name = 'YesNoField_01')
BEGIN
UPDATE Table_01 SET TypeReassignment = CASE YesNoField_01 WHEN 'Y' THEN 2 ELSE 1 END
WHERE TypeReassignment = 0
END
...
//script continues with other modifications. Towards the end of my script
//the YesNoField_01 field is dropped from the table.
The intent of the IF statement is to execute an UPDATE on a specific column only if another field exists on the table. As my comment at the end suggests, I am removing this original column (YesNoField_01) towards the end of my script.
The purpose of the IF check is so the script can be executed multiple times, even if it has been executed once before. If part of this script has been executed, it needs to skip over completed steps and continue execution without any errors. In this case, I need to skip over a data update.
However, if I execute my script on a database that has already had this script executed once before, I am getting the following error.
Invalid column name 'YesNoField_01'
When I navigate to the failing statement, it appears that the script is attempting to execute the UPDATE command within the IF block. When you independently execute the SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'[dbo].[Table_01]') AND name = 'YesNoField_01' statement, you see that nothing is returned because the field YesNoField_01 has already been removed from the table.
I'm confused. If my SELECT statement does not result in an existing record, why am I getting an execution error from within the IF block? Or, a better question, why is it even trying to execute my IF block when the IF conditional should evaluate to false?
Perhaps you could alter the test to check for the column's existence indirectly, thus:
DECLARE #YN_FieldName sysname =
(
SELECT Name
FROM sys.columns
WHERE object_id = OBJECT_ID(N'[dbo].[Table_01]')
AND name = 'YesNoField_01'
)
IF #YN_FieldName IS NOT NULL
BEGIN
UPDATE
Table_01
SET TypeReassignment =
CASE YesNoField_01
WHEN 'Y' THEN 2
ELSE 1
END
WHERE
TypeReassignment = 0
END
I suspect, though, that dynamic SQL will be required.

t sql "select case" vs "if ... else" and explaination about "begin"

I have few experiences with t sql and I have to write a stored.
This is my stored:
USE myDatabase
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[myStored]
(
#myPar1 INT,
#myPar2 SMALLDATETIME
)
AS
BEGIN
SET NOCOUNT ON
IF EXISTS (
SELECT
1
FROM
myTable1
WHERE
myPar1 = #myPar1
AND myPar2 = #myPar2
)
BEGIN
DELETE FROM
myTable1
WHERE
myPar1 = #myPar1
AND myPar2 = #myPar2
END
ELSE
IF EXISTS (
SELECT
1
FROM
myTable2
WHERE
myPar2 = #myPar2
)
BEGIN
INSERT INTO
myTable1
(myField1, myField2, myField3, myField4)
VALUES
(#myPar1, #myPar2, '', 1)
END
ELSE
IF EXISTS (
SELECT
1
FROM
myTable3
WHERE
myPar2 = #myPar2
)
BEGIN
INSERT INTO
myTable1
(myField1, myField2, myField3, myField4)
VALUES
(#myPar1, #myPar2, '', 1)
END
END
And these are my questions:
1 - Are there macroscopic errors?
2 - Someone suggest to use "SELECT CASE" someone else to use "IF ... ELSE", what's the difference? And what is the best option for my stored?
3 - I'm not sure about the use of the "BEGIN ... END" statement, in particular in combination with "IF ... ELSE" statement. What does it mean? Is it necessary to put "BEGIN ... END" inside the "IF ... ELSE" statement? Also for executing a single instruction?
For a single IF Statement
IF (Some Condition) --<-- If condition is true control will get inside the
BEGIN -- BEGIN ..END Block and execute the Code inisde
/* Your Code Here*/
END
All the single IF statements will check the Conditions Independently.
ONE IF with ONE ELSE
IF (Some Condition) --<-- If condition is true control will get inside the
BEGIN -- BEGIN ..END Block and execute the Code inisde
/* Your Code Here*/ -- IF not true control will jump to Else block
END
ELSE --<-- You dont mention any condition here
BEGIN
/* Your Code Here*/
END
Only One block of code will execute IF true then 1st block Otherwsie ELSE block of code.
Multiple IFs and ELSE
IF (Some Condition) --<--1) If condition is true control will get inside the
BEGIN -- BEGIN ..END Block and execute the Code inisde
/* Your Code Here*/ -- IF not true control will check next ELSE IF Blocl
END
ELSE IF (Some Condition) --<--2) This Condition will be checked
BEGIN
/* Your Code Here*/
END
ELSE IF (Some Condition) --<--3) This Condition will be checked
BEGIN
/* Your Code Here*/
END
ELSE --<-- No condition is given here Executes if non of
BEGIN --the previous IFs were true just like a Default value
/* Your Code Here*/
END
Only the very 1st block of code will be executed WHERE IF Condition is true rest will be ignored.
BEGIN ..END Block
After any IF, ELSE IF or ELSE if you are Executing more then one Statement you MUST wrap them in a BEGIN..END block. not necessary if you are executing only one statement BUT it is a good practice to always use BEGIN END block makes easier to read your code.
Your Procedure
I have taken out ELSE statements to make every IF Statement check the given Conditions Independently now you have some Idea how to deal with IF and ELSEs so give it a go yourself as I dont know exactly what logic you are trying to apply here.
CREATE PROCEDURE [dbo].[myStored]
(
#myPar1 INT,
#myPar2 SMALLDATETIME
)
AS
BEGIN
SET NOCOUNT ON
IF EXISTS (SELECT 1 FROM myTable1 WHERE myPar1 = #myPar1
AND myPar2 = #myPar2)
BEGIN
DELETE FROM myTable1
WHERE myPar1 = #myPar1 AND myPar2 = #myPar2
END
IF EXISTS (SELECT 1 FROM myTable2 WHERE myPar2 = #myPar2)
BEGIN
INSERT INTO myTable1(myField1, myField2, myField3, myField4)
VALUES(#myPar1, #myPar2, '', 1)
END
IF EXISTS (SELECT 1 FROM myTable3 WHERE myPar2 = #myPar2)
BEGIN
INSERT INTO myTable1(myField1, myField2, myField3, myField4)
VALUES(#myPar1, #myPar2, '', 1)
END
END
I don't see any macroscopic error
IF ELSE statement are the one to use in your case as your insert or delete data depending on the result of your IF clause. The SELECT CASE expression is useful to get a result expression depending on data in your SELECT statement but not to apply an algorithm depending on data result.
See the BEGIN END statement like the curly brackets in code { code }. It is not mandatory to put the BEGIN END statement in T-SQL. In my opinion it's better to use it because it clearly shows where your algorithm starts and ends. Moreover, if someone has to work on your code in the future it'll be more understandable with BEGIN END and it'll be easier for him to see the logic behind your code.
There are no errors in this script.
Case statement is for expression evaluation and not for statement execution. Hence, cannot be used in this current requirement. For more details about case statement look at http://msdn.microsoft.com/en-us/library/ms181765.aspx
Usually, a statement can be single or a compound. Compound ones are a combination of statements. For an IF condition, one can specify a single or compound statement and SQL server chose to group it inside a BEGIN .. END (unlike few other databases/programming languages). This is same for ELSE. Hence, IF should be followed by BEGIN...END and ELSE should be followed by BEGIN...END. For more details please refer to http://msdn.microsoft.com/en-us/library/ms182717(v=sql.120).aspx

Nested if statements in SQL Server stored procedure SELECT statement

I'm new here, and relatively new to stored procedures, so please bear with me! I've checked related questions on here and can't find anything that works in this instance.
I am trying to build a stored procedure (MS SQL Server 2005) that takes a number of passed in values and in effect dynamically builds up the SQL as you would with inline SQL.
This is where I've come unstuck.
We have (somewhat simplified for clarity):
#searchf1 varchar(100), -- search filter 1
#searchr1 varchar(100), -- search result 1
#searchf2 varchar(100), -- search filter 2
#searchr2 varchar(100), -- search result 2
#direction char(1), -- direction to order results in
AS
set nocount on
set dateformat dmy
SELECT *
FROM database.dbo.table T
WHERE T.deleted = 'n'
ORDER BY CASE #direction
WHEN 'A' THEN T.id
WHEN 'D' THEN T.id DESC
END
END
set nocount off
I have also tried the lines from ORDER BY as:
IF #direction = 'N' THEN
ORDER BY
T.id
ELSE
ORDER BY
T.id DESC
Both approaches give me an error along the lines:
"Incorrect syntax near the keyword 'DESC'." (which references the line id DESC following the final ORDER BY
As part of this stored procedure I also want to try to feed in matched pairs of values which reference a field to look up and a field to match it to, these could either be present or ''. To do that I need to add into the SELECT section code similar to:
WHERE
deleted = 'n'
IF #searchf1 <> '' THEN
AND fieldf1 = #searchf1 AND fieldr1 = #searchr1
This however generates errors like:
Incorrect syntax near the keyword 'IF'.
I know dynamic SQL of this type isn't the most elegant. And I know that I could do it with glocal IF ELSE statements, but if I did the SP would be thousands of lines long; there are going to up to 15 pairs of these search fields, together with the direction and field to order that direction on.
(the current version of this SP uses a passed in list of IDs to return generated by some inline dynamic SQL, through doing this I'm trying to reduce it to one hit to generate the recordset)
Any help greatly appreciated. I've hugely simplified the code in the above example for clarity, since it's the general concept of a nested IF statement with SELECT and ORDER BY that I'm inquiring about.
For this I would try to go with a more formal Dynamic SQL solution, something like the following, given your defined input parameters
DECLARE #SQL VARCHAR(MAX)
SET #SQL = '
SELECT
FROM
database.dbo.table T
WHERE
T.deleted = ''n'' '
--Do your conditional stuff here
IF #searchf1 <> '' THEN
SET #SQL = #SQL + ' AND fieldf1 = ' + #searchf1 + ' AND fieldr1 = ' + #searchr1 + ''' '
--Finish the query
SET #SQL = #SQL + ' ORDER BY xxx'
EXEC(#SQL)
DISCLAIMER: The use of Dynamic SQL is NOT something that should be taken lightly, and proper consideration should be taken in ALL circumstances to ensure that you are not open to SQL injection attacks, however, for some dynamic search type operations it is one of the most elegant route.
Try it this way:
SELECT * FROM database.dbo.table T WHERE T.deleted = 'n'
ORDER BY
CASE WHEN #direction='A' THEN T.id END ASC,
CASE WHEN #direction='D' THEN T.id END DESC
Source Article:
http://blog.sqlauthority.com/2007/07/17/sql-server-case-statement-in-order-by-clause-order-by-using-variable/
Another option that you might have, depending on the data type of your field, if nulls are NOT allowed, would be to do something like this.
SELECT *
FROM database.dbo.table T
WHERE T.deleted = 'n'
AND fieldf1 = COALESCE(#searchf1, fieldf1)
AND fieldr1 = COALESCE(#searchr1, fieldr1)
--ETC
ORDER BY fieldf1
This way you are not using dynamic SQL and it is fairly readable, just have the variable be null when you are looking to omit the data.
NOTE: As I mentioned this route will NOT work if any of the COALESCE columns contain null values.