Fetch the record from multiple records based on string column - sql

I have a table as follows:
I need to create a query so that I can get the below result (only the highlighted records):
I have tried using something like below but still getting all the records and not only the highlighted ones.
Select EmpPk as [User EmpPK],
Activity_PK as [Activity PK],
Attempt_Start_Date as [Attempt Start Date],
Attempt_Completion_Date as [Attempt Completion Date],
Registration_Status as [Registration Status],
Attendance_Status as [Attendance Status],
EstCrdHrs
From Employee_Activity
Where ((Attendance_Status='In Progress' AND Registration_Status ='In Progress')
OR (Attendance_Status='Attended' AND Registration_Status ='Completed'))

You did not precisely describe the logic that you are looking to implement.
I understand that, for each EmpPk, you want records where attendance_status = 'Attended' and registration_status = 'Completed'; if there is no such record, then you want all other records.
If so, you could phrase this with not exists:
select t.*
from employee_activity ea
where
(
ea.attendance_status = 'Attended'
and ea.registration_status = 'Completed'
) or not exists (
select 1
from employee_activity ea1
where
ea1.empPk = ea.empPk
and ea1.attendance_status = 'Attended'
and ea1.registration_status = 'Completed'
)
You could also use window functions:
select *
from (
select
t.*,
rank() over(
partition by empPk
order by case when attendance_status = 'Attended' and registration_status = 'Completed' then 1 else 2 end
) rn
from employee_activity
) t
where rn = 1
The order by clause of window function rank() puts the "completed" record of each employee first; then the outer query filter on top ranked record(s) per employee (if there is no "complete" record, then all other records of the same customer will be ranked first).

Related

SQL - Flag rows till 0 value of each group

I am calculating a running balance and want to flag all rows till 0 value to have 'MATCHED' flag else 'NOT-MATCHED' flag with respect to account ID.
Here is what I have tried but didn't got proper result:
SEL a.*,
CASE WHEN RUNNING_BALANCE OVER (PARTITION BY ACCT_SROGT_ID ROWS UNBOUNDED PRECEDING ) = 0 THEN 'M' ELSE 'NM' END R
FROM NON_MATCHING_RUNNING_BALANCE a
We can use a sub-query to find the last acct_rank which is 0 and then use case to test each row.
Select
a.*,
Case when a.acct_rank > z.last_zero
Then 'unmatched' else 'matched'
End as is_matched
From accounts a
Join ( select
account_id as id,
MAX(acct_rank) last_zero
From accounts
Where running_balance = 0
Group by account_id) z
On a.account_id = z.id;
Check this one
WITH SUB AS (
select NON_MATCHING_RUNNING_BALANCE.*,row_number()over(partition by [Account ID] order by [Account ID]) RN from NON_MATCHING_RUNNING_BALANCE
)
SELECT SUB.*,CASE WHEN SUB.RN<=SUB2.RN AND SUB.[Account ID]=SUB2.[Account ID] THEN 'MATCHED' ELSE 'Not-Matched' END AS 'MATCH' FROM SUB LEFT JOIN (
SELECT * FROM SUB WHERE value=0 ) SUB2 ON SUB.[Account ID]=SUB2.[Account ID]

Oracle SQL -- Pick Max Value from RN Function but update all fields with that value

