SQL CASE Statement (keeping the CASE statement within the WHERE clause) - sql-server

I have a table named:
Ext_Meeting_Status
This has fields
Ext_Meeting_Status_ID
TEXT
The values are:
EXT_Meeting_Status_ID Text
1 Draft
2 Published
3 Cancelled
4 Closed
How do i return the "Text" field of "Published" if date is today, else return "Close".
I tried using:
select * from Ext_Meeting_Status
where
GETDATE() = CASE
WHEN ( GETDATE() = '2010-12-13 10:02:31.560' )
THEN ( Ext_Meeting_Status_ID=2)
ELSE ( Ext_Meeting_Status_ID=4)
END

select * from Ext_Meeting_Status
where Ext_Meeting_Status_ID =
CASE WHEN (GETDATE() = '2010-12-13 10:02:31.560')
THEN (2)
ELSE (4)
END
I believe this should work..
One more note : Comparing current date to the exact millisecond level might not work as the query may not get executed at that time...
You may try something like this.
Select getdate(), * from #Temp
Where ID = Case when getdate() between '2010-12-13 05:21:08.240' and '2010-12-13 05:22:08.240'
Then 1
Else 2
End

I don't think it's possible. You may want to try to put it all into a sub-select and use the CASE there.

Related

Set all column values based on condition existing in one row using Snowflake

Working on a view in Snowflake and based certain criteria I want to set the Pass/Fail column for all rows to "Pass" if a certain output is reached. Example (below)for a give Item number/ Plant combination, where the condition is met for one row, I would like to set all rows to "Pass"
Here is my case statement as is: I'm Having trouble getting this scenario to "Pass" for all rows
case
when
((case
when 'PIRStatus' is null
then 'PIR-Missing'
else 'PIR-Exists'
end)='PIR-Exists'
and "FixedVendor" = 'X'
and (case
when "SLStatus" = 'SL-Exists'
then 1
else 2
end) = 1)
then 'Pass'
else 'Fail'
end as "Pass/Fail"
PIRStatus Vendor BlockedVendor FixedVendor SLStatus Pass/Fail
PIR-Exists 12547 X SL-Exists Pass
PIR-Exists 85996 SL-Missing Fail
PIR-Exists 54788 SL-Missing Fail
This is based on a given Item/ Plant combination, as long as any row says pass then I want the other rows to Pass as well
You probably want to use a correlated subquery, which I find is best written with a CTE like this:
WITH CTE_CONDITION AS (
SELECT
id,
case when (
(
case when 'PIRStatus' is null then 'PIR-Missing' else 'PIR-Exists' end
)= 'PIR-Exists'
and "FixedVendor" = 'X'
and (
case when "SLStatus" = 'SL-Exists' then 1 else 2 end
) = 1
) then 'Pass' else 'Fail' end as "Pass/Fail"
FROM
table
)
SELECT
* ,
CASE WHEN EXISTS (SELECT 1 FROM CTE_CONDITION WHERE "Pass/Fail" = 'Pass' AND table.id = CTE_CONDITION.id)
THEN 'This ID Passes At Least Somewhere'
ELSE 'This ID never passes'
END as DOES_THIS_EVER_PASS
FROM table
The thing to remember using EXISTS is that the SELECT portion doesn't really matter (thus, SELECT 1) but it is the WHERE clause that connects the table itself to CTE_CONDITION.
You might even clean this up by creating CTE_PASS and CTE_FAIL and putting conditions in the WHERE clauses, to compartmentalize the logic and avoid that messy CASE statement.
Thus, you could accomplish the same thing with something like:
WITH CTE_PASS AS (
SELECT id
FROM table
WHERE {conditions that mean a pass}
)
SELECT
* ,
CASE WHEN EXISTS (SELECT 1 FROM CTE_PASS WHERE table.id = CTE_CONDITION.id)
THEN 'This ID Passes At Least Somewhere'
ELSE 'This ID never passes'
END as DOES_THIS_EVER_PASS
FROM table

Apply Different WHERE clause depending on value of one field

