How to deal with case statements using where clause? - sql

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

Related

Query to find extract time between

Im a beginner with SQL and need help to get some transactions in our WMS between 00.00.00 and 06.00.00 but can't make it work.
This is how far I have come,
SELECT cast(datreg as time) [time], logguser, l16lcode, partno, l16qty, datreg
FROM L16T3
WHERE datreg > '0000-00-00 00:00:00'
AND datreg < '9999-99-99 06:00:00'
AND L16T3.l16lcode = 2
I dont know what to write to get transactions only between 24.00-06.00
(Using SQL Server 2012)
Best Regards
Try this condition:
WHERE DATEPART(hour, datreg) BETWEEN 0 AND 5 OR
(DATEPART(hour, datreg) = 6 AND DATEPART(minute, datreg) = 0 AND DATEPART(second, datreg) = 0)
I would suggest:
SELECT cast(datreg as time) as [time], logguser, l16lcode, partno, l16qty, datreg
FROM L16T3 l
WHERE CONVERT(time, l.datreg) >= '00:00:00' AND
CONVERT(time, l.datreg) < '06:00:00' AND
l.l16lcode = 2;
You can also use the hours:
WHERE DATEPART(hour, l.datreg) >= 0 AND
DATEPART(hour, l.datreg) < 6 AND
l.l16lcode = 2;
However, this does not generalize so easily if, say, the second time were 06:30:00.
Something lie this perhaps:
SELECT IIF(CONVERT(TIME, GETDATE()) BETWEEN '00:00:00' AND '23:59:59','TRUE','FALSE');
Try the above query in SQLFiddle
In your case it would be something like this:
SELECT cast(datreg as time) [time], logguser, l16lcode, partno, l16qty, datreg
FROM L16T3
WHERE CONVERT(TIME, datreg ) BETWEEN '00:00:00' AND '06:00:00'
AND L16T3.l16lcode = 2

Move code to nested query to resolve copypaste

I have sql query
Here is code
SELECT tt.creationdate AS CreatedDate,
DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) AS DaysOpen,
CASE WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 180 THEN '180+ Days'
WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 150 THEN '150 - 180 Days'
WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 120 THEN '120 - 150 Days'
WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 90 THEN '90 - 120 Days'
WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 60 THEN '60 - 90 Days'
WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 30 THEN '30 - 60 Days'
WHEN DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) >= 0 THEN '0 - 30 Days'
ELSE NULL END AS TaskAging,
tms.SupportType,
tms.SupportModule,
tt.*
FROM public.tasks tt
LEFT JOIN
public.tasks_meta_support tms
ON tms.taskid = tt.Id
WHERE tt.issupportticket = 1
AND tt.supportorganizationid = 65277
AND tt.completeddate IS NULL
AND tt.isdeleted = 0
I need to move DaysOpen to nested query to reuse it in CASE
How I can do this correctly?
Just use a subquery:
SELECT tt.DaysOpen,
(CASE WHEN tt.DaysOpen >= 180 THEN '180+ Days'
WHEN tt.DaysOpen >= 150 THEN '150 - 180 Days'
WHEN tt.DaysOpen >= 120 THEN '120 - 150 Days'
WHEN tt.DaysOpen >= 90 THEN '90 - 120 Days'
WHEN tt.DaysOpen >= 60 THEN '60 - 90 Days'
WHEN tt.DaysOpen >= 30 THEN '30 - 60 Days'
WHEN tt.DaysOpen >= 0 THEN '0 - 30 Days'
END )AS TaskAging,
tms.SupportType,
tms.SupportModule,
tt.*
FROM (SELECT tt.*, DATEDIFF(DAY, CAST(tt.creationdate AS DATE), GETDATE()) AS DaysOpen
FROM public.tasks tt
) tt LEFT JOIN
public.tasks_meta_support tms
ON tms.taskid = tt.Id
WHERE tt.issupportticket = 1
AND tt.supportorganizationid = 65277
AND tt.completeddate IS NULL
AND tt.isdeleted = 0;
Note that the ELSE is redundant, so I removed it.
First I would move the GETDATE() to #Now and set it just before the query. You might get a difference in behaviour if this run 23:59:59.999, but in general you want the values fromwhen you asked, not when it's running.
Also try not to use wildcards when selecting columns.
Also, do you want all rows from public.tasks and only the matching one from publi.tasks_meta_support or all rows from public.tasksmeta_support? The order you write thing is really important here (https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2005/ms177634(v%3dsql.90)#e-using-the-sql-92-left-outer-join-syntax).
That said you could use a CTE or some a subquery.
I would go with a CTE and writing out all the columns.
Not knowing which columns there are in public.tasks maybe this subquery?
Note that I moved everything related to public.tasks to tt.
DECLARE #Now datetime;
SET #Now = #Now;
SELECT ptsq.CreatedDate,
ptsq.DaysOpen,
ptsq.TaskAging,
tms.SupportType,
tms.SupportModule,
ptsq.*
FROM (SELECT creationdate AS CreatedDate,
DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) AS DaysOpen,
CASE WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 180 THEN '180+ Days'
WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 150 THEN '150 - 180 Days'
WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 120 THEN '120 - 150 Days'
WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 90 THEN '90 - 120 Days'
WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 60 THEN '60 - 90 Days'
WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 30 THEN '30 - 60 Days'
WHEN DATEDIFF(DAY, CAST(creationdate AS DATE), #Now) >= 0 THEN '0 - 30 Days'
FROM public.tasks
WHERE issupportticket = 1
AND supportorganizationid = 65277
AND isdeleted = 0) ptsq
LEFT OUTER JOIN public.tasks_meta_support tms ON ptsq.taskid = tms.Id -- Assuming you want all rows from public.tasks.
WHERE ptsq.completeddate IS NULL -- Could probably be moved to ptsq

SQL: How to Consolidate CASE

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'

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

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.