Select Latest or most recent date in SQL query - sql

I am running a query in SQL on our EHR/EMR database. I am primarily looking at an assessment that is done by a nurse during each patient encounter/visit and looking to return an answer for the most recent assessment date along with some other info. I have the query created and all the data is coming over, however, it is returning all assessment dates and the answers instead of just the latest date and answer. I'll attach the full code below.
SELECT DISTINCT
MAX(PTA.ASSESSMENT_DATE) AS Max_Date,
SAQ.QUESTION_TEXT, SAA.ANSWER_TEXT, dbo.PT_BASIC.PATIENT_CODE,
dbo.PT_BASIC.NAME_FULL
FROM
dbo.PTC_ASSESSMENT_ANSWER AS PAA
INNER JOIN
dbo.PTC_ASSESSMENT AS PTA ON PTA.ASSESSMENT_ID = PAA.ASSESSMENT_ID
AND PTA.PATIENT_ID = PAA.PATIENT_ID
INNER JOIN
dbo.SYS_ASSESSMENT_POINTER AS SAP ON SAP.POINTER_ID = PAA.POINTER_ID
INNER JOIN
dbo.SYS_ASSESSMENT_QUESTION AS SAQ ON SAQ.QUESTION_ID = SAP.QUESTION_ID
INNER JOIN
dbo.SYS_ASSESSMENT_ANSWER AS SAA ON SAA.ANSWER_ID = SAP.ANSWER_ID
INNER JOIN
dbo.PT_BASIC ON PTA.PATIENT_ID = dbo.PT_BASIC.PATIENT_ID
WHERE
(PTA.ASSESSMENT_DATE BETWEEN CONVERT(DATETIME, '2017-09-05 00:00:00', 102)
AND CONVERT(DATETIME, '2017-10-12 00:00:00', 102))
GROUP BY
dbo.PT_BASIC.PATIENT_CODE, dbo.PT_BASIC.NAME_FULL, SAQ.QUESTION_TEXT,
SAA.ANSWER_TEXT
HAVING
(SAA.ANSWER_TEXT LIKE '%LEVEL % -%')
The current output would be something similar to this:
9/5/2017 PATIENT ABC Answer1
9/6/2017 PATIENT ABC Answer2
9/7/2017 PATIENT ABC Answer3
9/6/2017 PATIENT XYZ Answer4
What I am expecting is:
9/7/2017 PATIENT ABC Answer3
9/6/2017 PATIENT XYZ Answer4

If your version of SQL Server supports it, using ROW_NUMBER() OVER() is an efficient and simple method for arriving at "latest" (or "earliest") rows from a single table. However as we know so little about your data model it isn't easy to guess how to reduce the rows to just the "lastest answer" which probably requires a more complex subquery. However you can still use ROW_NUMBER() OVER() on that subquery. I suspect that the nature of questions and answers is that the table aliases SAP, SAQ, SAA may all need to be involved in this subquery.
Note that instead of directly joining PTA this is now a subquery and the join condition to the outer query requires that RN=1 which is the row with the "latest" date.
SELECT
MAX(PTA.ASSESSMENT_DATE) AS Max_Date
, SAQ.QUESTION_TEXT
, SAA.ANSWER_TEXT
, dbo.PT_BASIC.PATIENT_CODE
, dbo.PT_BASIC.NAME_FULL
FROM dbo.PTC_ASSESSMENT_ANSWER AS PAA
INNER JOIN (
SELECT
*
, ROW_NUMBER() OVER (PARTITION BY PATIENT_ID
ORDER BY ASSESSMENT_DATE DESC) AS RN
FROM dbo.PTC_ASSESSMENT
WHERE ASSESSMENT_DATE BETWEEN '20170905' AND '20171012'
) AS PTA ON PTA.ASSESSMENT_ID = PAA.ASSESSMENT_ID
AND PTA.PATIENT_ID = PAA.PATIENT_ID
AND PTA.RN = 1
INNER JOIN dbo.SYS_ASSESSMENT_POINTER AS SAP ON SAP.POINTER_ID = PAA.POINTER_ID
INNER JOIN dbo.SYS_ASSESSMENT_QUESTION AS SAQ ON SAQ.QUESTION_ID = SAP.QUESTION_ID
INNER JOIN dbo.SYS_ASSESSMENT_ANSWER AS SAA ON SAA.ANSWER_ID = SAP.ANSWER_ID
INNER JOIN dbo.PT_BASIC ON PTA.PATIENT_ID = dbo.PT_BASIC.PATIENT_ID
WHERE SAA.ANSWER_TEXT LIKE '%LEVEL % -%'
GROUP BY
dbo.PT_BASIC.PATIENT_CODE
, dbo.PT_BASIC.NAME_FULL
, SAQ.QUESTION_TEXT
, SAA.ANSWER_TEXT
select distinct is not required on this query (or any similar query using GROUP BY)
yyymmdd is the safest date literal in SQL Server, you don't need the converts using style 102
your having clause should be moved to a where clause as it does not evaluate any aggregated value

