LAG and Partition by multiple computations - sql-server

I have a list of accounts and respective call reason and I did a LAG and Over Partition By. The below query told me whether the same CustomerID contacted again within 7 days and if contact more than once in 7 days returns N whilst if not returns Y.
SELECT
con.[CustomerID]
,con.[ContactDate]
,con.[ContactReason1]
,ISNULL (LAG(con.[ContactDate], 1) OVER (PARTITION BY con.[CustomerID] ORDER BY con.[ContactDate]),'2999-12-31') as '2ndConDate'
,ISNULL (DATEDIFF(day,LAG(con.[ContactDate], 1) OVER (PARTITION BY con.[CustomerID] ORDER BY con.[ContactDate]), con.[ContactDate]),-1) as 'NumDays'
,CASE WHEN DATEDIFF(day,LAG(con.[ContactDate], 1) OVER (PARTITION BY con.[CustomerID] ORDER BY con.[ContactDate]), con.[ContactDate]) < 7 THEN 'N' ELSE 'Y' END AS '7DayContact'
FROM [DWH_Layer].[Layer1].[Layer2] con
Now I need to do a further drill down, and get if the same CustomerID contacted us in the previous 7 days using the same ContactReason1 then return N else Y.
Any ideas?

SELECT
con.[CustomerID]
,con.[ContactDate]
,con.[ContactReason1]
,ISNULL (LAG(con.[ContactDate], 1) OVER (PARTITION BY con.[CustomerID] ORDER BY con.[ContactDate]),'2999-12-31') as '2ndConDate'
,ISNULL (DATEDIFF(day,LAG(con.[ContactDate], 1) OVER (PARTITION BY con.[CustomerID] ORDER BY con.[ContactDate]), con.[ContactDate]),-1) as 'NumDays'
,CASE WHEN DATEDIFF(day,LAG(con.[ContactDate], 1) OVER (PARTITION BY con.[CustomerID] ORDER BY con.[ContactDate]), con.[ContactDate]) < 7 THEN 'N' ELSE CASE WHEN LAG([ContactReason1], 1) OVER (PARTITION BY con.[CustomerID] ORDER BY con.[ContactDate]) = [ContactReason1] THEN 'Y' ELSE 'N' END END AS '7DayContact'
FROM [DWH_Layer].[Layer1].[Layer2] conenter code here

Related

Query running tally of open issues on a given day

