How do I merge 2 rows into 1 row in SQL? - sql

ReportDateTime EuId1 EuId2
2020-02-01 1:00 1576 Null
2020-02-01 1:00 Null 1579
2020-02-01 2:00 Null 1573
2020-02-01 2:00 1566 Null
This is what I have and this is what I want...
ReportDateTime EuId1 EuId2
2020-02-01 1:00 1576 1579
2020-02-01 2:00 1566 1573
Here is my code...
;WITH cteEq AS (
SELECT e.EntHID, e.EntCode, e.EntName
FROM cfEntity fac (NOLOCK)
JOIN cfEntityRelation er (NOLOCK) ON fac.EntHID = er.EntParentHID AND er.EntRelEffEnd = '12/31/2078'
JOIN cfEntity e (NOLOCK) ON er.EntChildHID = e.EntHID AND e.EntTypeTID = -200020
WHERE e.EntHID IN (SELECT ea.EaHID FROM cfEntityAttribute ea (NOLOCK) WHERE ea.EaKey = 'AirPermitXref_Diesel')
)
SELECT
ReportDateTime = a.EqReportDate
, EuId1 = CASE
WHEN EntName LIKE '%EU1%' THEN a.EqPwr
END
, EuId2 = CASE
WHEN EntName LIKE '%EU2%' THEN a.EqPwr
END
FROM eqHourlyAir a (NOLOCK)
JOIN cteEq e (NOLOCK) ON a.EqHID = e.EntHID
OUTER APPLY (
SELECT ad.EqHID, ad.EqReportDate, ad.EqRunTime
FROM eqHourlyAir ad (NOLOCK)
LEFT JOIN cfEntityAttribute ea (NOLOCK) ON ad.EqHID = CAST(ea.EaValue AS INT) AND ea.EaKey = 'AirPermitXref_DWI'
WHERE ea.EaHID = a.EqHID
AND ad.EqReportDate = a.EqReportDate
) dwi
OUTER APPLY (
SELECT ad.EqHID, ad.EqReportDate, ad.EqRunTime
FROM eqHourlyAir ad (NOLOCK)
LEFT JOIN cfEntityAttribute ea (NOLOCK) ON ad.EqHID = CAST(ea.EaValue AS INT) AND ea.EaKey = 'AirPermitXref_Diesel'
WHERE ea.EaHID = a.EqHID
AND ad.EqReportDate = a.EqReportDate
) dsl
WHERE CAST(a.EqReportDate AS DATE) >= #StartDate AND CAST(a.EqReportDate AS DATE) <= #EndDate
ORDER BY a.EqReportDate

using nolock hint is not the best idea !
if you have one null value and only one non value for each reportingdate you can grooup by ReportDateTime and get the max value :
...
SELECT
ReportDateTime = a.EqReportDate,
EuId1 = MAX(CASE WHEN EntName LIKE '%EU1%' THEN a.EqPwr END),
EuId2 = MAX(CASE WHEN EntName LIKE '%EU2%' THEN a.EqPwr END)
FROM
{...}
WHERE
CAST(a.EqReportDate AS DATE) >= #StartDate
AND CAST(a.EqReportDate AS DATE) <= #EndDate
GROUP BY a.EqReportDate
ORDER BY
a.EqReportDate

From you sample data it's very easy to select your desired result as below:
select ReportDateTime ,max(EuId1) EuId1,max(EuId2) EuId2 from
(select * from table1 join table2 on .... )t
group by ReportDateTime
But your query indicates that there is more to the story. Please share some more information.

Related

Join subquery and pull most recent date

I have two tables:
CLIENTS
ID NAME
001 John
002 Sara
CLIENT_STATUS
CLIENT_ID STATUS DATE
001 3 2018-01-02
001 2 2018-01-04
002 2 2018-01-02
002 1 2018-01-03
I want to filter by status = 1 and I just want the most recent date within the specified time frame.
I have this so far:
DECLARE
#StartDate DATE,
#EndDate DATE
SET #StartDate = '2016-07-01'
SET #EndDate = '2018-06-30'
SELECT
c.NAME
, c.ID
, cs.STATUS
FROM CLIENT c
LEFT JOIN (
SELECT cs.CLIENT_ID, cs.DATE
FROM CLIENT_STATUS
WHERE STATUS = 1 AND h.DATE BETWEEN #StartDate AND #EndDate
) AS hst ON hst.CLIENT_ID = c.ID
Only that doesn't Order by the most recent date.
Please note this is part of a larger query.
Left (or INNER) join with a sub-query that has row numbers:
SELECT *
FROM CLIENTS
LEFT JOIN (
SELECT *, ROW_NUMBER() OVER (PARTITION BY CLIENT_ID ORDER BY DATE DESC) AS rn
FROM CLIENT_STATUS
WHERE STATUS = 1
) RECENT_STATUS ON CLIENTS.ID = RECENT_STATUS.CLIENT_ID AND RECENT_STATUS.rn = 1
You can use row_number() function :
SELECT TOP (1) WITH TIES c.ID, c.NAME, cs.DATE
FROM CLIENT c INNER JOIN
CLIENT_STATUS cs
ON cs.CLIENT_ID = c.ID
WHERE cs.STATUS = 1 AND cs.DATE >= #StartDate AND cs.DATE <= #EndDate
ORDER BY ROW_NUMBER() OVER (PARTITION BY c.ID ORDER BY cs.DATE DESC);

