SQL: How to Consolidate CASE - sql

I have to repeat a CASE statement twice, and I'm wondering if there's a way to consolidate it.
Basically, I have a:
where open_time >= '11/1/16' and open_time < '12/1/16'
The problem is I need to DATEADD to the open_time based on a CASE Statement. I don't know how to consolidate it together, so I'm doing it twice.
Like:
where
DATEADD(hh,
CASE WHEN MONTH(open_time)=1 THEN -5
ELSE -4
END
,open_time) >= '11/1/16'AND
DATEADD(hh,
CASE WHEN MONTH(open_time)=1 THEN -5
ELSE -4
END
,open_time) < '12/1/16'
Is there any way to make it so I don't have to repeat the entire CASE Statment?

Use a BETWEEN?
WHERE case ... end BETWEEN '11/1/16' AND '12/1/16'
Note that between is "inclusive", so a between b and c is a <= b AND b <= c.

You could write this as:
where (month(open_time) = 1 and
cast(dateadd(hour, -5, open_time) as date) between '2016-11-01' and '2016-11-30'
) or
(month(open_time) <> 1 and
cast(dateadd(hour, -4, open_time) as date) between '2016-11-01' and '2016-11-30'
)
I'm not a fan of using between with date/time values. In this case, the value is explicitly a date, so it doesn't seem too confusing.
Or, if you prefer:
month(open_time) <> 1 and
cast(dateadd(hour, case when month(open_time) = 1 then -5 else -4 end, open_time
) as date) between '2016-11-01' and '2016-11-30'

Related

SQL Query with date range Male Female

I have a query that works but I need to incorporate in that query the following:
For male date is older or equals 3 months;
For female date is older or equals 4 months;
SELECT *
FROM Davaoci
WHERE DatumPoslednjegDavanja >= DATEADD(month, -3, GETDATE())
AND KrvnaGrupa = 'APos'
ORDER BY DatumPoslednjegDavanja DESC
Use a CASE statement:
SELECT * FROM Davaoci
WHERE DatumPoslednjegDavanja >= DATEADD(
month,
CASE WHEN Pol = 'M' THEN -3 ELSE -4 END,
GETDATE()
)
AND KrvnaGrupa = 'APos'
ORDER BY DatumPoslednjegDavanja DESC
EDITED: Based off your comments on the question, I made some adjustments to my answer. Working through our language barrier, I think this is what you're looking for.
NOTE: The way I have this set up now, it will only accept rows where the Pol column has an 'M' or 'F'. You may need to adjust the ELSE as needed.
SELECT *
FROM Davaoci
WHERE
KrvnaGrupa = 'APos'
AND CASE
WHEN Pol = 'M'
THEN DatumPoslednjegDavanja >= DATEADD(month, -3, GETDATE())
WHEN Pol = 'F'
THEN DatumPoslednjegDavanja <= DATEADD(month, -4, GETDATE())
ELSE FALSE
END
ORDER BY
DatumPoslednjegDavanja DESC;

How to deal with case statements using where clause?

below is my where clause it gives me syntax error near ">" sign
(( case when datediff(day,a.durationfrom,a.durationto) <=30 then DATEDIFF(day, a.CompletionDate, GETDATE()) >= 40)
else DATEDIFF(day, a.CompletionDate, GETDATE()) >= 42 end as '0')
I see 2 issues with the syntax, firstly the extra parentheses around CASE THEN and also a use of an alias in a WHERE clause. I would try to change it to
case when datediff(day,a.durationfrom,a.durationto) <=30 then DATEDIFF(day, a.CompletionDate, GETDATE()) >= 40
else DATEDIFF(day, a.CompletionDate, GETDATE()) >= 42 end
I did also drop the outer parentheses since I don't see the need for them but they are not incorrect
This looks like SQL Server code and SQL Server does not support a boolean type. So, this makes no sense:
(case when datediff(day, a.durationfrom, a.durationto) <= 30
then DATEDIFF(day, a.CompletionDate, GETDATE()) >= 40)
else DATEDIFF(day, a.CompletionDate, GETDATE()) >= 42
end) as col_0
Presumably, your intention is something like this:
(case when datediff(day, a.durationfrom, a.durationto) <= 30 and
DATEDIFF(day, a.CompletionDate, GETDATE()) >= 40)
then 1
when datediff(day, a.durationfrom, a.durationto) <= 30
then 0
when DATEDIFF(day, a.CompletionDate, GETDATE()) >= 42
then 1
else 0
end) as col_0