Cross apply allows you to use a correlated query and chive the top most n records ordered by date desc for each patient assessment. (after review maybe you just need patient?)
Perhaps just change:
INNER JOIN
dbo.PTC_ASSESSMENT AS PTA ON PTA.ASSESSMENT_ID = PAA.ASSESSMENT_ID
AND PTA.PATIENT_ID = PAA.PATIENT_ID
TO:
CROSS APPLY (SELECT TOP 1 *
FROM dbo.PTC_ASSESSMENT PTA2
WHERE PTA2.ASSESSMENT_ID = PAA.ASSESSMENT_ID
/*AND PTA2.PATIENT_ID = PAA.PATIENT_ID*/
ORDER BY PTA2.Assessment_date desc) PTA
GIVING YOU: (I left the /AND PTA2.PATIENT_ID = PAA.PATIENT_ID/ --I think you can omit this. I left the */ in place but it's not needed)
SELECT MAX(PTA.ASSESSMENT_DATE) AS Max_Date
, SAQ.QUESTION_TEXT
, SAA.ANSWER_TEXT
, dbo.PT_BASIC.PATIENT_CODE
, dbo.PT_BASIC.NAME_FULL
FROM dbo.PTC_ASSESSMENT_ANSWER AS PAA
CROSS APPLY (SELECT TOP 1 *
FROM dbo.PTC_ASSESSMENT PTA2
WHERE PTA2.ASSESSMENT_ID = PAA.ASSESSMENT_ID --I think you can omit this.
/*AND PTA2.PATIENT_ID = PAA.PATIENT_ID*/
ORDER BY PTA2.Assessment_date desc) PTA
INNER JOIN dbo.SYS_ASSESSMENT_POINTER AS SAP
ON SAP.POINTER_ID = PAA.POINTER_ID
INNER JOIN dbo.SYS_ASSESSMENT_QUESTION AS SAQ
ON SAQ.QUESTION_ID = SAP.QUESTION_ID
INNER JOIN dbo.SYS_ASSESSMENT_ANSWER AS SAA
ON SAA.ANSWER_ID = SAP.ANSWER_ID
INNER JOIN dbo.PT_BASIC
ON PTA.PATIENT_ID = dbo.PT_BASIC.PATIENT_ID
WHERE (PTA.ASSESSMENT_DATE BETWEEN CONVERT(DATETIME, '2017-09-05 00:00:00', 102) AND CONVERT(DATETIME, '2017-10-12 00:00:00', 102))
GROUP BY dbo.PT_BASIC.PATIENT_CODE
, dbo.PT_BASIC.NAME_FULL
, SAQ.QUESTION_TEXT
, SAA.ANSWER_TEXT
HAVING (SAA.ANSWER_TEXT LIKE '%LEVEL % -%')
It appears you're not concerned about patients w/o assessments as all your joins are inner or we could use OUTER APPPLY to be sure to keep all answers regardless if an assessment has been provided.
Alternatively you could use a row_number() logic ( Tab Alleman's link has this covered) and a cte; but if cross apply is available might as well use it here.

Please include order by PTA.ASSESSMENT_DATE DESC to see the latest records at the top.

Related

Teradata SQL CASE Statement with multiple conditions

I have the below SQL query -
select distinct HospitalAcctID,
AdmitDate,
DischargeDate,
PatMRN,
Pat_id,
ICD,
MedCenter,
(case when SeqCount =1 and AdmitDate > '06/01/2013' and AdmitDate < '06/01/2018' then 1 else null end ) Firstdiag
from
(
select distinct acct.HSP_ACCOUNT_ID as HospitalAcctID,
cast(acct.ADM_DATE_TIME as date format 'mm/dd/yyyy') as AdmitDate,
cast(acct.DISCH_DATE_TIME as date format 'mm/dd/yyyy') as DischargeDate,
pat.pat_mrn_id as PatMRN,
pat.pat_id as Pat_id,
REF_BILL_CODE as ICD,
grp7.NAME AS MedCenter,
row_number() over (partition by PatMRN order by AdmitDate) as SeqCount
from acct
inner join pat on pat.pat_id = acct.pat_id
inner join hspenc on hspenc.CSN_ID = acct.CSN_ID
inner join dx on acct.ACCOUNT_ID = dx.ACCOUNT_ID and line = 1
inner join edg on dx.DX_ID = edg.DX_ID
inner join loc on loc.LOC_ID = acct.LOC_ID
inner join grp7 ON loc.RPT_GRP_SEVEN = grp7.RPT_GRP_SEVEN
where
grp7.NAME = 'SMC AREA'
and ADMIT_CONF_STAT_C in ('1','4')
and (edg. REF_BILL_CODE in ('431',
'431')
)
and ADT_PAT_CLASS_C in ('1204','12113')
order by AdmitDate;
)Admit
But I am getting the below syntax error -
Syntax error, expected something like an 'EXCEPT' keyword, 'UNION' Keyword or a 'MINUS' keyword between 'AdmitDate' and ','
In the outer select statement, I am trying to get the min (first ) date when the was first diagnosed. I also want to get only the patients who were diagnosed between 6/2013 to 6/2018 which is why I have the CASE statement. But the CASE statement is giving me error.
As #BarbarosĂ–zhan already wrote, remove the last line order by AdmitDate; in the Derived Table.
But there's no need for ROW_NUMBER:
select distinct acct.HSP_ACCOUNT_ID as HospitalAcctID,
cast(acct.ADM_DATE_TIME as date format 'mm/dd/yyyy') as AdmitDate,
cast(acct.DISCH_DATE_TIME as date format 'mm/dd/yyyy') as DischargeDate,
pat.pat_mrn_id as PatMRN,
pat.pat_id as Pat_id,
REF_BILL_CODE as ICD,
grp7.NAME AS MedCenter,
case when -- current rows is first row
min(AdmitDate)
over (partition by PatMRN) = AdminDate
-- current row within date range
and AdminDate >= DATE '2013-06-01' and AdmitDate < DATE '2018-06-01'
then 1
else null
end as Firstdiag
from acct
inner join pat on pat.pat_id = acct.pat_id
inner join hspenc on hspenc.CSN_ID = acct.CSN_ID
inner join dx on acct.ACCOUNT_ID = dx.ACCOUNT_ID and line = 1
inner join edg on dx.DX_ID = edg.DX_ID
inner join loc on loc.LOC_ID = acct.LOC_ID
inner join grp7 ON loc.RPT_GRP_SEVEN = grp7.RPT_GRP_SEVEN
where
grp7.NAME = 'SMC AREA'
and ADMIT_CONF_STAT_C in ('1','4')
and (edg. REF_BILL_CODE in ('431',
'431')
)
and ADT_PAT_CLASS_C in ('1204','12113')
order by AdmitDate;
I also switched to a Standard SQL date literal DATE '2013-06-01' instead of '06/01/2013'. There's only one possible format for the former (DATE 'YYYY-MM-DD') while the latter depends on the FORMAT of the base column and might fail when it changes (of course not in your query, because you defined it in the CAST).

Filter with Dates but keep the calculation

I would like to know what can you do in the following scenario:
Lets say I am filtering on a date in the where clause (between eomonth(#StartDate) and eomonth(getdate()-1). I have a calculated column that is correct when I run the query without any filter, but the problem is that when I filter lets say #StartDate = 06/30/2017 then the calculations will obviously change. Is there any way of doing this?
The calculated column is a windowing function.
Edited:
I have added a picture of the data. So I am using a windowing function to calculate the agentfourmonthperiod. You will see that it sums the units for that month and the 3 previous months. This I dont want to change when filtering. So the units and agentfourmonthperiod columns should stay exactly the same after filtering on the #StartDate. Please see data below:
I want to design an SSRS report that the user will be filtering on the #StartDate, but then it should show the calculation as it does when no filter in used.
Hope this makes sense. Otherwise I can add the code. Its just quite long though.
Code:
WITH DATA
AS
(
SELECT
EOMONTH(SubmissionDates.original_date_c) AS IntakeMonth,
ProvincialArea.SAD_ProvMananger AS ProvManager,
RegionalArea.SAD_RegMananger AS RegManager,
SalesArea.SAD_SalesManager AS AreaSalesManager,
ConsultantUserExt.name AS Consultant,
COUNT(LeadsLink.LeadsID) OVER(PARTITION BY ConsultantUserExt.name, EOMONTH(SubmissionDates.original_date_c,0) ORDER BY EOMONTH(SubmissionDates.original_date_c,0)) AS Unit,
ROW_NUMBER() OVER(PARTITION BY ConsultantUserExt.name, EOMONTH(SubmissionDates.original_date_c,0) ORDER BY EOMONTH(SubmissionDates.original_date_c,0)) AS rn
FROM Import.OobaApplication as Application
LEFT OUTER JOIN Import.OobaApplicant applicant ON application.ApplicationID = applicant.ApplicationID
AND applicant.PrincipleApplication = 'Y'
LEFT OUTER JOIN usr_userext_cstm ON Application.Consultant = usr_userext_cstm.comcorp_key_c
or Application.Consultant = usr_userext_cstm.deal_maker_key_c
or Application.Consultant = usr_userext_cstm.ops_key_c
LEFT OUTER JOIN usr_userext AS ConsultantUserExt ON usr_userext_cstm.id_c = ConsultantUserExt.id AND ConsultantUserExt.deleted = 0
LEFT OUTER JOIN usr_userext_cstm AS ConsultantUserExtCstm on ConsultantUserExt.id = ConsultantUserExtCstm.id_c
LEFT OUTER JOIN CapcubedInternalDB.dbo.ProvincialArea AS ProvincialArea ON ConsultantUserExtCstm.sad_provincialmanager_c = ProvincialArea.ID
LEFT OUTER JOIN CapcubedInternalDB.dbo.RegionalArea AS RegionalArea ON ConsultantUserExtCstm.sad_regionalmanager_c = RegionalArea.ID
LEFT OUTER JOIN CapcubedInternalDB.dbo.SalesArea AS SalesArea ON ConsultantUserExtCstm.sad_salesmanager_c = SalesArea.ID
LEFT OUTER JOIN CapcubedInternalDB.dbo.LeadsLink AS LeadsLink ON Application.ApplicationID = LeadsLink.GroupCode
LEFT OUTER JOIN suitecrmprod.dbo.leads AS SuiteLeads ON LeadsLink.LeadsID = SuiteLeads.ID
--Latest Bank Submission
LEFT OUTER JOIN (SELECT
bankSub.ApplicationID As BankSubAppID, bankSub.SubmissionDate,
bankSub.Bank, bankSub.RequiredLoanAmount,
bankSub.BankCode AS BankSubBankCode
FROM Import.OobaBankSubmission bankSub
LEFT OUTER JOIN Import.OobaBankSubmission later ON bankSub.ApplicationID = later.ApplicationID
AND bankSub.SubmissionDate > later.SubmissionDate
WHERE later.applicationID IS NULL) AS BankSub ON Application.ApplicationID = BankSub.BankSubAppID
LEFT OUTER JOIN ccrep_calendar_cstm AS SubmissionDates ON CONVERT(VARCHAR(10),BankSub.SubmissionDate,101) = SubmissionDates.original_date_c
WHERE SubmissionDates.cc_date_c BETWEEN COALESCE(EOMONTH(#StartDate), '01/31/2016') AND COALESCE(#EndDate, GETDATE(), -1)
AND ConsultantUserExtCstm.consultantstatus_c NOT LIKE 2
)
SELECT *
INTO #Rn
FROM DATA
WHERE rn = 1
SELECT i.IntakeMonth, c.ProvManager, c.RegManager, c.AreaSalesManager, c.Consultant, COALESCE(#Rn.Unit, 0) AS Unit
INTO #FillData
FROM (SELECT DISTINCT IntakeMonth FROM #Rn) AS i
CROSS JOIN
(SELECT DISTINCT Consultant, ProvManager, RegManager, AreaSalesManager FROM #Rn) AS c
LEFT OUTER JOIN #Rn ON #Rn.IntakeMonth = i.IntakeMonth AND #Rn.Consultant = c.Consultant
ORDER BY Consultant, IntakeMonth
SELECT
IntakeMonth,
Consultant,
Unit,
SUM(Unit) OVER(PARTITION BY Consultant ORDER BY Consultant ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) AS agentfourmonthperiod
FROM #FillData
WHERE ('(All)' IN (#ProvincialManager) OR (ProvManager IN (#ProvincialManager)))
AND ('(All)' IN (#RegionalManager) OR (RegManager IN (#RegionalManager)))
AND ('(All)' IN (#AreaSalesManager) OR (AreaSalesManager IN (#AreaSalesManager)))
AND ('(All)' IN (#Consultant) OR (Consultant IN (#Consultant)))
DROP TABLE #Rn
DROP TABLE #FillData
You could of course remove any filter on dates from the query and apply them directly in the tablix of your report. Obvously, this means that SQL Server has to return all the data each time the report is run, so I guess that this isn't what you want.
For the window function to have access to the previous 3 rows, you will have to include the previous 3 months in your calculation. To achieve this, change the first condition in the WHERE clause in the cte (data) to something like this:
SubmissionDates.cc_date_c
BETWEEN
ISNULL(DATEADD(month, DATEDIFF(month, 0, #StartDate)-3, 0), '01/10/2015')
AND
ISNULL(#EndDate, DATEADD(day, DATEDIFF(day, 0, GETDATE())-1, 0))
As I thought that your date filter logic was wrong, I changed it to include the dates from the beginning of the month rather than from the end.
Now that the previous 3 months are included, we can apply a filter in the end to exclude the previous months from display, but this has to be done after using the window function, for example with another cte:
WITH calc AS (
SELECT
IntakeMonth,
Consultant,
Unit,
SUM(Unit) OVER(PARTITION BY Consultant ORDER BY Consultant ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) AS agentfourmonthperiod
FROM #FillData
WHERE ('(All)' IN (#ProvincialManager) OR (ProvManager IN (#ProvincialManager)))
AND ('(All)' IN (#RegionalManager) OR (RegManager IN (#RegionalManager)))
AND ('(All)' IN (#AreaSalesManager) OR (AreaSalesManager IN (#AreaSalesManager)))
AND ('(All)' IN (#Consultant) OR (Consultant IN (#Consultant)))
)
SELECT IntakeMonth, Consultant, Unit, agentfourmonthperiod
FROM calc
WHERE IntakeMonth >= ISNULL(EOMONTH(#StartDate), '01/31/2016')

Subquery returned more than 1 value.The subquery that contains SUM(dbo.SalarySettingsBreakup.Amount) AS AmountSSB

My sub-query returns more than one value and gives error.
(SELECT dbo.employee.id,
dbo.employee.employeecode,
dbo.employee.firstname,
dbo.employee.departmentid,
dbo.salarysettings.monthlyoffered,
dbo.salarysettings.id AS SalarySettingsID,
(SELECT Sum(amount) AS AmountVP
FROM voucherprocesses
WHERE vouchertypeid = 2
AND employee = dbo.employee.id
AND voucherdate BETWEEN '9/1/2017 12:00:00 AM' AND
'9/30/2017 12:00:00 AM'
GROUP BY employee) AS SalaryAdvance,
(SELECT Sum(dbo.salarysettingsbreakup.amount) AS AmountSSB
FROM dbo.employee
LEFT JOIN dbo.salarysettings
ON dbo.employee.id = dbo.salarysettings.employee
LEFT JOIN dbo.salarysettingsbreakup
ON dbo.salarysettings.id =
dbo.salarysettingsbreakup.salarysetting
WHERE dbo.salarysettingsbreakup.paymenttype = 2
AND dbo.salarysettingsbreakup.isactive = 1
GROUP BY dbo.employee.id) AS TotalDeduction,
(SELECT CASE
WHEN employee.joiningdate BETWEEN
'9/1/2017 12:00:00 AM' AND '9/30/2017 12:00:00 AM' THEN(
( salarysettings.monthlyoffered / 30 ) * ( 30 -
( Datepart(dd, joiningdate) - 1 ) ) )
ELSE 0
END) AS PayToBank
FROM dbo.employee
LEFT JOIN dbo.salarysettings
ON dbo.employee.id = dbo.salarysettings.employee
WHERE dbo.salarysettings.isactive = 1)
hope will work, try this :
(SELECT e.id,
e.employeecode,
e.firstname,
e.departmentid,
dbo.salarysettings.monthlyoffered,
dbo.salarysettings.id AS SalarySettingsID,
(SELECT Sum(amount) AS AmountVP
FROM voucherprocesses
WHERE vouchertypeid = 2
AND voucherprocesses.employee = e.id
AND voucherdate BETWEEN '9/1/2017 12:00:00 AM' AND
'9/30/2017 12:00:00 AM'
) AS SalaryAdvance,
(SELECT Sum(dbo.salarysettingsbreakup.amount) AS AmountSSB
FROM dbo.employee e2
LEFT JOIN dbo.salarysettings
ON e2.id = dbo.salarysettings.employee
LEFT JOIN dbo.salarysettingsbreakup
ON dbo.salarysettings.id =
dbo.salarysettingsbreakup.salarysetting
AND dbo.salarysettingsbreakup.paymenttype = 2
AND dbo.salarysettingsbreakup.isactive = 1
WHERE e2.id = e.id
) AS TotalDeduction,
(SELECT CASE
WHEN employee.joiningdate BETWEEN
'9/1/2017 12:00:00 AM' AND '9/30/2017 12:00:00 AM' THEN(
( salarysettings.monthlyoffered / 30 ) * ( 30 -
( Datepart(dd, joiningdate) - 1 ) ) )
ELSE 0
END) AS PayToBank
FROM dbo.employee e
LEFT JOIN dbo.salarysettings
ON e.id = dbo.salarysettings.employee
WHERE dbo.salarysettings.isactive = 1)
You have much to learn. You need to understand how subqueries work as well as outer joins. The following is wrong due to 2 issues.
(SELECT Sum(dbo.salarysettingsbreakup.amount) AS AmountSSB
FROM dbo.employee
LEFT JOIN dbo.salarysettings
ON dbo.employee.id = dbo.salarysettings.employee
LEFT JOIN dbo.salarysettingsbreakup
ON dbo.salarysettings.id =
dbo.salarysettingsbreakup.salarysetting
WHERE dbo.salarysettingsbreakup.paymenttype = 2
AND dbo.salarysettingsbreakup.isactive = 1
GROUP BY dbo.employee.id) AS TotalDeduction,
First is that you did not properly correlate the subquery. As Rahmat posted (but did not explain), you need to associate the employee ID from the outer query with the subquery. Because you did not correlate the subquery, it produces multiple rows for each row in the outer query - producing your error.
In addition, your lack of understanding about the correlation causes you to add complexity and a logical mistake (which gets covered up when correlated correctly). There is no need to include the employee table in your subquery. Since you correlate it to the employee table in the main query, it is redundant. In addition, you don't need to group by anything in the subquery since it is intended to generate a single scalar value per row in the outer query. And lastly, there is no purpose to outer joining in the subquery. Either you have matching rows in salarysettingsbreakup or you don't. An inner and outer join will achieve the same result - NULL if no matches. I also question whether you need to sum at all given the table and column names involved. You should search for explanations about how outer joins work and what happens when you reference columns from the unpreserved table (e.g. salarysettingsbreakup) in the where clause.
So a better subquery is:
(SELECT Sum(bkp.amount)
FROM dbo.salarysettings as sset
INNER JOIN dbo.salarysettingsbreakup as bkp
ON sset.id = bkp.salarysetting
AND bkp.paymenttype = 2
AND bkp.isactive = 1
WHERE sset.employee = dbo.employee.id) as TotalDeduction,
Note the inclusion of some best practices. Give a readable alias to your tables and use it with all of the columns referenced. I also despise the practice of using a table name as a column name - that adds to the confusion of reading your queries IMO.

SQL Query to return 2 results for multiple employees

I am very new to SQL and in fact, I am completely self taught. I currently have this query below which works to find (badly) 2 random support tickets by employee.
Right now, the query will ask the employees name and provide 2 results. Is there a way to have this provide 2 results for ALL employees?
SELECT
TOP 2 CONVERT (
DATE,
SD_REQUEST.END_DATE_UT
) AS 'Close Date',
SD_REQUEST.RFC_number AS 'Ticket',
agent.LAST_NAME AS 'Agent',
AM_DOMAIN.NAME_EN AS 'Company',
EE.LAST_NAME AS 'Recipient',
RR.LAST_NAME AS 'Requestor',
catpath.SD_CATALOG_PATH_EN
FROM
SD_REQUEST
LEFT JOIN AM_EMPLOYEE AS agent ON agent.EMPLOYEE_ID = SD_REQUEST.OWNER_ID
LEFT JOIN AM_EMPLOYEE AS EE ON EE.EMPLOYEE_ID = SD_REQUEST.RECIPIENT_ID
LEFT JOIN AM_EMPLOYEE AS RR ON RR.EMPLOYEE_ID = SD_REQUEST.REQUESTOR_ID
LEFT JOIN SD_CATALOG_PATH AS catpath ON catpath.SD_CATALOG_ID = SD_REQUEST.SD_CATALOG_ID
LEFT JOIN AM_DOMAIN ON AM_DOMAIN.DOMAIN_ID = EE.DEFAULT_DOMAIN_ID
WHERE
agent.LAST_NAME = 'insert name here'
AND CONVERT (
datetime,
SD_REQUEST.END_DATE_UT,
101
) BETWEEN (Getdate() - 8)
AND (Getdate() - 2)
ORDER BY
NEWID()
I'm assuming you're using SQL Server based on syntax in question. You can use the ROW_NUMBER() function inside a cte/subquery to generate a number for each row, using PARTITION BY you can have the numbering start over for each member of a given set/group, in this case agent.LAST_NAME, you can use that number to limit to two results per set/group:
;with cte AS (
SELECT CONVERT (DATE,SD_REQUEST.END_DATE_UT) AS 'Close Date',
SD_REQUEST.RFC_number AS 'Ticket',
agent.LAST_NAME AS 'Agent',
AM_DOMAIN.NAME_EN AS 'Company',
EE.LAST_NAME AS 'Recipient',
RR.LAST_NAME AS 'Requestor',
catpath.SD_CATALOG_PATH_EN,
ROW_NUMBER() OVER(PARTITION BY agent.LAST_NAME ORDER BY NEWID()) AS RN
FROM
SD_REQUEST
LEFT JOIN AM_EMPLOYEE AS agent ON agent.EMPLOYEE_ID = SD_REQUEST.OWNER_ID
LEFT JOIN AM_EMPLOYEE AS EE ON EE.EMPLOYEE_ID = SD_REQUEST.RECIPIENT_ID
LEFT JOIN AM_EMPLOYEE AS RR ON RR.EMPLOYEE_ID = SD_REQUEST.REQUESTOR_ID
LEFT JOIN SD_CATALOG_PATH AS catpath ON catpath.SD_CATALOG_ID = SD_REQUEST.SD_CATALOG_ID
LEFT JOIN AM_DOMAIN ON AM_DOMAIN.DOMAIN_ID = EE.DEFAULT_DOMAIN_ID
WHERE CONVERT (datetime,SD_REQUEST.END_DATE_UT,101) BETWEEN (Getdate() - 8) AND (Getdate() - 2)
)
SELECT *
FROM cte
WHERE RN <= 2

SQL - Derived tables issue

I have the following SQL query:
SELECT VehicleRegistrations.ID, VehicleRegistrations.VehicleReg,
VehicleRegistrations.Phone, VehicleType.VehicleTypeDescription,
dt.ID AS 'CostID', dt.IVehHire, dt.FixedCostPerYear, dt.VehicleParts,
dt.MaintenancePerMile, dt.DateEffective
FROM VehicleRegistrations
INNER JOIN VehicleType ON VehicleRegistrations.VehicleType = VehicleType.ID
LEFT OUTER JOIN (SELECT TOP (1) ID, VehicleRegID, DateEffective, IVehHire,
FixedCostPerYear, VehicleParts, MaintenancePerMile
FROM VehicleFixedCosts
WHERE (DateEffective <= GETDATE())
ORDER BY DateEffective DESC) AS dt
ON dt.VehicleRegID = VehicleRegistrations.ID
What I basically want to do is always select the top 1 record from the 'VehicleFixedCosts' table, where the VehicleRegID matches the one in the main query. What is happening here is that it's selecting the top row before the join, so if the vehicle registration of the top row doesn't match the one we're joining to it returns nothing.
Any ideas? I really don't want to have use subselects for each of the columns I need to return
Try this:
SELECT vr.ID, vr.VehicleReg,
vr.Phone, VehicleType.VehicleTypeDescription,
dt.ID AS 'CostID', dt.IVehHire, dt.FixedCostPerYear, dt.VehicleParts,
dt.MaintenancePerMile, dt.DateEffective
FROM VehicleRegistrations vr
INNER JOIN VehicleType ON vr.VehicleType = VehicleType.ID
LEFT OUTER JOIN (
SELECT ID, VehicleRegID, DateEffective, IVehHire, FixedCostPerYear, VehicleParts, MaintenancePerMile
FROM VehicleFixedCosts vfc
JOIN (
select VehicleRegID, max(DateEffective) as DateEffective
from VehicleFixedCosts
where DateEffective <= getdate()
group by VehicleRegID
) t ON vfc.VehicleRegID = t.VehicleRegID and vfc.DateEffective = t.DateEffective
) AS dt
ON dt.VehicleRegID = vr.ID
Subquery underneath dt might need some grouping but without schema (and maybe sample data) it's hard to say which column should be involved in that.