I've tried searching but it's likely I'm using the wrong keywords as I can't find an answer.
I'm trying to find the number of orders that are open between two dates and by employee. I have one table that shows a list of employees, another that shows a list of orders that contains an open and close date and also a dates table if that helps.
The employee and order tables joined will return something like:
employee order ref opened closed
a 123 01/01/2012 04/01/2012
b 124 02/01/2012 03/01/2012
a 125 02/01/2012 03/01/2012
And I need to transform this data into:
Date employee Count
01/01/2012 a 1
02/01/2012 a 2
02/01/2012 b 1
03/01/2012 a 2
03/01/2012 b 1
04/01/2012 a 1
I'm pulling the data from SQL server.
Any ideas?
Thanks
Nick
Join Dates to the result of the join between Employees and Orders, then group by dates and employees to obtain the counts, something like this:
SELECT
d.Date,
o.Employee,
COUNT(*) AS count
FROM Employees e
INNER JOIN Orders o ON e.ID = o.Employee
INNER JOIN Dates d ON d.Date BETWEEN o.Opened AND o.Closed
GROUP BY
d.Date,
o.Employee
My favorite way to do this counts the number of cumulative opens and the number of cumulative closes over time.
with cumopens as
(select employee, opened as thedate,
row_number() over (partition by employee order by opened) as cumopens,
0 as cumcloses
from eo
),
cumcloses as
(select employee, closed as thedate, 0 as cumopens,
row_number() over (partition by employee order by closed ) as cumcloses
from eo
)
select employee, c.thedate, max(cumopens), max(cumcloses),
max(cumopens) - max(cumcloses) as stillopened
from ((select *
from cumopens
) union all
(select *
from cumcloses
)
) c
group by employee, thedate
The only problem with this approach is that only dates where there is employee activity get reported. This works in your case.
The more general solution requires a sequence numbers to generate dates. For this, I often create one from some existing table with enough rows:
with nums as
(select row_number() over (partition by null order by null) as seqnum
from employees
)
select employee, dateadd(day, opened, seqnum) as thedate, count(*)
from eo join
nums
on datediff(day, opened, closed) < seqnum
group by employee, dateadd(day, opened, seqnum)
order by 1, 2
SELECT opened,employee,count(*)
FROM employee LEFT JOIN orders
WHERE opened < firstDate and opened > secondDate
GROUP BY opened,employee
or you can change the first condition in
WHERE opened BETWEEN firstDate and secondDate
Calling the result column count was a bit odd because it seems to be in fact a row number.
You can do that by using ROW_NUMBER.
The other interesting part is that you also want open date and close date as separate rows. Using a simple UNION will solve that.
WITH cte
AS (SELECT Row_number() OVER ( PARTITION BY employee
ORDER BY order_ref) count,
employee,
opened,
closed
FROM orders)
SELECT employee, opened date, count
FROM cte
UNION ALL
SELECT employee, closed date, count
FROM cte
ORDER BY Date,
employee
DEMO
Related
I have a table with the name of each customer and date columns and want to write a query to give me the number of gap days for each user,
name date
ali 2022-01-01
ali 2022-01-04
ali 2022-01-05
ser 2022-03-01
the answer should be 3 for ali and for ser will be null.
here is what I tried:
select name ,min(date) over (partition by name order by date) start_date , max(date) over (partition by name order by date) end_date from table
One approach to achieve this is using a window function (like lag, lead) to find the prior/next day and then find the difference between the dates (current and prior, for example ) using datediff function. Something like this..
SELECT name,
MAX(datediff(date, PreviousDate)) AS Gap
FROM (SELECT name,
date,
LAG(date) OVER(PARTITION BY name ORDER BY date) as PreviousDate
FROM table t
GROUP BY name
my approach is to match every record with the closest date then find the maximum gap and left join with the original table to get the gap for each user.
here's MySQL version:
select
cu.name, max(cg.gap) maxgap
from
customers cu left join
(
select
c.name, datediff(min(cn.date), c.date) gap
from
customers c left join customers cn on c.name = cn.name
where
cn.date > c.date
group by
c.name, c.date
) cg
on cu.name = cg.name
group by
cu.name
I have one table which contains trhese colums:
APPOINTSMENTS
|id
|worker_id
|post_id
|date
I can find last appointments for each worker with this query:
SELECT * FROM (
SELECT id,worker_id,post_id,max(date) as date
FROM appointments
GROUP BY worker_id
)
How to find previous appointment (previous to last one) for each worker? How to do it with procedure (but sqlite not supports it, but anyway).
First get the highest date for each worker.
SELECT
worker_id, MAX(date) AS max_date
FROM appointments
GROUP BY worker_id
Then you can use this query as subquery in the next step.
Get the highest date for each worker that is lower than the actual highest date.
SELECT
a.id, a.worker_id, a.post_id, MAX(a.date) AS second_highest_date
FROM appointments a
JOIN (
SELECT
worker_id, MAX(date) AS max_date
FROM appointments
GROUP BY worker_id
) md
ON a.worker_id = md.worker_id
AND a.date < md.max_date
GROUP BY a.worker_id
Here is one method for doing this:
select a.*
from appointments a
where 2 = (select count(*)
from appointments a2
where a2.worker_id = a.worker_id and
a2.date >= a.date
);
Assuming that the dates are unique for each "worker", this will work for the "nth" date. The same logic can work for dates that are not unique, but you would have to clarify exactly what you want in that case.
I want to calculate the day difference between first visit and the second visit; second visit and third visits etc. per customer using SQL. Please assist.
For example, Customer A visited three times on
2016-01-03, 2016-01-06 and 2016-05-30 while customer B visited ten times with different dates.
Query
With cte as (Select customerid, VisitDate,
ROW_NUMBER() OVER(PARTITION BY CustomerID ORDER BY VisitDate) as rownum
FROM visitTable V)
Select CustomerID, VisitDate, rownum, DateDiff(D,R1.VisitDate, R2.VisitDate) as NoOfDays
FROM cte R1
LEFT JOIN cte R2 ON R1.CustomerID = R2.CustomerID AND R1.rownum = 1 AND R2.rownum = 2
Thank you
I think you were pretty close to the right idea. Your join needs to compare row numbers. I also switched the order of your date diff but I didn't test it.
With cte as (
Select customerid, VisitDate,
ROW_NUMBER() OVER(PARTITION BY CustomerID ORDER BY VisitDate) as rownum
FROM visitTable V
)
Select R1.CustomerID, R1.VisitDate, R1.rownum,
DateDiff(D,R2.VisitDate, R1.VisitDate) as NoOfDays --this is days since last visit
FROM cte R1 --current row
LEFT JOIN cte R2 --previous visit - will result in null days for 1st row.
ON R1.CustomerID = R2.CustomerID
AND R1.rownum - 1 = R2.rownum
order by R1.CustomerID, R1.VisitDate;
I'm working on a query in MS SQL to show items that have been in our "service center" more than once within the last 30 days. The data needed is from the service order prior to the most recent service order, based on serial number. So if an item has been received in the last 30 days, check to see if it was received at a previous time within the last 30 days.
ServiceOrders table: CustID, ItemID, DateReceived
ItemMaster table: CustID, ItemID, SerialNumber
I can get DateReceived items by using
ServiceOrders.DateReceived >= DATEADD(month,-1,GETDATE())
I could load service orders from the past month into a temp table, and then query against that to get the prior service order, but that doesn't sound like the best plan. Any ideas on an efficient way to get the previous service orders?
Example data
ServiceOrders table:
CustID ItemID DateReceived
1 2 9/26/2016
1 2 9/05/2016
1 2 1/15/2015
5 6 9/20/2016
7 6 9/02/2016
ItemMaster table:
CustID ItemID SerialNumber
1 2 8675309
5 6 101
7 6 101
So in the above example, SerialNumber 8675309 and 101 have been received more than once in the last 30 days. I need the data from ServiceOrders and ItemMaster for the DateReceived 9/05/2016 and 09/02/2016 records (the second most recent within 30 days). There are other fields in both tables, but they're simplified here. CustID won't necessarily stay the same from date to date, as the item can be transferred. SerialNumber is the key.
Filter the last month orders into Common Table Expression into cte and number them descending. Then select those items with more than 1 occurrences into cte2, join both cte's selecting the second row.
;With cte as(
Select row_number() over(PARTITION by ItemID order by DateReceived desc) as RowNum, *
from ServiceOrders
where DateReceived >= DateAdd(Month, -1, Getdate())
), cte2 as(
Select
ItemID From cte
Group by ItemID
Having count(*)>1
)
select b.*, c.SerialNumber from cte2 as a
left join cte as b on a.ItemID= b.ItemID and b.RowNum=2
left join ItemMaster as c on b.ItemID=c.ItemID and b.CustID=c.CustID
SELECT *, COUNT(ServiceOrders.DateReceived) as DateCount FROM TABLE
Paste to excel
Filter last column to show results = or > than 2
Might be a quick solution for you.
Get the items which have been received more than once in the last 30 days. Then use row_number to number the rows based on the descending order of date_received. Finally, get the rows whose row_number is 2 (the date before the latest date in the last 30 days).
If serialnumber is needed in the output, just join the itemmaster table to the final resultset.
WITH morethanone
AS (SELECT
so.itemid
FROM serviceorders so
JOIN itemmaster i
ON i.itemid = so.itemid
GROUP BY so.itemid
HAVING COUNT(CASE WHEN DATEDIFF(dd, so.datereceived, GETDATE()) <= 30 THEN 1 END)>1
)
SELECT
custid,
itemid,
datereceived
FROM (SELECT
*,
ROW_NUMBER() OVER (PARTITION BY itemid ORDER BY datereceived DESC) rn
FROM serviceorders
WHERE itemid IN (SELECT itemid FROM morethanone)
AND DATEDIFF(dd, datereceived, GETDATE()) <= 30
) x
WHERE rn = 2
I am trying to create a report to show me the last date a customer filed a ticket.
Customers can file dozens of tickets. I want to know when the last ticket was filed and show how many days it's been since they have done so.
The fields I have are:
Customer,
Ticket_id,
Date_Closed
All from the Same table "Tickets"
I'm thinking I want to do a ranking of tickets by min date? I tried this query to grab something but it's giving me all the tickets from the customer. (I'm using SQL in a product called Domo)
select * from (select *, rank() over (partition by "Ticket_id"
order by "Date_Closed" desc) as date_order
from tickets ) zd
where date_order = 1
This should be simple enough,
SELECT customer,
MAX (date_closed) last_date,
ROUND((SYSDATE - MAX (date_closed)),0) days_since_last_ticket_logged
FROM emp
GROUP BY customer
select Customer, datediff(day, date_closed, current_date) as days_since_last_tkt
from
(select *, rank() over (partition by Customer order by "Date_Closed" desc) as date_order
from tickets) zd
join tickets t on zd.date_closed = t.date_closed
where zd.date_order = 1
Or you can simply do
select customer, datediff(day, max(Date_closed), current_date) as days_since_last_tkt
from tickets
group by customer
To select other fields
select t.*
from tickets t
join (select customer, max(Date_closed) as mxdate,
datediff(day, max(Date_closed), current_date) as days_since_last_tkt
from tickets
group by customer) tt
on t.customer = tt.customer and tt.mxdate = t.date_closed
I would do this with a simple sub-query to select the last closed date for the customer. Then compare this to today with datediff() to get the number of days since last closed.
Select
LastTicket.Customer,
LastTicket.LastClosedDate,
DateDiff(day,LastTicket.LastClosedDate,getdate()) as DaysSinceLastClosed
From
(select
tickets.customer
max(tickets.dateClosed) as LastClosedDate
from tickets
Group By tickets.Customer) as LastTicket
Based on the responses this is what I did:
select "Customer",
Max("date_closed") "last_date,
round(datediff(DAY, CURRENT_DATE, max("date_closed")), 0) as "Closed_date"
from tickets
group by "Customer"
ORDER BY "Customer"