T-SQL Date Difference between rows using row number same table - sql-server

This is my SQL Server view:
SELECT
ROW_NUMBER() OVER (PARTITION BY N.PHN
ORDER BY N.CheckDate ASC) AS RowNumber,*
FROM
(SELECT
dbo.Flu.Day AS CheckDate,
dbo.Flu.PHN AS PHN
FROM
dbo.Flu
LEFT OUTER JOIN
dbo.Patient ON dbo.Flu.PHN = dbo.Patient.PHN) AS N;
Result:
I am trying to find the difference between two consecutive dates in days for each PHN based on RowNumber; keeping in mind that some PHN will only have one RowNumber.

You can do it with LAG() window function:
SELECT f.Day AS CheckDate, f.PHN AS PHN,
DATEDIFF(
day,
COALESCE(LAG(f.Day) OVER (PARTITION BY f.PHN ORDER BY f.Day ASC), f.Day),
f.Day
) diff
FROM dbo.Flu f LEFT OUTER JOIN dbo.Patient p
ON f.PHN = p.PHN

Related

Print results side by side SQL Server

I have following result set,
Now with above results i want to print the records via select query as below attached image
Please note, I will have only two types of columns in output Present Employee & Absent Employees.
I tried using pivot tables, temporary table but cant achieve what I want.
One method would be to ROW_NUMBER each the the "statuses" and then use a FULL OUTER JOIN to get the 2 datasets into the appropriate columns. I use a FULL OUTER JOIN as I assume you could have a different amount of employees who were present/absent.
CREATE TABLE dbo.YourTable (Name varchar(10), --Using a name that doesn't require delimit identification
Status varchar(7), --Using a name that doesn't require delimit identification
Days int);
GO
INSERT INTO dbo.YourTable(Name, Status, Days)
VALUES('Mal','Present',30),
('Jess','Present',20),
('Rick','Absent',30),
('Jerry','Absent',10);
GO
WITH RNs AS(
SELECT Name,
Status,
Days,
ROW_NUMBER() OVER (PARTITION BY Status ORDER BY Days DESC) AS RN
FROM dbo.YourTable)
SELECT P.Name AS PresentName,
P.Days AS PresentDays,
A.Name AS AbsentName,
A.Days AS AbsentDays
FROM (SELECT R.Name,
R.Days,
R.Status,
R.RN
FROM RNs R
WHERE R.Status = 'Present') P
FULL OUTER JOIN (SELECT R.Name,
R.Days,
R.Status,
R.RN
FROM RNs R
WHERE R.Status = 'Absent') A ON P.RN = A.RN;
GO
DROP TABLE dbo.YourTable;
db<>fiddle
2 CTE's is actually far neater:
WITH Absents AS(
SELECT Name,
Status,
Days,
ROW_NUMBER() OVER (ORDER BY Days DESC) AS RN
FROM dbo.YourTable
WHERE Status = 'Absent'),
Presents AS(
SELECT Name,
Status,
Days,
ROW_NUMBER() OVER (ORDER BY Days DESC) AS RN
FROM dbo.YourTable
WHERE Status = 'Present')
SELECT P.Name AS PresentName,
P.Days AS PresentDays,
A.Name AS AbsentName,
A.Days AS AbsentDays
FROM Absents A
FULL OUTER JOIN Presents P ON A.RN = P.RN;

How to combine two rows into a single row in CTE