I have been banging my head on this for a while now and I think I've drastically over-complicating things at this point. What I have is a table containing the fields
OpenDate
ClosedDate
Client
Contract
Service
What I need to turn that into is
Date
Client
Contract
Service
OpenedOnThisDay
OpenedYesterday
ClosedOnThisDay
ClosedYesterday
OpenAtStartOfTomorrow
OpenAtStartOfToday
For any given Date, there may or may not be any issues opened or closed ON that day. That day should still be included with 0's
I have come at this a number of ways and can produce one of the desired results at a time (opened on, closed on, Open at end of), but I cannot get them all at once, at least not without exponentially increasing the query time.
My queries currently as views are as follows
Opened On
select Cast(EntryDateTime as Date) as DateStamp
,ContractNumber
,Client
,services.Service
,sum(1) as Count
,lag(sum(1)) OVER (
partition by tickets.ContractNumber
,services.Service ORDER BY Cast(EntryDateTime as Date) ASC
) as CountDayBefore
from v_JiraImpactedServices as services
LEFT JOIN v_JiraTickets as tickets ON services.ticketnumber = tickets.TicketNumber
WHERE tickets.Client is not null
AND tickets.TicketNumber IS NOT NULL
and tickets.ContractNumber is not null
GROUP BY Cast(tickets.EntryDateTime as Date)
,tickets.ContractNumber
,tickets.Client
,services.Service;
Closed On
select Cast(ResolvedDateTime as Date) as DateStamp
,ContractNumber
,Client
,services.Service
,sum(1) as Count
,lag(sum(1)) OVER (
partition by tickets.ContractNumber
,services.Service ORDER BY Cast(ResolvedDateTime as Date) ASC
) as CountDayBefore
from v_JiraImpactedServices as services
LEFT JOIN v_JiraTickets as tickets ON services.ticketnumber = tickets.TicketNumber
WHERE tickets.Client is not null
and tickets.TicketNumber is not null
AND tickets.ContractNumber is not null
GROUP BY Cast(tickets.ResolvedDateTime as Date)
,tickets.ContractNumber
,tickets.Client
,services.Service;
Open On
SELECT calendar.FullDate as DateStamp
,tickets.ContractNumber
,tickets.client
,services.Service
,IsNull(count(tickets.TicketNumber), 0) as Count
,IsNull(lag(count(tickets.TicketNumber), 1) OVER (
partition by tickets.ContractNumber
,services.Service Order By FullDate ASC
), 0) as CountDayBefore
FROM v_Calendar as calendar
LEFT JOIN v_JiraTickets as tickets ON Cast(tickets.EntryDateTime as Date) <= calendar.FullDate
AND (
Cast(tickets.ResolvedDateTime as Date) > calendar.FullDate
OR tickets.ResolvedDateTime is null
)
LEFT JOIN v_JiraImpactedServices as services ON services.ticketnumber = tickets.TicketNumber
WHERE tickets.Client is not null
AND tickets.ContractNumber is not null
GROUP BY calendar.FullDate
,tickets.ContractNumber
,tickets.Client
,services.Service;
As I said each of these by itself gives ALMOST the desired results, but omits days with 0 values.
Aside from producing days with 0 values, I need to also combine these into a single table result. All attempts so far have either produced obviously wrong JOIN results, or takes an hour to execute.
I would be most grateful if someone could point me in the right direction here.
Just to give you an idea, although the fieldnames don't match your scenario, this is how I would approach this:
WITH
SourceData (ClientID, ContractID, ServiceID, DateStamp) AS (
SELECT a.ID, b.ID, c.ID, d.DateStamp
FROM clients a
JOIN contracts b ON a.ID = b.ClientID
JOIN [services] c ON b.ID = c.ContractID
CROSS JOIN calendar d
WHERE d.DateStamp >= DATEADD(day, -60, GETDATE())
)
SELECT d.DateStamp, s.ClientID, s.ContractID, s.ServiceID
, COUNT(CASE WHEN Cast(EntryDateTime as Date) = d.DateStamp THEN 1 END) AS OpenedOn
, COUNT(CASE WHEN Cast(ResolvedDateTime as Date) = d.DateStamp THEN 1 END) AS ClosedOn
, COUNT(CASE WHEN Cast(ResolvedDateTime as Date) > d.DateStamp OR ResolvedDateTime IS NULL AND EntryDateTime IS NOT NULL THEN 1 END) AS InProgress
FROM SourceData s
LEFT JOIN tickets t
ON s.ClientID = t.ClientID
AND s.ContractID = t.ContractID
AND s.ServiceID = t.ServiceID
AND s.DateStamp >= Cast(EntryDateTime as Date)
AND (s.DateStamp <= ResolvedDateTime OR ResolvedDateTime IS NULL)
GROUP BY d.DateStamp, s.ClientID, s.ContractID, s.ServiceID

Columns created by case statement do not group by when use partition by

I am doing reporting where I previously got into same problem but got it solved here is the link to question,
Over here I got the same problem with little change here I also require partition by
CASE WHEN MP.PT = 'OPD' THEN COUNT(MP.YN) OVER (PARTITION BY MP.PT,mp.tti ORDER BY mp.tti) END AS OPD,
CASE WHEN MP.PT = 'IPD' THEN COUNT(MP.YN) OVER (PARTITION BY MP.PT,mp.tti ORDER BY mp.tti) END AS IPD,
CASE WHEN MP.PT = 'A&E' THEN COUNT(MP.YN) OVER (PARTITION BY MP.PT,mp.tti ORDER BY mp.tti) END AS EAC
The result should be in same row as they part of single select but it appear in multiple rows and do not aggregate
Try this:
SUM(IIF(MP.PT = 'OPD', 1, 0)) OVER (PARTITION BY mp.tti) AS OPD,
SUM(IIF(MP.PT = 'IPD', 1, 0)) OVER (PARTITION BY mp.tti) AS IPD,
SUM(IIF(MP.PT = 'A&E', 1, 0)) OVER (PARTITION BY mp.tti) AS EAC

How do I get difference days in SQL Server?

