i have a table, which showing statuses of processes ( especially i searching canceled processes), there is no sorting out there. I want to select all of them that they were resume again. I want to do this "sticking a specific date to canceled process and check if there are still other statuses after the cancellation status.
Example:
[id] [moddate] [status]
1 01/01/17 started
1 02/01/17 waiting for signature
1 04/01/17 canceled
1 09/01/17 delivery documents
1 11/01/17 complited <-- I want to select these statuses, (Canceled and then somehow resumed)
I got something like this on start:
SELECT * FROM DATABASE
WHERE APPLICATIONSTATUSSYMBOL LIKE 'CANCELED%'
AND APPLICATIONDATE BETWEEN '17/01/01' AND '17/07/24';
One method for doing this uses window functions:
select d.*
from (select d.*,
max(case when status = 'canceled' then applicationdate end) over (partition by id) as canceldate
from database
where applicationdate between date '2017-01-01' and date '2017-07-24'
) d
where applicationdate > canceldate;
Related
I'm using SSMS to create a report showing customer accounts where the Sales Reps didn't follow up on leads we received this year. That would be indicated in accounts wheriin the list of activities (actions in the account), 'Lead' is the last one listed (the rep didn't take any actions after receiving the lead).
My code is pulling the latest 'Lead' activity for all customers who've had at least one lead this year:
CustomerName
Activity
Date
Bob's Tires
Lead
2021-01-05
Ned's Nails
Lead
2021-02-02
Good Eats
Lead
2021-02-03
I need it to only pull customers where the Lead was the last activity:
CustomerName
Activity
Date
Ned's Nails
Lead
2021-02-02
Here is my code and example tables. What am I missing? I've tried many things with no luck.
WITH activities AS (
SELECT
a. *
, CASE WHEN a.ContactDate = MAX(CASE WHEN a.Activity LIKE 'Lead%'
THEN a.ContactDate END) OVER (PARTITION BY a.AcctID)
THEN 1 ELSE 0 END AS no_followup
FROM AcctActivities a
WHERE a.ContactDate >= '2021-01-01'
)
SELECT
c.Name,
act.Activity,
act.ContactDate
FROM Customers c
INNER JOIN activities act ON c.AcctID = act.AcctID AND act.no_followup = 1
ORDER BY c.AcctID, act.ContactDate ASC
Table 1: Customers (c)
AcctID
CustomerName
11
Bob's Tires
12
Ned's Nails
13
Good Eats
14
Embers
Table 2: Activities (a)
AcctivityID
AcctID
Activity
Date
1
11
Contact Added
2021-01-01
2
11
Lead
2021-01-05
3
11
Phone Call
2021-01-06
4
12
Lead
2021-02-02
5
13
Lead
2021-02-03
6
13
Phone Call
2021-01-15
7
13
Sales Email
2021-01-15
8
14
Cold Call
2021-01-20
Your approach filters which rows may be considered in the max value in the comparison. I've included the suggested modification below which also modifies your CASE expression to consider that the current row is a lead as the case expression may filter the bounded values to consider (i.e. it will give you the latest lead activity but the latest lead activity may not be your latest activity).
Another modification, possibly optional but safe is adding the ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING in the OVER clause of your partition. While you could have also used UNBOUNDED PRECEDING instead of CURRENT ROW, it seems like extra processing when all the rows before the ordered ContactDate would be already be less than the current value and you are interested in the maximum value for contact date . The window function by default considers all rows current and before. The amendment would ask the window function to look at all the results in the partition after the current row.
Eg.
WITH activities AS
(
SELECT
a. *,
CASE
WHEN a.Activity LIKE 'Lead%' AND
a.ContactDate = (MAX(a.ContactDate) OVER (PARTITION BY a.AcctID ORDER BY a.ContactDate ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ))
THEN 1
ELSE 0
END AS no_followup
FROM
AcctActivities a
WHERE
a.ContactDate >= '2021-01-01'
)
SELECT
c.Name,
act.Activity,
act.ContactDate
FROM
Customers c
INNER JOIN
activities act ON c.AcctID = act.AcctID
AND act.no_followup = 1
ORDER BY
c.AcctID, act.ContactDate ASC
Furthermore, if you are only interested in the customer details and all the resulting activity names would be Lead you may consider the following approach which uses aggregation and having clause to filter your desired results. This approach returns less details in the resulting CTE by filtering early.
WITH customers_with_last_activity_as_lead as (
SELECT AcctID, MAX(ContactDate) as ContactDate
FROM AcctActivities a
WHERE a.ContactDate >= '2021-01-01'
GROUP BY AcctID
HAVING
MAX(a.ContactDate) = MAX(
CASE
WHEN a.Activity LIKE 'Lead%' THEN a.ContactDate
END
)
)
SELECT
c.Name,
-- 'Lead' as Activity, -- Uncomment this line if it is that you would like to see this constant value in your resulting queries.
act.ContactDate
FROM
Customers c
INNER JOIN
customers_with_last_activity_as_lead act ON c.AcctID = act.AcctID
ORDER BY
c.AcctID, act.ContactDate ASC
if all the values aren't a constant/literal Lead then the following approach may assist in retrieving the correct activity name also
WITH customers_with_last_activity_as_lead as (
SELECT
AcctID,
REPLACE(MAX(CONCAT(ContactDate,Activity)),MAX(ContactDate),'') as Activity,
MAX(ContactDate) as ContactDate
FROM AcctActivities a
WHERE a.ContactDate >= '2021-01-01'
GROUP BY AcctID
HAVING
MAX(a.ContactDate) = MAX(
CASE
WHEN a.Activity LIKE 'Lead%' THEN a.ContactDate
END
)
)
SELECT
c.Name,
act.Activity,
act.ContactDate
FROM
Customers c
INNER JOIN
customers_with_last_activity_as_lead act ON c.AcctID = act.AcctID
ORDER BY
c.AcctID, act.ContactDate ASC
Let me know if this works for you.
I agree with Gordon that your question isn't totally clear (do you actually only care about activities this year? What is the intended meaning of no_followup?). Having said that, I think this is what you want:
select c.Name,
lastActivity.Activity,
lastActivity.ContactDate
from Customers c
cross apply (
select top 1 a.Activity, a.ContactDate
from activities a
where a.acctId = c.acctId
-- and a.ContactDate >= '2021-01-01' uncomment this if you only care about activity this year
order by a.ContactDate desc
) lastActivity
where lastActivity.Activity like 'Lead%'
I need to find date ranges where status is Missing/Not Ready in all the groups ( Only the overlapping date ranges where all the groups have status of missing/notready)
'''
ID. Group. Eff_Date. Exp_Date Status
1. 1 1/1/18 10:00 3/4/18 15:23 Ready
1 1 3/4/18 15:24. 7/12/18 13:54. Not Ready
1. 1 7/12/18 13:55. 11/22/19 11:20 Missing
1. 1. 11/22/19 11:21. 9/25/20 1:12. Ready
1. 1. 9/25/20 1:13 12/31/99. Missing
1. 2 1/1/16 10:00 2/2/17 17:20 Ready
1 2 2/2/17 17:21. 5/25/18 1:23. Missing
1. 2 5/25/18 1:24 9/2/18 4:15 Not Ready
1. 2 9/2/18 4:16. 6/3/21 7:04. Missing
1. 2 6/3/21 7:04. 12/31/99. Ready
Output for not ready: ( below are the dates where each group has not ready status)
5/25/18 1:24. 7/12/18 13:54 Not Ready
Missing: ( Below are the date where each group has Missing status)
9/25/20 1:13 6/3/21 7:04 Missing
'''
Note-> Each ID can have any number of groups. Database is Snowflake
You can do this by unpivoting and counting. Assuming that the periods do not overlap for a given id:
with x as (
select eff_date as date, 1 as inc
from t
where status = 'Missing'
union all
select end_date, -1 as inc
from t
where status = 'Missing'
)
select date, next_date, active_on_date
from (select date,
sum(sum(inc)) over (order by date) as active_on_date,
lead(date) over (order by date) as next_date
from x
group by date
) x
where active_on_date = (select count(distinct id) from t);
Note: This handles one status at a time, which is what this question is asking. If you want to handle all event types, then ask a new question with appropriate sample data, desired results, and explanation.
I need to check if the row value repeats in next row. If it does than the Ticket is still open and if it is closed then I need to show value in Closed column.
In example below, Ticket 55 is open from May 1st to May 7th so each day I am showing it Open in Open Column and on May 7th the Ticket is closed so I show it as closed
Ticket Open Closed
5/1/2019 55 1
5/2/2019 55 1
5/3/2019 55 1
5/4/2019 55 1
5/5/2019 55 1
5/6/2019 55 1
5/7/2019 55 1 1
5/8/2019 60
Assuming that ticket and he date column you showed no name for aren't nullable, you can use lead() to get the next ticket ID for a ticket where the records are ordered by the date column you showed no name for. If that is null that means there is no follow up. Also using lead() you can check if the date of the next record is the next day.
SELECT ...
CASE
WHEN lead(ticket) OVER (PARTITION BY ticket
ORDER BY <your anonymous date column>) IS NULL
OR lead(<your anonymous date column>) OVER (PARTITION BY ticket
ORDER BY <your anonymous date column>) <> dateadd(day, 1, <your anonymous date column>) THEN
1
END closed,
...
Replace <your anonymous date column> with the name of the date column.
Is this what you want?
select t.*,
(case when date = max(date) over (partition by ticket)
then 1 else 0
end) as closed
from t;
It would appear that you simply want 1 as open.
If the ticket values can repeat, use lead():
select t.*,
(case when ticket = lead(ticket) over (partition by ticket order by ticket)
then 0 else 1
end) as closed
from t;
If you use SQL Server 2012 or later you can use LEAD(). Here is a sample :
I have found next ticket number via LEAD() function partitioned by TicketNumber. If it returns a value that's mean the ticket still not closed. If it is null ticket is closed.
SELECT T.TicketDate
, T.TicketNumber
, CASE WHEN LEAD(T.TicketNumber) OVER (PARTITION BY T.TicketNumber ORDER BY T.TicketDate ) IS NULL THEN '' ELSE '1' END [Open]
, CASE WHEN LEAD(T.TicketNumber) OVER (PARTITION BY T.TicketNumber ORDER BY T.TicketDate ) IS NULL THEN '1'ELSE '' END Closed
FROM Ticket T
I wanted to profile my data set to find the data discrepancies.
My sample date set:
id status stdate enddate
1 new 01-JUL-17 31-JUL-17
1 process 01-OCT-17 31-DEC-18
1 new 01-JAN-19 31-JAN-19--- issue
2 new 01-SEP-14 31-JAN-15
2 process 01-JUN-16 30-NOV-17
2 complete 01-DEC-17 31-DEC-18
....
....
I would like to find out how many of those IDs have a result status that is older than current. The order of the status sequence should be NEW-PROCESS-COMPLETE. So I want report all IDs where the most recent status has reversed to an earlier status.
You can use the LAG() function to find the offending rows, as in:
with x (id, status, stdate, enddate,
prev_id, prev_status, prev_stdate, prev_enddate) as (
select
id,
status,
stdate,
enddate,
lag(id) over(partition by id order by stdate),
lag(status) over(partition by id order by stdate),
lag(stdate) over(partition by id order by stdate),
lag(enddate) over(partition by id order by stdate)
from my_table
)
select * from x
where status = 'new' and prev_status in ('process', 'complete')
or status = 'process' and prev_status = 'complete'
Note: I assume you need to compare only between rows of the same ID.
I have a query regarding my report, the report format is as under
**Date** **Received** **Closed** **Pending**
12/01/10 1000 900 100
12/02/10 2000 1000 1000
12/03/10 1500 1300 200
The above report shows the Help Desk tickets Received, Closed, Pending Count as date wise.
How can I create a dynamic SQL query to show above result?
Received Tickets is calculated on SubmitedDate
Closed Tickets is calculated on ClosedDate with status "Closed"
same for Pending Tickets whose status is "Pending".
Please provide me the idea or some sample SQL queries.
Write the received, closed, and pending queries separately, and then join them together like this:
SELECT r.[Date], r.Count As Received, c.Count As Closed, p.Count AS Pending
FROM
( /* Received query here */ ) r
FULL JOIN
( /* Closed query here */) c ON c.[Date] = r.[Date]
FULL JOIN
( /* Pending query here */) p ON p.[Date] = r.[Date]
I chose a full join because you wouldn't want a zero-result at any point to ever force a row to be culled from the results.
Use:
SELECT CONVERT(VARCHAR, t.submitteddate, 101) AS [date].
COUNT(t.submitteddate) AS received
SUM(CASE WHEN t.status = 'closed' THEN 1 ELSE 0 END) AS closed,
SUM(CASE WHEN t.status = 'pending' THEN 1 ELSE 0 END) AS pending
FROM YOUR_TABLE t
GROUP BY CONVERT(VARCHAR, t.submitteddate, 101)
ORDER BY [date]
If you want to see dates where none were sold, you're going to have to derive a table of dates and then LEFT JOIN the query above to that based on the date.