My query is as follows
SELECT HEADER_TABLE.SEGMENT1,
LINES_TABLE.LINE_NUM,
CASE
WHEN ( HEADER_TABLE.REVISION_NUM = '0'
AND HEADER_TABLE.PRINT_COUNT = '0')
THEN
'Unavailable'
ELSE
NVL (ACK_TABLE.ACK_TYPE, 'Absent')
END
AS X_ACK_TYPE,
ACK_TABLE.GXS_DATE
FROM HEADER_TABLE,
LINES_TABLE,
(SELECT po_number,
po_line_number,
gxs_date,
po_ack_filename,
ack_type
FROM (SELECT po_number,
po_line_number,
gxs_date,
po_ack_filename,
ack_type,
ROW_NUMBER ()
OVER (PARTITION BY po_number ORDER BY gxs_date DESC)
rn
FROM xxcmst_po_ack_from_gxs_stg)
WHERE rn = 1) ACK_TABLE,
(SELECT PO_NUMBER FROM XXCMST.XXCMST_ACTION_TABLE_ACKNOWLEDGEMENT) ACTION_TABLE
WHERE HEADER_TABLE.PO_HEADER_ID = LINES_TABLE.PO_HEADER_ID
AND HEADER_TABLE.SEGMENT1 = ACK_TABLE.PO_NUMBER(+)
AND HEADER_TABLE.SEGMENT1 = ACTION_TABLE.PO_NUMBER(+)
AND LINES_TABLE.LINE_NUM = ACK_TABLE.PO_LINE_NUMBER(+)
AND HEADER_TABLE.SEGMENT1 = '100';
This is giving me 6 records with 1 GXS_DATE and X_ACK_TYPE = 'Absent'. The RN function is needed here to pull 1 record only from the subquery but the requirement is to have all the 6 records have the same date and ACK_TYPE which is not happening. How can I achieve this? Please refer to the below screenshot and I need X_ACK_TYPE = AK for all the 6 LINE_NUMs and GXS_DATE = 3/6/2020 for all these 6 records.
My current data screenshot here
Instead of
ACK_TABLE.GXS_DATE
in SELECT clause use the LAG function as follows:
CASE WHEN ACK_TABLE.GXS_DATE IS NOT NULL
THEN ACK_TABLE.GXS_DATE
ELSE LAG(ACK_TABLE.GXS_DATE IGNORE NULLS)
OVER (PARTITION BY HEADER_TABLE.SEGMENT1 ORDER BY LINES_TABLE.LINE_NUM )
END AS GXS_DATE
or If there will be always one value of ACK_TABLE.GXS_DATE exists per HEADER_TABLE.SEGMENT1 then you can simply write it as
MIN(ACK_TABLE.GXS_DATE)
OVER (PARTITION BY HEADER_TABLE.SEGMENT1) AS GXS_DATE
-- Update --
for ACK_TYPE, You need to apply the same logic in ELSE portion of your CASE statement from the original query as follows:
Replace this:
ELSE
NVL (ACK_TABLE.ACK_TYPE, 'Absent')
END
With this:
ELSE
NVL (MIN(ACK_TABLE.ACK_TYPE)
OVER (PARTITION BY HEADER_TABLE.SEGMENT1), 'Absent')
END

How to get first and last record in HiveSQL if key is different