SQL Join two tables by unrelated date

I’m looking to join two tables that do not have a common data point, but common value (date). I want a table that lists the date and total number of hired/terminated employees on that day. Example is below:
Table 1
Hire Date Employee Number Employee Name
--------------------------------------------
5/5/2018 10078 Joe
5/5/2018 10077 Adam
5/5/2018 10078 Steve
5/8/2018 10079 Jane
5/8/2018 10080 Mary
Table 2
Termination Date Employee Number Employee Name
----------------------------------------------------
5/5/2018 10010 Tony
5/6/2018 10025 Jonathan
5/6/2018 10035 Mark
5/8/2018 10052 Chris
5/9/2018 10037 Sam
Desired result:
Date Total Hired Total Terminated
--------------------------------------
5/5/2018 3 1
5/6/2018 0 2
5/7/2018 0 0
5/8/2018 2 1
5/9/2018 0 1
Getting the total count is easy, just unsure as the best approach from the standpoint of "adding" a date column
If you need all dates within some window then you need to join the data to a calendar. You can then left join and sum flags for data points.
DECLARE #StartDate DATETIME = (SELECT MIN(ActionDate) FROM(SELECT ActionDate = MIN(HireDate) FROM Table1 UNION SELECT ActionDate = MIN(TerminationDate) FROM Table2)AS X)
DECLARE #EndDate DATETIME = (SELECT MAX(ActionDate) FROM(SELECT ActionDate = MAX(HireDate) FROM Table1 UNION SELECT ActionDate = MAX(TerminationDate) FROM Table2)AS X)
;WITH AllDates AS
(
SELECT CalendarDate=#StartDate
UNION ALL
SELECT DATEADD(DAY, 1, CalendarDate)
FROM AllDates
WHERE DATEADD(DAY, 1, CalendarDate) <= #EndDate
)
SELECT
CalendarDate,
TotalHired = SUM(CASE WHEN H.HireDate IS NULL THEN NULL ELSE 1 END),
TotalTerminated = SUM(CASE WHEN T.TerminationDate IS NULL THEN NULL ELSE 1 END)
FROM
AllDates D
LEFT OUTER JOIN Table1 H ON H.HireDate = D.CalendarDate
LEFT OUTER JOIN Table2 T ON T.TerminationDate = D.CalendarDate
/* If you only want dates with data points then uncomment out the where clause
WHERE
NOT (H.HireDate IS NULL AND T.TerminationDate IS NULL)
*/
GROUP BY
CalendarDate
I would do this with a union all and aggregations:
select dte, sum(is_hired) as num_hired, sum(is_termed) as num_termed
from (select hiredate as dte, 1 as is_hired, 0 as is_termed from table1
union all
select terminationdate, 0 as is_hired, 1 as is_termed from table2
) ht
group by dte
order by dte;
This does not include the "missing" dates. If you want those, a calendar or recursive CTE works. For instance:
with ht as (
select dte, sum(is_hired) as num_hired, sum(is_termed) as num_termed
from (select hiredate as dte, 1 as is_hired, 0 as is_termed from table1
union all
select terminationdate, 0 as is_hired, 1 as is_termed from table2
) ht
group by dte
),
d as (
select min(dte) as dte, max(dte) as max_dte)
from ht
union all
select dateadd(day, 1, dte), max_dte
from d
where dte < max_dte
)
select d.dte, coalesce(ht.num_hired, 0) as num_hired, coalesce(ht.num_termed) as num_termed
from d left join
ht
on d.dte = ht.dte
order by dte;
Try this one
SELECT ISNULL(a.THE_DATE, b.THE_DATE) as Date,
ISNULL(a.Total_Hire,0) as Total_Hire,
ISNULL (b.Total_Terminate,0) as Total_terminate
FROM (SELECT Hire_date as the_date, COUNT(1) as Total_Hire
FROM TABLE_HIRE GROUP BY HIRE_DATE) a
FULL OUTER JOIN (SELECT Termination_Date as the_date, COUNT(1) as Total_Terminate
FROM TABLE_TERMINATE GROUP BY HIRE_DATE) a
ON a.the_date = b.the_date

Data according to time