i'm trying to build a query in which I need to apply 2 different where clauses, depending on the value of Current Month. In this case, I need to show data from the last 2 years, only of the months before the current month:
Example 1:
Current Date is: 01-01-2017
Need to show data from:
01/2015; 02/2015; 03/2015; 04/2015; 05/2015; 06/2015;
07/2015; 08/2015; 09/2015; 10/2015; 11/2015; 12/2015;
01/2016; 02/2016; 03/2016; 04/2016; 05/2016; 06/2016;
07/2016; 08/2016; 09/2016; 10/2016; 11/2016; 12/2016.
Example 2:
Current Date is: 01-03-2017
Need to show data from: 01/2016; 02/2016; 01/2017; 02/2017.
So I built the following query:
SELECT *
FROM TABLE1
WHERE
CASE MONTH(GETDATE())
WHEN 1
THEN YEAR(Data)>=YEAR(GETDATE())-2 and YEAR(data)<YEAR(GETDATE())
ELSE YEAR(Data)>=YEAR(GETDATE())-1 and YEAR(data)<=YEAR(data) and MONTH(data)<MONTH(GETDATE())
END
I'm getting an error.
Can you please help me?
Thank you.
Your syntax is incorrect for sure. THEN is not a logical expression - it is supposed to return value. So you can't write logical expression in THEN/ELSE blocks as you have attempted to. Instead you might try something like:
WHERE
#date >= CASE WHEN a=b THEN '20150101' ELSE '20160202' END
Another thing is: conversions and functions in predicate are very bad for performance. When working with dates you might want to prepare filter predicate before the query when possible, e.g.:
declare
#date_begin date,
#date_end date
set #date_end = DATEADD(..., #arg_date)
set #date_begin = DATEADD(YEAR, -2, #date_end)
select ...
where date between #date_begin and #date_end
in your case it could be something like:
declare
#arg_date DATE = GETDATE(),
#date_begin DATE,
#date_end DATE,
#max_month INT
set #max_month = MONTH(#date)
if #max_month = 1
begin
set #date_end = DATEADD(dd, 1-DATEPART(dy, #arg_date), #arg_date) /* first day of year */
set #date_begin = dateadd(YY, -2, #date_end)
end
else
begin
set #date_end = #arg_date
set #date_begin = dateadd(YY, -1, DATEADD(dd, 1-DATEPART(dy, #date_end), #date_end)) /* first day of year_begin */
end
SELECT *
FROM TABLE1 t
WHERE t.date >= #date_begin and t.date < #date_end
AND (#max_month = 1 OR MONTH(t.date) < #max_month)
another (a better) way is to prepare #periods table variable, put each (date_begin, date_end) pair you need into it and join with TABLE1 - you'll get rid of all function calls from within WHERE clause.
You should realize: you know exactly which periods of each year you need in the result set. There is nothing to compute from stored TABLE1->date column. Just filter it with precomputed date intervals. Don't convert or modify date column - it is already ready to use. Merely apply appropriate filters. MONTH(date) <= 3 is date <= 20170331. Don't torture left part - prepare appropriate right part of such predicates.
The easiest way would be something like:
SELECT *
FROM TABLE1
WHERE
(YEAR(Data)>=YEAR(GETDATE())-2 and YEAR(data)<YEAR(GETDATE()) AND MONTH(GETDATE()) = 1)
OR (YEAR(Data)>=YEAR(GETDATE())-1 and MONTH(data)<MONTH(GETDATE()) and MONTH(GETDATE()) <> 1)
(Note I removed the superfluous and YEAR(data)<=YEAR(data).).
Personally I prefer (and I think it's generally advised) AND/OR logic to a CASE in a WHERE clause.
The error with your CASE statement is caused by the fact that CASE returns an atomic value. It cannot be used in the same way as if in procedural languages.
You can't swap in additional statements to your where clause using case statements. Instead, you need to resolve the case to an equality:
select *
from Table1
where case month(getdate()) -- You want to avoid using functions on fields in your WHERE claises, as this can reduce performance.
when 1 then case when Data >= dateadd(year,datediff(year,0,getdate())-2,0)
and Data < dateadd(year,datediff(year,0,getdate()),0)
then 1 -- Data rows the meet the criteria will return 1.
else 0 -- Data rows that do not will return 0.
end
else case when (Data >= dateadd(year,datediff(year,0,getdate())-1,0)
and Data < dateadd(m,datediff(m,0,getdate())-12,0)
)
or (Data >= dateadd(year,datediff(year,0,getdate()),0)
and Data < dateadd(m,datediff(m,0,getdate()),0)
)
then 1
else 0
end
end = 1 -- Then limit the results to only those rows that returned a 1.
In your specific instance however, this can be simplified to a standard or:
select *
from Table1
where (month(getdate()) = 1
and Data >= dateadd(year,datediff(year,0,getdate())-2,0)
and Data < dateadd(year,datediff(year,0,getdate()),0)
)
or (month(getdate()) <> 1
and (Data >= dateadd(year,datediff(year,0,getdate())-1,0)
and Data < dateadd(m,datediff(m,0,getdate())-12,0)
)
or (Data >= dateadd(year,datediff(year,0,getdate()),0)
and Data < dateadd(m,datediff(m,0,getdate()),0)
)
)
Note the use of brackets above to separate out the logical tests. Where a Data row meets either one of those criteria it will be returned in your query.

how to order list that has date and a word in sql server

case when prefinallist.truckbooked is null then 'Immediate' else CAST(prefinallist.previous_date as varchar) END as ETA
The list contain either the word Immediate or datetime.
How to show immediate on the top and date in acending.
You can try to use ORDER BY like this:
ORDER BY (`ETA` = 'Immediate') ASC
or you can also use CASE statement inside the ORDER BY like
ORDER BY CASE WHEN ETA = 'Immediate' THEN 1 ELSE 2 END

Aggregate Function Error on an Expression

What could be wrong with this query:
SELECT
SUM(CASE
WHEN (SELECT TOP 1 ISNULL(StartDate,'01-01-1900')
FROM TestingTable
ORDER BY StartDate Asc) <> '01-01-1900' THEN 1 ELSE 0 END) AS Testingvalue.
The get the error:
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
As koppinjo stated what your current (broken) query is doing is checking if you have a NULL-value (or StartDate = '01-01-1900') in your table, return either a 1 or a 0 depending on which, and then attempting to SUM that single value.
There are 2 different logical things you want.
Either getting the amount of rows that has a StartDate or checking if any row is missing StartDate.
SELECT --Checking if there is a NULL-value in table
(
CASE WHEN
(SELECT TOP 1 ISNULL(StartDate,'01-01-1900')
FROM TestingTable
ORDER BY StartDate Asc) <> '01-01-1900' THEN 1
ELSE 0
END
) AS TestingValue
SELECT SUM(TestingValue) TestingValue --Give the count of how many non-NULLs there is
FROM
(
SELECT
CASE WHEN
ISNULL(StartDate,'01-01-1900') <> '01-01-1900' THEN 1
ELSE 0
END AS TestingValue
FROM TestingTable
) T
Here is a SQL Fiddle showing both outputs side by side.
Hard to say, but you probably want something like this:
SELECT
SUM(TestingValue)
FROM
(SELECT
CASE
WHEN ISNULL(StartDate,'01-01-1900') <> '01-01-1900'
THEN 1
ELSE 0
END AS TestingValue
FROM TestingTable) t
As your original query is written now, your subquery will return 1 value overall, so your sum would be 1 or 0 always, not to mention it is illegal. To get around that, this SQL will apply the case statement to every row in the TestingTable and insert the result into a derived table (t), then the 'outer' select will sum the results. Hope this helps!

JOIN ON subselect returns what I want, but surrounding select is missing records when subselect returns NULL

I have a table where I am storing records with a Created_On date and a Last_Updated_On date. Each new record will be written with a Created_On, and each subsequent update writes a new row with the same Created_On, but an updated Last_Updated_On.
I am trying to design a query to return the newest row of each. What I have looks something like this:
SELECT
t1.[id] as id,
t1.[Store_Number] as storeNumber,
t1.[Date_Of_Inventory] as dateOfInventory,
t1.[Created_On] as createdOn,
t1.[Last_Updated_On] as lastUpdatedOn
FROM [UserData].[dbo].[StoreResponses] t1
JOIN (
SELECT
[Store_Number],
[Date_Of_Inventory],
MAX([Created_On]) co,
MAX([Last_Updated_On]) luo
FROM [UserData].[dbo].[StoreResponses]
GROUP BY [Store_Number],[Date_Of_Inventory]) t2
ON
t1.[Store_Number] = t2.[Store_Number]
AND t1.[Created_On] = t2.co
AND t1.[Last_Updated_On] = t2.luo
AND t1.[Date_Of_Inventory] = t2.[Date_Of_Inventory]
WHERE t1.[Store_Number] = 123
ORDER BY t1.[Created_On] ASC
The subselect works fine...I see X number of rows, grouped by Store_Number and Date_Of_Inventory, some of which have luo (Last_Updated_On) values of NULL. However, those rows in the sub-select where luo is null do not appear in the overall results. In other words, where I get 6 results in the sub-select, I only get 2 in the overall results, and its only those rows where the Last_Updated_On is not NULL.
So, as a test, I wrote the following:
SELECT 1 WHERE NULL = NULL
And got no results, but, when I run:
SELECT 1 WHERE 1 = 1
I get back a result of 1. Its as if SQL Server is not relating NULL to NULL.
How can I fix this? Why wouldn't two fields compare when both values are NULL?
You could use Coalesce (example assuming Store_Number is an integer)
ON
Coalesce(t1.[Store_Number],0) = Coalesce(t2.[Store_Number],0)
The ANSI Null comparison is not enabled by default; NULL doesn't equal NULL.
You can enable this (if your business case and your Database design usage of NULL requires this) by the Hint:
SET ansi_nulls off
Another alternative basic turn around using:
ON ((t1.[Store_Number] = t2.[Store_Number]) OR
(t1.[Store_Number] IS NULL AND t2.[Store_Number] IS NULL))
Executing your POC:
SET ansi_nulls off
SELECT 1 WHERE NULL = NULL
Returns:
1
This also works:
AND EXISTS (SELECT t1.Store_Number INTERSECT SELECT t2.Store_Number)

Resources