In a query with a where, I need to be able to still thorw all rows as a result.
For example:
declare #Crit nvarchar(15)
set #Crit = 'Package'; --as an example
IF #Crit = ''
¿¿??
SELECT * FROM Criterios
WHERE CRITERIO = #Crit
In this case, if I set the value of #Crit to 'Package', it works like a normal query, but if I do not set any value #Crit = '', and the query throws nothing.
What I am trying to do inside the if, is to expecify a value that equals to everything, sort of the * from selects.
Is there anyway to achieve this?
You're talking about a conditional WHERE clause, which can be achieved a number of ways.
One approach is:
SELECT *
FROM Criterios
WHERE (CRITERIO = #Crit OR #Crit = '')
Another way is to use dynamic SQL:
DECLARE #SQL NVARCHAR(1000)
SET #SQL = 'SELECT * FROM Criterios'
IF (#Crit <> '')
SET #SQL = #SQL + ' WHERE CRITERIO = #Crit'
EXECUTE sp_executesql #SQL, N'#Crit VARCHAR(10)', #Crit
There are pros and cons to each, depending on scenario. Dynamic SQL typically less readable, more complicated to write (and need to be careful about SQL injection) but can give you better execution plans especially in more complex scenarios, as you only end up with the exact conditions you need.
The typical way doing this is by not passing a value for your parameter.
SELECT * FROM Criterios
WHERE CRITERIO = #Crit
OR #Crit IS NULL
Be careful with this pattern though. You can create some serious performance problems. Here is a great article that goes into more detail about how to solve that issue.
http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/
If you are stuck using an empty string you can change the above slightly to.
SELECT * FROM Criterios
WHERE CRITERIO = #Crit
OR #Crit = ''
You can use a dynamic SQL to do this. If #crit is null then the where clause is excluded, if it is not null it will be in the where clause.
DECLARE #crit nvarchar(15) = 'Package'
,#sqlStatement nvarchar(max) =
'SELECT * FROM Criterios'
;
SET #sqlStatement = CONCAT(#sqlStatement,'WHERE CRITERIO = ' +#crit)
EXEC sp_executesql #sqlStatement;
Consider using the COALESCE function to return the first non-null value, as below
declare #Crit nvarchar(15)
set #Crit = 'Package'; --as an example
IF #Crit = ''
BEGIN
SET #Crit = NULL
END
SELECT * FROM Criterios
WHERE CRITERIO = COALESCE(#Crit, CRITERIO)
Related
I have a T-Sql script where part of this script checks to see if a certain column exists in the a table. If so, I want it to execute a routine... if not, I want it to bypass this routine. My code looks like this:
IF COL_LENGTH('Database_Name.dbo.Table_Name', 'Column_Name1') IS NOT NULL
BEGIN
UPDATE Table_Name
SET Column_Name2 = (SELECT Column_Name3 FROM Table_Name2
WHERE Column_Name4 = 'Some Value')
WHERE Column_Name5 IS NULL;
UPDATE Table_Name
SET Column_Name6 = Column_Name1
WHERE Column_Name6 IS NULL;
END
My problem is that even when COL_LENGTH of Column_Name1 is null (meaning it does not exist) I am still getting an error telling me "Invalid column name 'Column_Name1'" from the 2nd UPDATE statement in the IF statement. For some reason this IF condition is still being evaluated even when the condition is FALSE and I don't know why.
SQL Server parses the statement and validates it, ignoring any if conditionals. This is why the following also fails:
IF 1 = 1
BEGIN
CREATE TABLE #foo(id INT);
END
ELSE
BEGIN
CREATE TABLE #foo(id INT);
END
Whether you hit Execute or just Parse, this results in:
Msg 2714, Level 16, State 1
There is already an object named '#foo' in the database.
SQL Server doesn't know or care which branch of a conditional will be entered; it validates all of the statements in a batch anyway. You can do things like (due to deferred name resolution):
IF <something>
BEGIN
SELECT foo FROM dbo.Table_That_Does_Not_Exist;
END
But you can't do:
IF <something>
BEGIN
SELECT column_that_does_not_exist FROM dbo.Table_That_Does;
END
The workaround, typically, is to use dynamic SQL:
IF <something>
BEGIN
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SELECT column_that_does_not_exist FROM dbo.Table_That_Does;';
EXEC sp_executesql #sql;
END
Make your statement a string. And if column exists, execute it
IF COL_LENGTH('Database_Name.dbo.Table_Name', 'Column_Name1') IS NOT NULL
BEGIN
DECLARE #sql VARCHAR(MAX)
SET #sql = 'UPDATE Table_Name
SET Column_Name2 = (SELECT Column_Name3 FROM Table_Name2
WHERE Column_Name4 = ''Some Value'')
WHERE Column_Name5 IS NULL;
UPDATE Table_Name
SET Column_Name6 = Column_Name1
WHERE Column_Name6 IS NULL;'
EXEC(#sql)
END
I'm trying to use a select case in order to either use a where condition or not in a sql query. But it does not work and I can use some help how to solve this if possible
DECLARE #CategoryID Int
SET #CategoryID = 0
SELECT * FROM SomeTable
CASE WHEN #CategoryID = 0 THEN
ELSE
WHERE (dbo.SomeTable.ID = #CategoryID)
END
So if I pass 0 to the #CategoryID parameter I should not filter at all, otherwise I want to filter. Can this be done?
Rephrase your logic to remove the CASE expression:
SELECT *
FROM SomeTable
WHERE #CategoryID IN (0, ID);
This works, because when #CategoryID = 0, the WHERE clause is always true, otherwise it would be true when ID = #CategoryID.
Your current attempt is a common problem, stemming from not using a CASE expression as it is intended. The predicate of a CASE expression (i.e. what follows the logic after THEN and ELSE) has to be a literal value, not another logical expression. In this case, we don't even need CASE.
Your syntax is wrong... You have to rearrange your where clause:
DECLARE #CategoryID Int = 0;
SELECT * FROM SomeTable
WHERE #CategoryID = 0 OR #CategoryID = ID
If variable is set to 0, then where clause is always true, otherwise, its value depends on condition #CategoryID = ID
This is possible, first is to build your query based on your case condition
DECLARE #CategoryID INT
SET #CategoryID = 0
declare #strsql varchar(max)
set #strsql =
CASE WHEN coalesce(#CategoryID, 0) = 0 THEN 'SELECT * FROM SomeTable'
ELSE
'SELECT * FROM SomeTable WHERE 1 = '+ cast(#CategoryID as varchar(10)) + ''
END
print #strsql
exec sp_executesql #strsql
I want to declare multiple variables based on user input and use them all as conditions in a WHERE clause. I have the variables hard set to the values I want right now for testing. I plan on using the #Well and #Analyst variables in a similar manner in the future. Here is the code:
DECLARE #Analysis nvarchar(20)
DECLARE #SQLQuery nvarchar(max)
DECLARE #Formation nvarchar(50)
DECLARE #Well nvarchar(30)
DECLARE #Analyst nvarchar(50)
SET #Analysis = 'Elemental Analysis'
SET #Formation = 'Bruce'
SET #SQLQuery = N'SELECT TB_Projects.JobLog#, TB_Projects.ProjName, COUNT(TB_Samples.Sample#) AS [Total Samples]
FROM TB_Projects INNER JOIN TB_Samples ON TB_Projects.JobLog# = TB_Samples.JobLog#
WHERE TB_Samples.['+ #Analysis +'] = 1 AND TB_Projects.Formation ='+#Formation+' GROUP BY TB_Projects.JobLog#, TB_Projects.ProjName'
EXECUTE(#SQLQuery)
I receive the following error with this code:
Msg 207, Level 16, State 1, Line 3
Invalid column name 'Bruce'.
'Bruce' should be the value returned for the column TB_Projects.Formation, it's not a column name. Why doesn't this work?
You have this in the string:
TB_Projects.Formation = '+#Formation+'
This is turned into:
TB_Projects.Formation = Bruce
See the problem? If you printed out the string before you ran it, the problem would probably be obvious.
The simplest solution is:
TB_Projects.Formation = '''+#Formation+'''
That will add single quotes.
A better solution is to use sp_executesql with a parameter for the value.
you need to wrap Formation value in single quotes:
SET #SQLQuery = N'SELECT TB_Projects.JobLog#, TB_Projects.ProjName, COUNT(TB_Samples.Sample#) AS [Total Samples]
FROM TB_Projects INNER JOIN TB_Samples ON TB_Projects.JobLog# = TB_Samples.JobLog#
WHERE TB_Samples.['+ #Analysis +'] = 1 AND TB_Projects.Formation ='''+#Formation+''' GROUP BY TB_Projects.JobLog#, TB_Projects.ProjName'
EXECUTE(#SQLQuery)
I have a field that stores value like >=99.35 (storing goals in table) and lets say the actual data value is 78. I then need to compare if goal met or not. How can I accomplish this?
I tried to put that in a #sql variable which will say like:
Select case when 78>=99.35 then 1 else 0 end
but how can I execute this #sql to get the value 1 or 0 in a field of a table?
DECLARE #sql VARCHAR(1000);
DECLARE #Result INT;
SET #Result = 78;
SET #sql = 'SELECT CASE WHEN ' + #Result + ' >=99.35 THEN 1 ELSE 0 END'
EXEC sp_executesql #sql
Using sp_executesql is more likely to cache the query plan if you are going to be repeatedly calling this SQL statement.
DECLARE #ActualValue INT = 100
DECLARE #SQLQuery nVARCHAR(MAX) = ''
SET #SQLQuery = ( SELECT 'SELECT CASE WHEN '+CONVERT(VARCHAR,#ActualValue)+ YourColumn+ 'THEN 1 ELSE 0 END AS ResultValue' FROM YourTable )
EXECUTE sp_executesql #SQLQuery
A solution using sp_executesql as described in the other answers will work fine, but if you're going to be executing the contents of a table as part of a dynamic SQL statement, then you need to be very careful about what can be stored in that field. Do the goals you're storing always consist of a single operator and a target value? If so, it wouldn't be hard to store the two separately and process them with a static query. Something like:
declare #SampleData table
(
[ActualValue] decimal(11, 2),
[Operator] varchar(2),
[ReferenceValue] decimal(11, 2)
);
insert #SampleData values
(100, '>=', 98.25),
(100, '<=', 98.25),
(100, 'G', 98.25);
select
[ActualValue],
[Operator],
[ReferenceValue],
[GoalMet] = case [Operator]
when '>=' then case when [ActualValue] >= [ReferenceValue] then 1 else 0 end
when '<=' then case when [ActualValue] <= [ReferenceValue] then 1 else 0 end
/*...other operators here if needed...*/
else null
end
from
#SampleData;
This is a bit more verbose but perhaps a bit safer as well. Maybe it's usable for your general case and maybe it's not; I just thought I'd throw it out there as an alternative.
I have a T-Sql script where part of this script checks to see if a certain column exists in the a table. If so, I want it to execute a routine... if not, I want it to bypass this routine. My code looks like this:
IF COL_LENGTH('Database_Name.dbo.Table_Name', 'Column_Name1') IS NOT NULL
BEGIN
UPDATE Table_Name
SET Column_Name2 = (SELECT Column_Name3 FROM Table_Name2
WHERE Column_Name4 = 'Some Value')
WHERE Column_Name5 IS NULL;
UPDATE Table_Name
SET Column_Name6 = Column_Name1
WHERE Column_Name6 IS NULL;
END
My problem is that even when COL_LENGTH of Column_Name1 is null (meaning it does not exist) I am still getting an error telling me "Invalid column name 'Column_Name1'" from the 2nd UPDATE statement in the IF statement. For some reason this IF condition is still being evaluated even when the condition is FALSE and I don't know why.
SQL Server parses the statement and validates it, ignoring any if conditionals. This is why the following also fails:
IF 1 = 1
BEGIN
CREATE TABLE #foo(id INT);
END
ELSE
BEGIN
CREATE TABLE #foo(id INT);
END
Whether you hit Execute or just Parse, this results in:
Msg 2714, Level 16, State 1
There is already an object named '#foo' in the database.
SQL Server doesn't know or care which branch of a conditional will be entered; it validates all of the statements in a batch anyway. You can do things like (due to deferred name resolution):
IF <something>
BEGIN
SELECT foo FROM dbo.Table_That_Does_Not_Exist;
END
But you can't do:
IF <something>
BEGIN
SELECT column_that_does_not_exist FROM dbo.Table_That_Does;
END
The workaround, typically, is to use dynamic SQL:
IF <something>
BEGIN
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SELECT column_that_does_not_exist FROM dbo.Table_That_Does;';
EXEC sp_executesql #sql;
END
Make your statement a string. And if column exists, execute it
IF COL_LENGTH('Database_Name.dbo.Table_Name', 'Column_Name1') IS NOT NULL
BEGIN
DECLARE #sql VARCHAR(MAX)
SET #sql = 'UPDATE Table_Name
SET Column_Name2 = (SELECT Column_Name3 FROM Table_Name2
WHERE Column_Name4 = ''Some Value'')
WHERE Column_Name5 IS NULL;
UPDATE Table_Name
SET Column_Name6 = Column_Name1
WHERE Column_Name6 IS NULL;'
EXEC(#sql)
END