I have table1 in this data is
ID Name StartDate EndDate
1 Paris 2014-02-01 00:00:00.000 2014-02-28 23:59:59.000
2 UK 2014-02-01 00:00:00.000 2014-02-28 23:59:59.000
3 France 2014-02-01 00:00:00.000 2014-02-28 23:59:59.000
and sp is
ALTER procedure [dbo].[spdata]
#fromdate datetime,
#todate datetime,
#Region varchar(50)
as
Select (Select Sum(Convert(int,SF)) from RVU inner dbo.VI vh on RVU.FID = vh.FID WHERE vh.No = Q.No and ID in (
Select ID from RU WHERE CAST(StartDate as date)>= CAST(#fromdate as date) and CAST(EndDate as date)<= CAST(#todate as date)
)) as SF
from (
Select
S.Name,
S.No,
SUM(Case when s.Vme='Car' then total else 0 end) as CAR,
SUM(Case when s.Vme='Tin' then total else 0 end) as Tin,
SUM(Case when s.Vme='Cake' then total else 0 end) as Cake,
SUM(Case when s.Vme='Flow' then total else 0 end) as Flow,
SUM(Case when s.Vme='Unit' then total else 0 end) as Unit,
SUM(total) total ,
MAX(S.Speed) Speed
from (
Select vh.Name as Name,vh.No as No,VV.Vame,count(VV.Vme) as total, RV.SF as MA,
RV.Speed from VVU VV inner join RVU RV on VV.MID=RV.ID inner join RU RU on RV.ID=RU.ID
left join dbo.VI vh on RV.FID = vh.FID WHERE CAST(RU.StartDate as date)>= CAST(#fromdate as date) and CAST(RU.EndDate as date)<= CAST(#todate as date) and
RU.Name_C= #Name_C AND Vme <> '' Group By vh.Name, vh.No, VV.Vme, RV.SF,
RV.Speed ) S GROUP BY s.RegNo, s.Name) Q
from that sp when i enter parameters DATA IS
[spdata] '2016-07-01 00:00:00.000', '2016-07-31 23:59:59.000', 'pARIS'
Name No CAR Tin Cake Flow Unit total Speed SF
John 412 0 0 12 0 5 17 82 60
Mike 48 2 1 5 1 3 9 160 464
ACNme 438 0 1 5 2 3 11 10 264
XYZ 248 0 1 5 3 3 12 60 244
now i want when i change time '2016-07-01 00:00:00.000', '2016-07-31 23:59:59.000',
like this
'2016-07-01 02:02:00.000', '2016-07-31 12:59:59.000',
then records also reflect on this time means according to date plus time data will be display
Don't cast your StartDate , EndDate , #fromdate , #todate as Date.
`Alter procedure [dbo].[spdata]
#fromdate datetime,
#todate datetime,
#Region varchar(50)
as
Select (Select Sum(Convert(int,SF)) from RVU inner dbo.VI vh on RVU.FID = vh.FID WHERE vh.No = Q.No and ID in (
Select ID from RU WHERE StartDate >= #fromdate and EndDate <=#todate
)) as SF
from (
Select
S.Name,
S.No,
SUM(Case when s.Vme='Car' then total else 0 end) as CAR,
SUM(Case when s.Vme='Tin' then total else 0 end) as Tin,
SUM(Case when s.Vme='Cake' then total else 0 end) as Cake,
SUM(Case when s.Vme='Flow' then total else 0 end) as Flow,
SUM(Case when s.Vme='Unit' then total else 0 end) as Unit,
SUM(total) total ,
MAX(S.Speed) Speed
from (
Select vh.Name as Name,vh.No as No,VV.Vame,count(VV.Vme) as total, RV.SF as MA,
RV.Speed from VVU VV inner join RVU RV on VV.MID=RV.ID inner join RU RU on RV.ID=RU.ID
left join dbo.VI vh on RV.FID = vh.FID WHERE RU.StartDate >= #fromdate and RU.EndDate <= #todate and
RU.Name_C= #Name_C AND Vme <> '' Group By vh.Name, vh.No, VV.Vme, RV.SF,
RV.Speed
) S GROUP BY s.RegNo, s.Name) Q`

How to modify my SQL to select values that match dates across different rows?

I have the following query (SQL Server):
select a.Booking_Type, b.Unit_Code, a.Start_Date, a.End_Date
from Booking a
inner join Property b
on a.Property_ID = b.Property_ID
where a.Agency_ID = 1020 and
b.IsEnabled = 1 and
a.Hold_Agreement_Signed is null and
(convert(varchar(10), a.Start_Date, 102) = convert(varchar(10), getdate(), 102) or convert(varchar(10), a.End_Date, 102) = convert(varchar(10), getdate()-1, 102))
my results from this query look like:
Booking_Type Unit_Code Start_Date End_Date
0 448 2014-09-22 00:00:00 2014-09-28 00:00:00
0 448 2014-09-21 05:00:00 2014-09-21 05:00:00
0 K187 2014-09-19 00:00:00 2014-09-21 00:00:00
0 K187 2014-09-18 00:00:00 2014-09-21 00:00:00
What I am looking to get is a single row with Unit_Code = 448 because it has a row with a Start_Date of today and a row with an End_Date of yesterday (there was a checkout yesterday and a checkin today).
How do I modify my query to obtain this?
you will need to join a second instance of Booking:
select a.Booking_Type, b.Unit_Code, a.Start_Date, a.End_Date
from Booking inner join Property b a.Property_ID = b.Property_ID
inner join Booking b1
on a.Property_ID = b1.Property_ID
and convert your where condition from OR to AND
... convert(varchar(10), a.Start_Date, 102) = convert(varchar(10), getdate(), 102)
**AND**
convert(varchar(10), **B1**.End_Date, 102) = convert(varchar(10), getdate()-1, 102))
If you just want to return the Unit_Code that meets your date criteria, you should use HAVING:
select b.Unit_Code
from Booking a
inner join Property b
on a.Property_ID = b.Property_ID
where a.Agency_ID = 1020
and b.IsEnabled = 1
and a.Hold_Agreement_Signed is null
GROUP BY b.Unit_Code
HAVING MAX(CASE WHEN CAST(a.Start_Date AS DATE) = CAST(GETDATE() AS DATE) THEN 1 END) = 1
AND MAX(CASE WHEN CAST(a.End_Date AS DATE) = CAST(GETDATE()-1 AS DATE) THEN 1 END) = 1

Get multiple rows from query

SELECT USERINFO.UserID
,SUM(DATEDIFF(DAY, DateFrom, DateTo) + 1) AS total_leave_days
FROM USERINFO
INNER JOIN CHECKINOUT ON USERINFO.USERID = CHECKINOUT.USERID
LEFT OUTER JOIN DEPARTMENTS ON DEPARTMENTS.DEPTID = USERINFO.DEFAULTDEPTID
left join AuthLeave on AuthLeave.userid = userinfo.userid
and AuthLeave.DATEFROM>='2014-01-01'
and AuthLeave.DATETO<='2014-06-30'
WHERE (CHECKINOUT.CHECKTIME >= '2014-01-01')
AND (CHECKINOUT.CHECKTIME <= '2014-06-30')
AND DEPARTMENTS.DEPTNAME = 'GEN/SUP-TBL'
GROUP BY USERINFO.UserID
here is my code from this i can get below out put
UserID total_leave_days
35 NULL
350 NULL
30 NULL
10 735
167 NULL
21 920
1 621
224 NULL
so it is not correct my Authleave table data is below:
UserID DATEFROM DATETO
1 2014-03-10 2014-03-15
10 2014-05-28 2014-05-29
21 2014-05-27 2014-05-27
1 2014-04-10 2014-04-15
from now i want output like below:
UserID total_leave_days
35 NULL
350 NULL
30 NULL
10 2
167 NULL
21 1
1 12
224 NULL
so how can i do this ?
Can you try This SQL
SELECT U.[UserID],
C.[Leave]
FROM [USERINFO] U
LEFT JOIN (SELECT [UserID],
SUM(DATEDIFF(DAY,[DATEFROM],[DATETO])) [Leave]
FROM [CHECKINOUT]
WHERE [CHECKTIME] >= '2014-01-01' AND [CHECKTIME] <= '2014-06-30'
GROUP BY [UserID]
) C ON U.[USERID] = C.[USERID]
LEFT JOIN [DEPARTMENTS] D ON D.[DEPTID] = U.[DEFAULTDEPTID]
LEFT JOIN [AuthLeave] A on A.[userid] = U.[userid]
WHERE D.[DEPTNAME] = 'GEN/SUP-TBL'
enter code here
Edit:
See the below SQL, I got a bit confused by Table Names.
SELECT U.[UserID],
L.[Leave]
FROM [USERINFO] U
JOIN CHECKINOUT C ON U.USERID = C.USERID
LEFT JOIN [DEPARTMENTS] D ON D.[DEPTID] = U.[DEFAULTDEPTID]
LEFT JOIN (SELECT [UserID],
SUM(DATEDIFF(DAY,[DATEFROM],[DATETO])) [Leave]
FROM [AuthLeave]
WHERE [DATEFROM] >= '2014-01-01' AND [DATETO] <= '2014-06-30'
GROUP BY [UserID]
) L ON L.[UserID] =U.[UserID]
WHERE D.[DEPTNAME] = 'GEN/SUP-TBL'
AND C.[CHECKTIME] >= '2014-01-01' AND C.[CHECKTIME] <= '2014-06-30'