I'm facing a problem that I don't know how to solve.
I would like to get difference of 3 days between 2 values. But when I do a query filter one value, i got results:
SELECT
BeginRange, EndRange,
DATEDIFF(DAY,InicioRange , FimRange ) as DifferenceDays,
Code
FROM
(SELECT
MAX(DataTransacao) OVER (ORDER BY DataTransacao) BeginRange,
LEAD(DataTransacao) OVER (ORDER BY DataTransacao) EndRange,
Code
FROM
#Relatorio1
WHERE
Code = '000008480700001') AS C
WHERE
c.EndRange > c.BeginRange
-- AND datediff(day,BeginRange, EndRange) >= 3
ORDER BY
DifferenceDays, Code
Results:
BeginRange EndRange DifferenceDays Code
-------------------------------------------------------
20170601 20170602 1 000008480700001
20170602 20170605 3 000008480700001
But when I run query without filter, I don't get the results above.
SELECT
BeginRange, EndRange,
DATEDIFF(DAY,InicioRange , FimRange ) as DifferenceDays,
Code
FROM
(SELECT
MAX(DataTransacao) OVER (ORDER BY DataTransacao) BeginRange,
LEAD(DataTransacao) OVER (ORDER BY DataTransacao) EndRange,
Code
FROM
#Relatorio1) AS C
WHERE
c.EndRange > c.BeginRange
-- AND datediff(day,BeginRange, EndRange) >= 3
ORDER BY
DifferenceDays, Code;
Results
NOTHING
What am I doing wrong? I can't get the first result that I got in first query.
Your question is a bit hard to follow, but I think you just need partition by:
SELECT BeginRange, EndRange,
DATEDIFF(DAY,InicioRange , FimRange ) as DifferenceDays
Code
FROM (SELECT MAX(DataTransacao) OVER (PARTITION BY Code ORDER BY DataTransacao) as BeginRange,
LEAD(DataTransacao) OVER (PARTITION BY Code ORDER BY DataTransacao) as EndRange,
Code
FROM #Relatorio1
) C
WHERE c.EndRange > c.BeginRange
-- AND datediff(day,BeginRange, EndRange) >= 3
ORDER BY DifferenceDays, Code;

Using OVER() if customer has watch gladiator then 1 else 0 SQL SERVER

I think I need some guidance as to what is wrong in my query. I am trying to do
Watched_Gladiator=CASE WHEN FilmName IN (CASE WHEN FilmName LIKE '%Gladiator%' THEN 1 END) then OVER(PARTITION BY Cust_Nr) THEN 1 ELSE 0 END
Tried this one too:
Watched_Gladiator=CASE WHEN FilmName IN (CASE WHEN FilmName LIKE '%Gladiator%' THEN Filmnamne END) then OVER(PARTITION BY Cust_Nr) THEN 1 ELSE 0 END
The Error I am currently getting is this:
Incorrect syntax near the keyword 'OVER'.
This is basically how my data looks like
Cust_Nr Date FilmName Watched Gladiator
157649306 20150430 Gladiator 1
158470722 20150504 Nick Cave: 20,000 Days On Earth 0
158467945 20150504 Out Of The Furnace 0
158470531 20150504 FilmA 0
157649306 20150510 Gladiator 1
158470722 20150515 Gladiator 1
I want to create a column (1 or zero) that shows if the customer has watched Gladiator then 1 ELSE 0. How can I do that?
I created a test column trying with a simple LIKE '%Gladiator%' THEN 1 ELSE 0. The problem with this solution is that it will show 1(one) more than once if the customer has watched multiple times. I only need 1 or zero.
I feel I am really close to finding a solution. I am very new to using OVER() and CASE WHEN but enjoying the thrill:=)
So you're saying that:
SELECT Cust_Nr, Date, FilmName,
CASE WHEN FilmName LIKE '%Gladiator%' THEN 1 ELSE 0 END as WatchedGladiator
FROM YourTable
WHERE YourColumn = #somevalue
Doesn't work? Because according to the data you've given, it should.
EDIT:
Well based on Tim's comment, I would simply add this bit to the query.
SELECT Cust_Nr, Date, FilmName, WatchedGladiator
FROM
(
SELECT Cust_Nr, Date, FilmName,
CASE WHEN FilmName LIKE '%Gladiator%' THEN 1 ELSE 0 END as WatchedGladiator
FROM YourTable
WHERE YourColumn = #somevalue
) as wg
WHERE WatchedGladiator = 1
The following does what you want for all films:
select r.*,
(case when row_number() over (partition by filmname order by date) = 1
then 1 else 0
end) as IsWatchedFirstAndGladiator
from results r;
For just Gladiator:
select r.*,
(case when filmname = 'Gladiator' and row_number() over (partition by filmname order by date) = 1
then 1 else 0
end) as IsWatchedFirst
from results r;
So you want to group by customer and add a column if this customer watched a specific film?
You could do:
SELECT Cust_Nr, MAX(Watched_Gladiator)
FROM( SELECT Cust_Nr,
Watched_Gladiator = CASE WHEN EXISTS
(
SELECT 1 FROM CustomerFilm c2
WHERE c2.Cust_Nr = c1.Cust_Nr
AND c2.FilmName LIKE '%Gladiator%'
) THEN 1 ELSE 0 END
FROM CustomerFilm c1 ) X
GROUP BY Cust_Nr
Demo
But it would be easier if you used the customer-table instead of this table, then you don't need the group-by.
Try grouping up to the cust/film level:
select
cust_nbr,
case when film_name like '%Gladiator%' then 1 else 0 end
from
(
select
cust_nbr,
film_name
from
<your table>
group by
cust_nbr,
film_name
) t
Or, as an alternative:
select distinct cust_nbr
from
<your table>
where
filmname = 'Gladiator'