I am getting data in a CTE like this.
Here I am getting two records for each ActivityId, what I want to achieve is two create a single record from the two rows. From the row where r2=1 I need only the RDate as Todate, ActualProgress as endprogress and PlannedProgress as endplannedprogress because these are the only values that will changed on both the rows.
I am getting this data in a CTE.
WITH CTE as(SELECT row_number() over (partition by pmaph.ActivityId order by date) r1, row_number() over (partition by pmaph.ActivityId order by date desc) r2,pma.PlanEndDate as PlanEndDate ,pma.PlanStartDate as PlanStartDate,pmaph.ActivityId,pmaph.ProjectMilestoneActivProgHist_Id as ProMileAvtiID,umd.UOM_Name as UomName, pmm.MilestoneName as MilestoneName,pma.ActivityName as ActivityName ,pmp.ProjectName as ProjectName, Replace((rtrim(ltrim(Convert(varchar(12),Cast(pmaph.Date as Datetime),106)))),' ','-') as RDate, isnull(pmaph.Actual_Progress,0) as ActualProgress,isnull(pmaph.Planned_Progress,0) as PlannedProgress FROM ProjectMilestoneActivityProgressHistory as pmaph left join dbo.PM_Project as pmp on pmaph.ProjectId=pmp.ProjectId left join dbo.PM_Activity as pma on pmaph.ActivityId=pma.ActivityId left join dbo.PM_Milestone as pmm on pmaph.MilestoneId=pmm.MilestoneId left join dbo.UOMDetail as umd on pma.UOM_Id=umd.UOM_Id where pmaph.Client_Id=#ClientId
)
select * from CTE where r1=1 or r2=1
You can do a Group By ActivityId and including a MAX(RDate) AND MAX(ActualProgress), it should return you only one-row per ActivityId.
Maybe this can give you a hint. Make sure to keep the format of your SQL.
;WITH CTE as
(
SELECT
row_number() over (partition by pmaph.ActivityId order by date) r1,
row_number() over (partition by pmaph.ActivityId order by date desc) r2,
pma.PlanEndDate as PlanEndDate ,
pma.PlanStartDate as PlanStartDate,
pmaph.ActivityId,
pmaph.ProjectMilestoneActivProgHist_Id as ProMileAvtiID,
umd.UOM_Name as UomName,
pmm.MilestoneName as MilestoneName,
pma.ActivityName as ActivityName,
pmp.ProjectName as ProjectName,
Replace((rtrim(ltrim(Convert(varchar(12),Cast(pmaph.Date as Datetime),106)))),' ','-') as RDate,
isnull(pmaph.Actual_Progress,0) as ActualProgress,
isnull(pmaph.Planned_Progress,0) as PlannedProgress
FROM
ProjectMilestoneActivityProgressHistory as pmaph
left join dbo.PM_Project as pmp on pmaph.ProjectId=pmp.ProjectId
left join dbo.PM_Activity as pma on pmaph.ActivityId=pma.ActivityId
left join dbo.PM_Milestone as pmm on pmaph.MilestoneId=pmm.MilestoneId
left join dbo.UOMDetail as umd on pma.UOM_Id=umd.UOM_Id
where
pmaph.Client_Id=#ClientId
)
SELECT
C1.*, -- Now you have all data in one row (by Activity), select whichever columns you want
C2.*
FROM
CTE AS C1
INNER JOIN CTE AS C2 ON
C1.ActivityId = C2.ActivityId AND
C2.r2 = 1 -- ... and join against the other row
WHERE
C1.r1 = 1 -- pick 1 row by Activity

Sql Filter table by two dates in order

I have been trying to filter one table by two dates with an order of importance (date2 > date1) as follows:
SELECT
t1.customer, t1.weights, t1.max(t1.date1) as date1, t1.date2
FROM
(SELECT *
FROM table
WHERE CAST(date2 AS smalldatetime) = '10/29/2017') t2
INNER JOIN
table t1 ON t1.customer = t2.customer
AND t1.date2 = t2.date2
GROUP BY
t1.customer, t1.date2
ORDER BY
t1.customer;
It filters the table correctly by date2 first, the max(t1.date1) doesn't what I want it to do though. I get duplicate customers, that share the same (and correct) date2, but show different date1's. These duplicate records have the following in common: The weight row is different. What would I need to do to output just the the customer records connected to the most current date1 without taking other columns into consideration?
I am still a noob, help would be greatly appreciated!
Solution for t-sql (all based on the accepted answer):
SELECT * FROM (
SELECT row_number() over(partition by t1.customer order by t1.date1 desc) as rownum, t1.customer, t1.weights, t1.date1 , t1.date2
FROM
(SELECT *
FROM table
WHERE CAST(date2 AS smalldatetime) = '10/29/2017') t2
INNER JOIN
table t1 ON t1.customer = t2.customer
AND t1.date2 = t2.date2
)t3
where rownum = 1;
If I understood correctly, then instead of a group by logic, I would just use a qualify row statement :)
Try the code below and tell me if it's what you needed - what I'm telling it to do is to bring back only one row per customer ID....but where we select the row based on the dates (by sorting them in ascending order) - however, I'm unclear of what you mean by importance of the 2 dates so I may be completely off base here...can you please give an example of input and desired output?
SELECT t1.customer, t1.weights, t1.date1, t1.date2
FROM
(
Select *
FROM table
WHERE Cast(date2 as smalldatetime)='10/29/2017'
) t2
Inner Join table t1
ON t1.customer = t2.customer
AND t1.date2 = t2.date2
Qualify row_number() over(partition by t1.customer order by date2 , date1)=1
Order By t1.customer;

SQL Query - Grouping/Aggregating Across multiple Tables