Sum on case expression when working with dates

I'm looking to create a view which will output the data in the following format
AgedPeriod BillValue Status
<1 35000 Outstanding
1-3 23386 Outstanding
3-6 5000 Outstanding
I can use the code below to SUM each case statement into a new column and I could name the column headings after the AgedPeriod listed above but even though the SUMS are right the format is wrong I would like to have the code below nested in another CASE statement that does not have to be GROUPED by b.BILL_DATE as grouping with the bill date defeats the purpose of my SUM. All attempts as using another CASE statement always bring the b.BILL_DATE out of the SUM and into the WHEN condition requiring it to be grouped.
SELECT
SUM(CASE WHEN (b.BILL_DATE <= GetDate()
AND b.BILL_DATE >= DateAdd(mm,-1, GetDate()))
THEN b.OUTSTANDING END),
SUM(CASE WHEN (b.BILL_DATE <= DateAdd(mm,-1, GetDate())
AND b.BILL_DATE >= DateAdd(mm,-3, GetDate()))
THEN b.OUTSTANDING END),
SUM(CASE WHEN (b.BILL_DATE <= DateAdd(mm,-3, GetDate())
AND b.BILL_DATE >= DateAdd(mm,-6, GetDate()))
THEN b.OUTSTANDING END)
FROM dbo.Tables
I understand this may not be achievable with the route that I have taken at present but is there be any other way I can SUM the outstanding amount on each time period? I can deal with the status column (no advice needed there)
I have added a table and some sample data and left a query to show how I would want the data split up but it would want it to be formatted as above (in a column)
Example on Sql Fiddle
Thanks
You want a group by rather than conditional aggregation. The query you want is something like this:
SELECT (CASE WHEN b.BILL_DATE >= DateAdd(month,-1, GetDate())
THEN '<1'
WHEN b.BILL_DATE >= DateAdd(month, -3, GetDate())
THEN '1-3'
WHEN b.BILL_DATE >= DateAdd(month, -6, GetDate())
THEN '3-6'
ELSE '6+'
END) as AgedPeriod,
SUM(Outstanding)
FROM dbo.Tables b
WHERE b.BILL_DATE <= GetDate()
GROUP BY (CASE WHEN b.BILL_DATE >= DateAdd(month,-1, GetDate())
THEN '<1'
WHEN b.BILL_DATE >= DateAdd(month, -3, GetDate())
THEN '1-3'
WHEN b.BILL_DATE >= DateAdd(month, -6, GetDate())
THEN '3-6'
ELSE '6+'
END);
Notes:
The groups are defined by a CASE statement. Because this is evaluated in order, you can simplify the logic.
The common condition b.BILL_DATE <= GetDate() is moved to the WHERE clause.
I added an extra condition for longer than six months. It seems like you wouldn't want to ignore these.
I don't know what the final column is supposed to be.
You could either use a subquery or CTE to perform the case when statement and then join back to the base table to get the sum for the outstanding column like this:
SELECT a.AgedPeriod
,sum(t1.Outstanding) BillValue
,a.[Status]
FROM dbo.Bill t1
JOIN (
SELECT (
CASE
WHEN b.BILLDATE >= DateAdd(month, - 1, GetDate())
THEN '<1'
WHEN b.BILLDATE >= DateAdd(month, - 3, GetDate())
THEN '1-3'
WHEN b.BILLDATE >= DateAdd(month, - 6, GetDate())
THEN '3-6'
ELSE '6+'
END
) AS AgedPeriod
,b.[ID]
,'Outstanding' [Status]
FROM dbo.Bill b
WHERE b.BILLDATE <= GetDate()
) a ON a.[ID] = t1.[ID]
GROUP BY a.AgedPeriod
,a.[Status]
Hope this helps! Here is a SQL Fiddle Demo for this:
SQL Fiddle Solution Demo

Current Year To Date, Last Year To Date, and Other