LASt 6 records of the output of the stored procedure

The following is the stored procedure and "I want to fetch the LATEST SIX
INVOICES FOR EACH CUSTOMER"
THERE COULD BE MORE INVOICES FOR EACH CUSTOMER BUT I HAVE TO FETCH ONLY
WHICH ARE LATEST 6 INVOICES.
ALTER PROCEDURE [dbo].[SCA_M_CUSTSOINV_REFRESH]
#COMP_CD NVARCHAR(20)='',
#USER_CD NVARCHAR(20)='',
#USER_TYPE NVARCHAR(1)=''
AS
SET NOCOUNT ON
DECLARE #SLSHIST_DATE NVARCHAR(10)
SELECT
#SLSHIST_DATE = CONVERT(NVARCHAR(10), DATEADD(MONTH,-SLSHIST_MTH,dbo.[GetCountryDate]()),120)
FROM SET_MASTER
WITH SUBQUERY AS
(SELECT
ROW_NUMBER() OVER (PARTITION BY A.CUST_CD ORDER BY C.INV_KEY DESC) "ROW_ID",
A.CUST_CD,C.SO_KEY "TXN_KEY",
C.INV_NO, C.INV_KEY, C.INV_DT, C.INV_STATUS, C.NET_TTL_TAX AS INV_AMT
FROM
(SELECT DIST_CD, SLSMAN_CD, CUST_CD FROM T_CA_SLSMANCUST
WHERE DIST_CD = #COMP_CD AND SLSMAN_CD = #USER_CD) A
INNER JOIN TXN_INVOICE C ON C.CUST_CD=A.CUST_CD
AND C.INV_DT >= #SLSHIST_DATE
)
SELECT
CUST_CD, TXN_KEY, INV_NO, INV_KEY, INV_DT, INV_STATUS, INV_AMT,
CASE ROW_ID WHEN 1 THEN 'Y' ELSE 'N' END "LAST_INV"
FROM SUBQUERY
ORDER BY CUST_CD,INV_KEY
You are getting ROW_ID by ROW_NUMBER() OVER (PARTITION BY A.CUST_CD ORDER BY C.INV_KEY DESC) and the last invoice is the one with ROW_ID = 1 so don't you just need to add WHERE ROW_ID <= 6 as below?
SELECT
CUST_CD, TXN_KEY, INV_NO, INV_KEY, INV_DT, INV_STATUS, INV_AMT,
CASE ROW_ID WHEN 1 THEN 'Y' ELSE 'N' END "LAST_INV"
FROM SUBQUERY
WHERE ROW_ID <= 6
ORDER BY CUST_CD,INV_KEY
SELECT TOP 6 * FROM invoices ORDER BY date DESC

Resources