I need to get the first and last record for a user if one of the key fields is different over time using a Hive table:
This is some sample data:
UserID EntryDate Activity
a3324 1/1/16 walk
a3324 1/2/16 walk
a3324 1/3/16 walk
a3324 1/4/16 run
a5613 1/1/16 walk
a5613 1/2/16 walk
a5613 1/3/16 walk
a5613 1/4/16 walk
And I'm looking for output preferably like this:
a3324 1/1/16 walk 1/4/16 run
Or at least like this:
a3324 walk run
I start writing code like this:
SELECT UserID, MINIMUM(EntryDate), MAXIMUM(EntryDate), Activity
FROM
SELECT UserID, DISTINCT Activity
GROUP BY UserID
HAVING Count(Activity) > 1
But I know that's not it.
I'd also like to be able to specify the cases where the original activity was Walk and the second activity was Run perhaps in the Where clause.
Can you help with an approach?
Thanks
You can use lag /lead to get a solution
SELECT * FROM (
select UserID ,EntryDate , Activityslec,
lead(Activityslec, 1) over (UserID ,EntryDate ) as nextActivityslec
from table) as A
where Activityslec <> nextActivityslec
SELECT
t.UserId
,MIN(CASE WHEN t.RowNumAsc = 1 THEN t.EntryDate END) as MinEntryDate
,MIN(CASE WHEN t.RowNumAsc = 1 THEN t.Activity END) as MinActivity
,MAX(CASE WHEN t.RowNumDesc = 1 THEN t.EntryDate END) as MaxEntryDate
,MAX(CASE WHEN t.RowNumDesc = 1 THEN t.Activity END) as MaxActivity
FROM
(
SELECT
UserId
,EntryDate
,Activity
,ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY EntryDate) as RowNumAsc
,ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY EntryDate DESC) as RowNumDesc
FROM
Table
) t
WHERE
t.RowNumAsc = 1
OR t.RowNumDesc = 1
GROUP BY
t.UserId
Looks like window functions are supported (https://cwiki.apache.org/confluence/display/Hive/LanguageManual+WindowingAndAnalytics) so using 2 row numbers 1 for EntryDate Ascending and another for Descending with Conditional Aggregation should get you to the answer.
And if you don't want to use Analytic Functions (window functions) you can use self left joins and conditional aggregation:
SELECT
t.UserId
,MIN(CASE WHEN mn.UserId IS NULL THEN t.EntryDate END) as MinEntryDate
,MIN(CASE WHEN mn.UserId IS NULL THEN t.Activity END) as MinActivity
,MAX(CASE WHEN mx.UserId IS NULL THEN t.EntryDate END) as MaxEntryDate
,MAX(CASE WHEN mx.UserId IS NULL THEN t.Activity END) as MaxActivity
FROM
Table t
LEFT JOIN Table mn
ON t.UserId = mn.UserId
AND t.EntryDate > mn.EntryDate
LEFT JOIN Table mx
ON t.UserId = mx.UserId
AND t.EntryDate < mx.EntryDate
WHERE
mn.UserId IS NULL
OR mx.UserId IS NULL
GROUP BY
t.UserId
Or a correlated Sub Query way:
SELECT
UserId
,MIN(EntryDate) as MinEntryDate
,(SELECT
Activity
FROM
Activity a
WHERE
u.UserId = a.UserId
AND a.EntryDate = MIN(u.EntryDate)
LIMIT 1
) as MinActivity
,MAX(EntryDate) as MaxEntryDate
,(SELECT
Activity
FROM
Activity a
WHERE
u.UserId = a.UserId
AND a.EntryDate = MAX(u.EntryDate)
LIMIT 1
) as MaxActivity
FROM
Activity u
GROUP BY
UserId

ORACLE SQL Returning most recently added record detail

Edit: Solved with a lot of help from Dems, I will post a truncated version of the query which is now working very well!
SELECT
*
FROM
O_PERSONS
/*The below left join returns the most recently added ethnicity classification*/
LEFT JOIN
(SELECT
ROW_NUMBER() OVER (PARTITION BY O_CLASSIFICATIONS.CLA_SUBJECT_ID ORDER BY O_CLASSIFICATIONS.CLA_DATE_NOTIFIED DESC) AS Sequence_ID,
O_CLASSIFICATIONS.CLA_CAT_ID,
O_CLASSIFICATIONS.CLA_SUBJECT_ID
FROM
O_CLASSIFICATIONS
WHERE
O_CLASSIFICATIONS.CLA_SUBJECT_IND = 'P'
AND
O_CLASSIFICATIONS.CLA_TOP_CAT_ID = 'ETHNIC'
AND
O_CLASSIFICATIONS.CLA_CAT_ID <> 'DECLINED'
) ETHNIC
ON ETHNIC.CLA_SUBJECT_ID = O_PERSONS.PER_ID
AND ETHNIC.Sequence_ID = 1
/*The below left join returns the most recently added PCG classification*/
LEFT JOIN
(SELECT
ROW_NUMBER() OVER (PARTITION BY O_CLASSIFICATIONS.CLA_SUBJECT_ID ORDER BY O_CLASSIFICATIONS.CLA_DATE_NOTIFIED DESC) AS Sequence_ID,
O_CLASSIFICATIONS.CLA_CAT_ID,
O_CLASSIFICATIONS.CLA_SUBJECT_ID
FROM
O_CLASSIFICATIONS
WHERE
O_CLASSIFICATIONS.CLA_SUBJECT_IND = 'P'
AND
O_CLASSIFICATIONS.CLA_TOP_CAT_ID = 'PRIMARY'
AND
O_CLASSIFICATIONS.CLA_CAT_ID <> 'DECLINED'
) PCG
ON PCG.CLA_SUBJECT_ID = O_PERSONS.PER_ID
AND PCG.Sequence_ID = 1
WHERE
O_PERSONS.PER_ID LIKE 'P%'
I am currently trying to write a query which will return certain details for clients on our system. Whilst a client will only have one date of birth, gender, and P ID, they may have multiple ethnicities (as a result of data quality) and also client groups (this is more legitimate as a client's needs may change). However, for these particular items, I am only interested in the most recently added ethnicities or client groups. Below I have written a query which assigns a row number to the ethnicity and to the client group with a plan to return only those which equal 1, as these generally will be the most recent. However, I have run into 2 issues, one of which I can resolve, the other of which I'm not so sure.
First off, some clients will not have an ethnicity or a client group recorded. When running the below query, they return with very odd row numbers (often in the thousands). However, I know in my 'where' that I could specify that a row is returned if client group or ethnicity was empty (as these will be data quality cases which need to be addressed).
The second issue is slightly trickier which I will try to represent with a table below. Please note I have abbreviated the table for ease of input and understanding.
P ID Ethnicity PCG RN E RN P
P1 WB OV 1 2
P1 WI OV 2 1
The above client had two ethnicities, though WB is the most recent (therefore the 1 in Row Number E is correct). However, the client has only had one PCG recorded but the row number returns a 2 in the first row (arguably the row I want to return). I'm not sure why though I guess because ETHNIC.CLA_SUBJECT_ID is joined on O_PERSONS.PER_ID and PER_ID occurs twice, that is why it thinks there is two rows for that particular field. However, even if that is the case, is there a way to force just 1's to appear in one row? Or could I do this a completely different way? Hopefully this query makes some sense, apologies if parts are unclear. Thanks,
SELECT
O_PERSONS.PER_ID as "P ID",
olm_bo.get_per_name(O_PERSONS.PER_ID) as "Full Name",
O_PERSONS.PER_BIRTH_DATE as "Date of Birth",
case
when O_PERSONS.PER_DECEASED_DATE is null then FLOOR(MONTHS_BETWEEN(sysdate,O_PERSONS.PER_BIRTH_DATE)/12)
else FLOOR(MONTHS_BETWEEN(O_PERSONS.PER_DECEASED_DATE,O_PERSONS.PER_BIRTH_DATE)/12)
end as "Age",
O_PERSONS.PER_DECEASED_DATE as "Date Deceased",
olm_bo.get_gender_desc('P', O_PERSONS.PER_GENDER) as "Gender",
CASE
WHEN ETHNIC.CLA_CAT_ID IN ('C1','C2','C3','C4','ABAN','AIND','AOTH','APKN') THEN 'Asian or Asian British'
ELSE NULL
End as "Ethnicity - Top" ,
CASE
WHEN ETHNIC.CLA_CAT_ID IN ('BAFR','D2') THEN 'African'
ELSE NULL
End as "Ethnicity - Detail" ,
CASE
WHEN PCG.CLA_CAT_ID IN ('ASYLUM','REFUGEE') THEN 'Asylum Seeker/Refugee'
ELSE NULL
End as "PCG",
CASE
WHEN PCG.CLA_CAT_ID IN ('ASYLUM','REFUGEE') THEN 'Asylum Seeker/Refugee'
ELSE NULL
End as "PCG - Top",
CASE
WHEN PCG.CLA_CAT_ID IN ('ASYLUM','REFUGEE') THEN 'Asylum Seeker/Refugee'
ELSE NULL
End as "PCG - DETAIL",
to_char(row_number() over(PARTITION BY ETHNIC.CLA_SUBJECT_ID ORDER BY abs(sysdate - ETHNIC.CLA_DATE_NOTIFIED) asc)) as "Row Number E",
to_char(row_number() over(PARTITION BY PCG.CLA_SUBJECT_ID ORDER BY abs(sysdate - PCG.CLA_DATE_NOTIFIED) asc))as "Row Number P"
FROM
O_PERSONS
LEFT JOIN O_CLASSIFICATIONS ETHNIC ON ETHNIC.CLA_SUBJECT_ID = O_PERSONS.PER_ID
AND ETHNIC.CLA_SUBJECT_IND = 'P'
AND ETHNIC.CLA_TOP_CAT_ID = 'ETHNIC'
AND ETHNIC.CLA_CAT_ID <> 'DECLINED'
LEFT JOIN O_CLASSIFICATIONS PCG ON PCG.CLA_SUBJECT_ID = O_PERSONS.PER_ID
AND PCG.CLA_SUBJECT_IND = 'P'
AND PCG.CLA_TOP_CAT_ID = 'PRIMARY'
AND PCG.CLA_CAT_ID <> 'DECLINED'
WHERE
/*Following line excludes any clients whose is less than 18)*/
O_PERSONS.PER_BIRTH_DATE > trunc(add_months(O_PERSONS.PER_BIRTH_DATE,-216))
AND O_PERSONS.PER_ID LIKE 'P%'
You should apply ROW_NUMBER() before you do the joins.
SELECT
* -- Your calculations here, '*' used for brevity
FROM
O_PERSONS
LEFT JOIN
(
SELECT
ROW_NUMBER() OVER (PARTITION BY CLA_SUBJECT_ID ORDER BY CLA_DATE_NOTIFIED DESC) AS sequence_id,
*
FROM
O_CLASSIFICATIONS
WHERE
CLA_SUBJECT_IND = 'P'
AND CLA_TOP_CAT_ID = 'ETHNIC'
AND CLA_CAT_ID <> 'DECLINED'
)
ETHNIC
ON ETHNIC.CLA_SUBJECT_ID = O_PERSONS.PER_ID
AND ETHNIC.sequence_id = 1
LEFT JOIN
(
SELECT
ROW_NUMBER() OVER (PARTITION BY CLA_SUBJECT_ID ORDER BY CLA_DATE_NOTIFIED DESC) AS sequence_id,
*
FROM
O_CLASSIFICATIONS
WHERE
CLA_SUBJECT_IND = 'P'
AND CLA_TOP_CAT_ID = 'PRIMARY'
AND CLA_CAT_ID <> 'DECLINED'
)
PCG
ON PCG.CLA_SUBJECT_ID = O_PERSONS.PER_ID
AND PCG.sequence_id = 1
WHERE
/*Following line excludes any clients whose is less than 18)*/
O_PERSONS.PER_BIRTH_DATE > trunc(add_months(O_PERSONS.PER_BIRTH_DATE,-216))
AND O_PERSONS.PER_ID LIKE 'P%'

SQL Optimize - From History table get value from two different dates

Not sure where to start... But basically I have a report table, an account table, and an account history table. The account history table will have zero or more records, where each record is the state of the account cancelled flag after it changed.
There is other stuff going on, but basically i am looking to return the account detail data, with the state of account cancelled bit on the start date and enddate as different columns.
What is the best way to do this?
I have the following working query below
(Idea) Should I do seperate joins on history table, 1 for each date?
I guess I could do it in three separate queries ( Get Begin Snapshot, End Snapshot, Normal Report query with a join to each snapshot)
something else?
Expected output:
AccountID, OtherData, StartDateCancelled, EndDateCancelled
Test Tables:
DECLARE #Report TABLE (ReportID INT, StartDate DATETIME, EndDate DATETIME)
DECLARE #ReportAccountDetail TABLE( ReportID INT, Accountid INT, Cancelled BIT )
DECLARE #AccountHistory TABLE( AccountID INT, ModifiedDate DATETIME, Cancelled BIT )
INSERT INTO #Report
SELECT 1,'1/1/2011', '2/1/2011'
--
INSERT INTO #ReportAccountDetail
SELECT 1 AS ReportID, 1 AS AccountID, 0 AS Cancelled
UNION
SELECT 1,2,0
UNION
SELECT 1,3,1
UNION
SELECT 1,4,1
--
INSERT INTO #AccountHistory
SELECT 2 AS CustomerID, '1/2/2010' AS ModifiedDate, 1 AS Cancelled
UNION--
SELECT 3, '2/1/2011', 1
UNION--
SELECT 4, '1/1/2010', 1
UNION
SELECT 4, '2/1/2010', 0
UNION
SELECT 4, '2/1/2011', 1
Current Query:
SELECT Accountid, OtherData,
MAX(CASE WHEN BeginRank = 1 THEN CASE WHEN BeginHistoryExists = 1 THEN HistoryCancelled ELSE DefaultCancel END ELSE NULL END ) AS StartDateCancelled,
MAX(CASE WHEN EndRank = 1 THEN CASE WHEN EndHistoryExists = 1 THEN HistoryCancelled ELSE DefaultCancel END ELSE NULL END ) AS EndDateCancelled
FROM
(
SELECT c.Accountid,
'OtherData' AS OtherData,
--lots of other data
ROW_NUMBER() OVER (PARTITION BY c.AccountID ORDER BY
CASE WHEN ch.ModifiedDate <= Report.StartDate THEN 1 ELSE 0 END DESC, ch.ModifiedDate desc) AS BeginRank,
CASE WHEN ch.ModifiedDate <= Report.StartDate THEN 1 ELSE 0 END AS BeginHistoryExists,
ROW_NUMBER() OVER ( PARTITION BY c.AccountID ORDER BY
CASE WHEN ch.ModifiedDate <= Report.EndDate THEN 1 ELSE 0 END DESC, ch.ModifiedDate desc) AS EndRank,
CASE WHEN ch.ModifiedDate <= Report.EndDate THEN 1 ELSE 0 END AS EndHistoryExists,
CAST( ch.Cancelled AS INT) AS HistoryCancelled,
0 AS DefaultCancel
FROM
#Report AS Report
INNER JOIN #ReportAccountDetail AS C ON Report.ReportID = C.ReportID
--Others joins related for data to return
LEFT JOIN #AccountHistory AS CH ON CH.AccountID = C.AccountID
WHERE Report.ReportID = 1
) AS x
GROUP BY AccountID, OtherData
Welcome input on writing stack overflow questions. Thanks!
ROW_NUMBER() often suprises me and out-performs my expectations. In this case, however, I'd be tempted to just use correlated sub-queries. At least, I'd test them against the alternatives.
Note: I would also use real tables, with real indexes, and a realistic volume of fake data. (If it's worth posting this question, I'm assuming that it's worth testing this realistically.)
SELECT
[Report].ReportID,
[Account].AccountID,
[Account].OtherData,
ISNULL((SELECT TOP 1 Cancelled FROM AccountHistory WHERE AccountID = [Account].AccountID AND ModifiedDate <= [Report].StartDate ORDER BY ModifiedDate DESC), 0) AS StartDateCancelled,
ISNULL((SELECT TOP 1 Cancelled FROM AccountHistory WHERE AccountID = [Account].AccountID AND ModifiedDate <= [Report].EndDate ORDER BY ModifiedDate DESC), 0) AS EndDateCancelled
FROM
Report AS [Report]
LEFT JOIN
ReportAccountDetail AS [Account]
ON [Account].ReportID = [Report].ReportID
ORDER BY
[Report].ReportID,
[Account].AccountID
Note: For whatever reason, I've found that TOP 1 and ORDER BY is faster than MAX().
In terms of your suggested answer, I'd modify it slightly to just use ISNULL instead of trying to make the Exists columns work.
I'd also join on the "other data" after all of the working out, rather than inside the inner-most query, so as to avoid having to group by all the "other data".
WITH
HistoricData AS
(
SELECT
Report.ReportID,
c.Accountid,
c.OtherData,
ROW_NUMBER() OVER (PARTITION BY c.ReportID, c.AccountID ORDER BY CASE WHEN ch.ModifiedDate <= Report.StartDate THEN 1 ELSE 0 END DESC, ch.ModifiedDate DESC) AS BeginRank,
ROW_NUMBER() OVER (PARTITION BY c.ReportID, c.AccountID ORDER BY ch.ModifiedDate DESC) AS EndRank,
CH.Cancelled
FROM
#Report AS Report
INNER JOIN
#ReportAccountDetail AS C
ON Report.ReportID = C.ReportID
LEFT JOIN
#AccountHistory AS CH
ON CH.AccountID = C.AccountID
AND CH.ModifiedDate <= Report.EndDate
)
,
FlattenedData AS
(
SELECT
ReportID,
Accountid,
OtherData,
ISNULL(MAX(CASE WHEN BeginRank = 1 THEN Cancelled END), 0) AS StartDateCancelled,
ISNULL(MAX(CASE WHEN EndRank = 1 THEN Cancelled END), 0) AS EndDateCancelled
FROM
[HistoricData]
GROUP BY
ReportID,
AccountID,
OtherData
)
SELECT
*
FROM
[FlattenedData]
LEFT JOIN
[OtherData]
ON Whatever = YouLike
WHERE
[FlattenedData].ReportID = 1
And a final possible version...
WITH
ReportStartHistory AS
(
SELECT
*
FROM
(
SELECT
[Report].ReportID,
ROW_NUMBER() OVER (PARTITION BY [Report].ReportID, [History].AccountID ORDER BY [History].ModifiedDate) AS SequenceID,
[History].*
FROM
Report AS [Report]
INNER JOIN
AccountHistory AS [History]
ON [History].ModifiedDate <= [Report].StartDate
)
AS [data]
WHERE
SequenceID = 1
)
,
ReportEndHistory AS
(
SELECT
*
FROM
(
SELECT
[Report].ReportID,
ROW_NUMBER() OVER (PARTITION BY [Report].ReportID, [History].AccountID ORDER BY [History].ModifiedDate) AS SequenceID,
[History].*
FROM
Report AS [Report]
INNER JOIN
AccountHistory AS [History]
ON [History].ModifiedDate <= [Report].EndDate
)
AS [data]
WHERE
SequenceID = 1
)
SELECT
[Report].ReportID,
[Account].*,
ISNULL([ReportStartHistory].Cancelled, 0) AS StartDateCancelled,
ISNULL([ReportEndHistory].Cancelled, 0) AS EndDateCancelled
FROM
Report AS [Report]
INNER JOIN
Account AS [Account]
LEFT JOIN
[ReportStartHistory]
ON [ReportStartHistory].ReportID = [Report].ReportID
AND [ReportStartHistory].AccountID = [Account].AccountID
LEFT JOIN
[ReportEndHistory]
ON [ReportEndHistory].ReportID = [Report].ReportID
AND [ReportEndHistory].AccountID = [Account].AccountID