I need to classify a set of dates as either 'Cur. YTD', 'Lst. YTD', or 'Other'. YTD is based upon getdate(). I have a temp table for testing that has a single column called 'calendar_date' of type DATETIME. I came up with this logic and it appears to work. I'm just wondering if this approach makes good sense from a performance perspective or if something else might be better.
select calendar_date,
case when (MONTH(calendar_date) < MONTH(getdate()))
or (MONTH(calendar_date) = MONTH (getdate())
AND DAY(calendar_date) <= DAY(getdate())) then
case when YEAR(calendar_date) = YEAR(GETDATE()) then 'CYTD'
when YEAR(calendar_date) = YEAR(getdate()) - 1 then 'LYTD'
else 'Other'
end
else 'Other'
end as Tim_Tag_YTD
from #temp1
Your logic looks good and will work as-is.
An alternative which simplifies a little, which assumes you have no future data.
select
calendar_date,
Tim_Tag_YTD = case DATEDIFF(YEAR, calendar_date, GETDATE())
when 0 then 'CYTD'
when 1 then 'LYTD'
else 'Other'
end
from #temp1;
In the case of your logic, you are explicitly putting future data into 'Other', which you can also do like this:
select
calendar_date,
Tim_Tag_YTD = case when calendar_date > GETDATE() then 'Other' else
case DATEDIFF(YEAR, calendar_date, GETDATE())
when 0 then 'CYTD'
when 1 then 'LYTD'
else 'Other'
end
end
from #temp1;
Sometimes something unintuitive performs faster. Something like this might be worth a shot.
set variable #FirstOfLastYear to Jan 1 of last year
using sql server date functions
set #FirstOfThisYear = DateAdd(year, 1, #FirstOfLastYear)
select 'last year' period
, whatever else you need
from #temp1 where calendar_date >= #FirstOfLastYear
and calendar_date < #FirstOfThisYear
union
select 'this year' period
, whatever else you need
from #temp1 where calendar_date >= #FirstOfThisYear
and calendar_date < getDate ()
union
select 'other' period
, whatever else you need
from #temp1 where calendar_date <= #FirstOfLastYear
or calendar_date > getdate()
You'll never know unless you try.

Check if DateTime in DB is more than 90 days old via Stored Procedure

UPDATE
Evidently I didn't include enough data, sorry!
What I need to do is set 'campaign_Status' = 6 when 'campaign_Date' is more than 90 days old.
Hi,
I have a column (campaign_Date) which stores a DATETIME. Using a Stored Procedure I need to check if the stored date is 90 days old (or more).
Any help would be great.
Thanks.
This will return all old campaigns:
SELECT *
FROM mytable
WHERE campaign_Date <= DATEADD(day, -90, GETDATE())
This will select 1 if campaign is old, 0 otherwise:
SELECT CASE WHEN campaign_Date <= DATEADD(day, -90, GETDATE()) THEN 1 ELSE 0 END
FROM mytable
Note that the first query condition is sargable: it will allow using an index to filter the dates.
This will update all old campaigns with status 6:
UPDATE mytable
SET campaign_status = 6
WHERE campaign_Date <= DATEADD(day, -90, GETDATE())
See the DateAdd function
http://msdn.microsoft.com/en-us/library/ms186819.aspx
SELECT *
FROM MyTable
WHERE Campaign_Date <= DateAdd (d, -90, GetDate())
Here's a variation on the previous answers, wrapped in a stored procedure (as seemed to be asked):
CREATE PROC sp_Campaign_Archive AS
UPDATE [Campaign Table]
SET Campaign_Status = 6
WHERE DateDiff(day,Campaign_Date,GetDate()) >= 90
GO
SELECT IIF(DATEDIFF(d, campaign_date, getdate()) >= 90, true, false)
AS IsNinetyOrMoreDaysOld
FROM myTable
EDIT: If you wish to pick records which are 90 or more days old,
SELECT campaign_date
FROM myTable
WHERE DATEDIFF(d, campaign_date, getdate()) >= 90
select campaign_Date,
case when getdate() - campaign_Date >= 90 then 'yes' else 'no' end as Is90DaysOldOrMore
from MyTable
UPDATE:
You can update the records like this:
update MyTable
set campaign_Status = 6
where getdate() - campaign_Date >= 90
Because this status will go out of date rapidly because it is date-dependent, you could make it a calculated column instead.