select D.[Date], E.emp_name, E.emp_jde, count(C.[agent_no]) calls, count(S.[EMPJDENUM]) sales
from
(select cast([start_date] as date) dte, [agent_no]
from call_table
where [skill_name] like '%5700 sales l%'
and [Agent_Time] != '0'
) C
full outer join
(select [AC#DTE_dt], [EMPJDENUM]
from sales_table
where [ICGCD2] in ('LAWN', 'HORT')
and [CHANNEL]= 'INQ'
and [ITMQTY]>3
) S on c.dte=s.[AC#DTE_dt]
right join
(select [Date]
from Date_table
) D on c.dte=d.[Date] or s.[AC#DTE_dt]=d.[Date]
right join
(select [emp_name], [emp_jde], [agent_no]
from Employee_table
) E on C.[agent_no]=E.agent_no and S.[EMPJDENUM]=E.emp_jde
group by D.[Date], E.emp_name, E.emp_jde
Date Tables -
Note: Not all dates will have both calls and sales.
Additional Tables -
What needs to be accomplished -
1) Join and Aggregate calls and sales by Employee by joining the calls table (on agent_no) and sales (on JDE) table
2) Since not all dates will include both calls and sales - use the date dimension table to ensure all dates are represented
The desired result would look like this -
The query I wrote executes - it takes so long I just end up canceling the query.
Any help would be appreciated.
Without seeing the query plan, it is a little tricky, but here are a couple of suggestions that might improve the performance:
remove the leading wildcard in where [skill_name] like '5700 sales l%'
put the group by into the subqueries
I have an example here that implements both of those. (Note that I did some reformatting just to try to understand what your query was doing.)
select D.[Date], E.emp_name, E.emp_jde, C.Calls, S.Sales
from Date_table As D
Left Join (
select cast([start_date] as date) As CallDate, [agent_no], Count(*) As Calls
from call_table
where [skill_name] like '5700 sales l%'
and [Agent_Time] != '0'
Group By Cast([start_date] As date), [agent_no]) As C On D.[Date] = C.CallDate
Left Join (
select [AC#DTE_dt] As SaleDate, [EMPJDENUM], Count(*) As Sales
from sales_table
where [ICGCD2] in ('LAWN', 'HORT')
and [CHANNEL]= 'INQ'
and [ITMQTY]>3
Group By [AC#DTE_dt], [EMPJDENUM]) As S on D.[Date] = s.SaleDate
right join Employee_table As E
on C.[agent_no]=E.agent_no
and S.[EMPJDENUM]=E.emp_jde;
Edit
In order to get a row for each possible combination of date and employee, you will need a cross join of the date table and the employee table.
select D.[Date], E.emp_name, E.emp_jde, C.Calls, S.Sales
from Date_table As D,
Employee_table as E
Left Join (
select cast([start_date] as date) As CallDate, [agent_no], Count(*) As Calls
from call_table
where [skill_name] like '5700 sales l%'
and [Agent_Time] != '0'
Group By Cast([start_date] As date), [agent_no]) As C
On D.[Date] = C.CallDate
And E.agent_no = C.agent_no
Left Join (
select [AC#DTE_dt] As SaleDate, [EMPJDENUM], Count(*) As Sales
from sales_table
where [ICGCD2] in ('LAWN', 'HORT')
and [CHANNEL]= 'INQ'
and [ITMQTY]>3
Group By [AC#DTE_dt], [EMPJDENUM]) As S
on D.[Date] = s.SaleDate
and E.emp_jde = S.[EMPJDENUM];

Group by customer name

Demo
SELECT ROW_NUMBER() OVER (ORDER BY Visit_Date DESC,P_Master.P_Name ASC) AS RowNumber,
P_Master.P_Name,
(SELECT MAX(Visit_Date) FROM P_Visit v WHERE v.PID = p_Master.PID) as Visit_Date
FROM P_Master
LEFT JOIN P_VISIT
ON P_Master.PID=P_VISIT.PID
WHERE P_Master.P_Name LIKE 'j%'
I have to show max date of column Visit_Date if i search on '2013-10-29' then record shows those customers have date '2013-10-29' in coloumn i have to shown max date of customer
all its working fine but How to make group by PID(I have to show only one record for the given search )
Please try below query, it will also help in pagination
SELECT ROW_NUMBER() OVER (ORDER BY Visit_Date DESC,P_Name ASC) AS RowNumber, *
FROM (SELECT DISTINCT P_Master.P_Name,
(SELECT MAX(Visit_Date) FROM P_Visit v WHERE v.PID = p_Master.PID) as Visit_Date
FROM P_Master
LEFT JOIN P_VISIT
ON P_Master.PID=P_VISIT.PID
WHERE P_Master.P_Name LIKE 'j%') tbl
This will work:
SELECT DISTINCT
P_Master.P_Name,
(SELECT MAX(Visit_Date) FROM P_Visit v WHERE v.PID = p_Master.PID) as Visit_Date
FROM P_Master
LEFT JOIN P_VISIT
ON P_Master.PID=P_VISIT.PID
WHERE P_Master.P_Name LIKE 'j%'

Resources