Move code to nested query to resolve copypaste - sql

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

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

SQL Server, filter for max date and max date minus 7 days

I'm trying to design a view and apply several conditions on my timestamp (datetime): last date and last date minus 7 days.
This works fine for the last date:
SELECT *
FROM table
WHERE timestamp = (SELECT MAX(timestamp) FROM table)
I couldn't figure out the way to add minus 7 days so far.
I tried, for instance
SELECT *
FROM table
WHERE (timestamp = (SELECT MAX(timestamp) FROM table)) OR (timestamp = (SELECT DATEADD(DAY, -7, MAX(timestamp)) FROM table)
and some other variations, including GETDATE() instead of MAX, however, I'm getting the execution timeout messages.
Please let me know what logic should I follow in this case.
Data looks like this, but there's more of it :)
So I want to get data only for rows with 29/11/2019 and 22/11/2019. I have an additional requirement for filtering for factors, but it's a simple one.
If you care about dates, then perhaps you want:
select t.*
from t cross join
(select max(timestamp) as max_timestamp from t) tt
where (t.timestamp >= convert(date, max_timestamp) and
t.timestamp < dateadd(day, 1, convert(date, max_timestamp))
) or
(t.timestamp >= dateadd(day, -7, convert(date, max_timestamp)) and
t.timestamp < dateadd(day, -6, convert(date, max_timestamp))
);
So I ended up with the next code:
SELECT *
FROM table
WHERE (timestamp >= CAST(DATEADD(DAY, - 1, GETDATE()) AS datetime)) AND (timestamp < CAST(GETDATE() AS DATETIME)) OR
(timestamp >= CAST(DATEADD(DAY, - 8, GETDATE()) AS datetime)) AND (timestamp < CAST(DATEADD(day, - 7, GETDATE()) AS DATETIME)) AND (Factor1 = 'Criteria1' OR
Factor2 = 'Criteria2')
Not sure if it's the best or the most elegant solution, but it works for me.

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

Subtracting date using DATEDIFF function and getting NULL as results

So I'm tasked with finding the delay in weeks for each order. I've used the DATEDIFF function and I'd like to believe I'm on the right track but when I use it I get NULL as the result. The data type for each column are both date.
SELECT DISTINCT Sales.Orders.custid, Sales.Customers.companyname,
CASE
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) = 7 AND DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 14 THEN '1 Week'
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) = 14 AND DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 21 THEN '2 Weeks'
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) = 21 AND DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 28 THEN '3 Weeks'
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) = 28 AND DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 35 THEN '4 Weeks'
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) = 35 AND DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 42 THEN '5 Weeks'
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) = 42 AND DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 49 THEN '6 Weeks'
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) > 49 THEN '7+ Weeks'
ELSE 'Unknown'
END AS Order_Delay
FROM Sales.Orders, Sales.Customers
ORDER BY
Order_Delay ASC;
I'm using MS SQL Server Management Studio 2016.
Try rewriting your query like this:
SELECT DISTINCT Sales.Orders.custid, Sales.Customers.companyname,
CASE
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) >= 7 AND DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 14 THEN '1 Week'
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 21 THEN '2 Weeks'
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 28 THEN '3 Weeks'
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 35 THEN '4 Weeks'
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 42 THEN '5 Weeks'
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 49 THEN '6 Weeks'
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) >= 49 THEN '7+ Weeks'
ELSE 'Unknown'
END AS Order_Delay
FROM Sales.Orders, Sales.Customers
ORDER BY
Order_Delay ASC;
I think you want to check whether difference is in particular range (from 7 to 14, etc.).
So I corrected first cndition:
WHEN DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) >= 7 AND DATEDIFF(DAY, Sales.Orders.shippeddate, Sales.Orders.orderdate) < 14 THEN '1 Week'
You could not use BETWEEN here, as its range includes also broders of a set.
For other cases, you don't need to check whether the difference is greater than, eg. in second WHEN you know that the difference is >=14, since it failed first condition, etc.
FROM Sales.Orders, Sales.Customers is an old-fashioned way of forming a cross join. This is probably accidental but the impact of this can be awful both in terms of performance but also the results can be plain wrong - and they are in your example. It is for this reason that I always recommend you use explicit join syntax such as inner join and cease using commas as a way to define the from clause.
You simply have to properly join the 2 tables, otherwise every order is applied to every customer and the results would be quite wrong. I have guessed that join, but it should look something like the one seen below:
SELECT /* DISTINCT ?? */
Sales.Orders.custid
, Sales.Customers.companyname
, CASE
WHEN ca.Order_Delay >= 7 THEN '7+ Weeks'
WHEN ca.Order_Delay >= 1 AND ca.Order_Delay < 7 THEN CAST(ca.Order_Delay AS varchar) + ' Weeks'
ELSE 'Unknown'
END AS order_delay
FROM Sales.Orders AS o
INNER JOIN Sales.Customers AS c ON o.custid = c.id
CROSS APPLY (
SELECT
FLOOR(DATEDIFF(DAY, o.shippeddate, o.orderdate) / 7)
) ca (order_delay)
ORDER BY
order_delay ASC
;
In SQL Server is possible to use cross apply as a way to perform a calculation, and give that calculation an alias that you can then use in the select clause. This can have the effect of making your code somewhat easier to read, but this is optional.
Above I have suggested a way to use floor() which you should read about here:
https://learn.microsoft.com/en-us/sql/t-sql/functions/floor-transact-sql?view=sql-server-2017
nb: If you want to show data for unshipped orders then you may need to change to an outer apply, and if an order is unshipped the the datediff() function would return NULL and your case expression would need to explicitly cater for NULLs
SELECT /* DISTINCT ?? */
Sales.Orders.custid
, Sales.Customers.companyname
, CASE
WHEN ca.Order_Delay >= 7 THEN '7+ Weeks'
WHEN ca.Order_Delay >= 1 AND ca.Order_Delay < 7 THEN CAST(ca.Order_Delay AS varchar) + ' Weeks'
WHEN ca.Order_Delay IS NULL then 'Unshipped'
ELSE 'Unknown'
END AS order_delay
FROM Sales.Orders AS o
INNER JOIN Sales.Customers AS c ON o.custid = c.id
OUTER APPLY (
SELECT
FLOOR(DATEDIFF(DAY, o.shippeddate, o.orderdate) / 7)
) ca (order_delay)
ORDER BY
order_delay ASC
;
https://learn.microsoft.com/en-us/sql/t-sql/functions/datediff-transact-sql?view=sql-server-2017
DATEDIFF ( datepart , startdate , enddate )
My guess is that in your system shippeddate is mostly later or equal to orderdate, so instead of
FLOOR(DATEDIFF(DAY, o.shippeddate, o.orderdate) / 7)
you might want
FLOOR(DATEDIFF(DAY, o.orderdate, o.shippeddate) / 7)
to check this assumption you might want to add ca.Order_Delay (as per code suggested by #Used_by_already) to list of selected columns and see what values are there. My bet is they are all negative.
You are looking for exactly 7, 14, 21 etc. You need >= 7 instead (and repeat for the rest...).

How to count the rows

How i can count the rows between the two dates.
SELECT Count(DATEDIFF(day, ReceiptDate,GETDATE()))
As TotalDays
From JobDetails
Where Receiptdate Between DATEADD(day, -30, GETDATE()) and DATEADD(day, -90, GETDATE())
AND RepairCompleted='N'
Group By ReceiptDate
for example i want to check 30 to 90 days not completed jobs count.
Try this:
SELECT Count(*) As TotalDays
FROM JobDetails
WHERE Receiptdate >= DATEADD(day, -90, GETDATE())
AND Receiptdate <= DATEADD(day, -30, GETDATE())
AND RepairCompleted='N'