Joining reports - sql

I am trying to join 3 reports into one, taking parts out of each report.
This is my script that works with 2 of the reports:
ALTER VIEW [dbo].[v_JB2] AS
SELECT R.*, I.ENTERED, I.PROBLEM_CODE, I.WORKORDER
FROM DALE.DBO.V_JBTRB R
JOIN REPORTS.DBO.V_TC_ANALYSIS_JEREMY I
ON R.HUBID = I.HUB
AND R.NODEID = I.NODE
AND CAST(R.CREATE_DATE AS DATE) = I.ENTERED_DATE
GO
and I want to add this field A.CREATE_DATE-O.ACTUAL_START_DATE AS ASSIGN_SECS from what should be DALE.DBO.V_MTTA

Your join of DALE.DBO.V_MTTA has no ON condition...
Try this:
SELECT R.*, I.ENTERED, I.PROBLEM_CODE, I.WORKORDER,
A.CREATE_DATE-O.ACTUAL_START_DATE as ASSIGN_SECS
FROM
DALE.DBO.V_JBTRB R JOIN
REPORTS.DBO.V_TC_ANALYSIS_JEREMY I
ON R.HUBID = I.HUB AND R.NODEID = I.NODE AND
CAST(R.CREATE_DATE AS DATE) = I.ENTERED_DATE
JOIN DALE.DBO.V_MTTA A ON A.CREATE_DATE-O.ACTUAL_START_DATE = ??? (what do you want this to be joined on? I don't know how your tables are related, but you need a valid ON statement for this join to work)

so the right answer was and i don't think anyone would have been able to tell based on the code was instead of joining a third query i added to my trb query and got the same data not sure why i didn't think of it sooner.
ALTER VIEW [dbo].[v_JBTRB] AS
SELECT SINGLE_USER, RECORD_ID, DIVISION, CREATE_DATETIMEINNEW, OUTAGESTARTDATE, STATUS_DESC, CAST(HUBID AS VARCHAR(255)) AS HUBID, CAST(NODEID AS VARCHAR(255)) AS NODEID, CATEGORY, STATUS, ASSIGN_SECS
FROM OPENQUERY(REMEDY_BI,
'
SELECT
T.RECORD_ID AS Record_ID
, T.DIVISION AS Division
, T.CREATE_DATE_ET AS Create_Date
, T.TIME_IN_NEW AS TimeInNew
, O.ACTUAL_START_DATE_ET AS OutageStartDate
, T.STATUS_DESC
, T.FACILITY AS HubID
, T.NODE AS NodeID
, T.CATEGORY
, T.STATUS
, T.SINGLE_USER
, T.CREATE_DATE-O.ACTUAL_START_DATE AS ASSIGN_SECS
FROM ARNEUSER.VW_BASE_TROUBLE T
JOIN ARNEUSER.VW_BASE_OUTAGE O
ON O.INSTANCE_ID = T.OUTAGE_INSTANCE_ID
AND O.SUBMITTED_BY = T.SUBMITTER
JOIN ARNEUSER.VW_BASE_TROUBLE_TKT_ASGN_HIS A
ON A.TROUBLE_ID = T.TROUBLE_ID
AND A.CREATE_DATE = ( SELECT MIN(CREATE_DATE)
FROM ARNEUSER.VW_BASE_TROUBLE_TKT_ASGN_HIS
WHERE TROUBLE_ID=T.TROUBLE_ID
AND STATUS_NUM=1
AND CREATE_DATE>=O.ACTUAL_START_DATE
AND SUBMITTER=T.SUBMITTER )
WHERE T.STATUS > 3
AND T.REGION = ''Carolina''
AND T.CREATE_DATE >= DATE_TO_UNIX_TZ(TRUNC(SYSDATE)-14)
AND T.CATEGORY IN (''HFC'',''CRITICAL INFRASTRUCTURE'',''VIDEO DIGITAL'',''VIDEO ANALOG'',''DIGITAL PHONE'',''HEADEND/HUB'',''METRO/REGIONAL NETWORK'',''NATIONAL BACKBONE'',''NETWORK'')
')
I added this part the rest was already there if that helps this is one of the reports i was originally joining. I was trying to join another report but it came from the same data base.
, T.CREATE_DATE-O.ACTUAL_START_DATE AS ASSIGN_SECS
AND A.CREATE_DATE = ( SELECT MIN(CREATE_DATE)
FROM ARNEUSER.VW_BASE_TROUBLE_TKT_ASGN_HIS
WHERE TROUBLE_ID=T.TROUBLE_ID
AND STATUS_NUM=1
AND CREATE_DATE>=O.ACTUAL_START_DATE
AND SUBMITTER=T.SUBMITTER )

this is the other query that was being joined for anyone curious the 8 **** replace some sensitive data
ALTER VIEW [dbo].[v_TC_ANALYSIS_JEREMY] AS
SELECT *, cast(entered_date + ' ' + entered_time as datetime) as ENTERED FROM OPENQUERY(ICOMS_H,'
SELECT
W.WONUM AS WORKORDER,
W.WOTYC AS TYPE,
CVGDT2DATE(W.WOEDT) AS ENTERED_DATE,
W.WOQCD AS QUEUE_CODE,
W.WOETM AS TIME_ENTERED,
W.WOPB1 AS PROBLEM_CODE,
TRIM(H.HOAAEQ) AS HUB,
TRIM(H.HONODE) AS NODE,
H.HOZIP5 AS ZIPCODE,
W.WOPOL AS POOL,
P.EXTXD0 AS AREA,
CVGTM2TIME(W.WOETM) AS ENTERED_TIME
FROM
********.WOMHIPF W
JOIN ******.HOSTPF H ON H.HONUM = W.WOHNUM
JOIN CF83PF P ON P.EXPLLL = W.WOPOL
WHERE
W.WOEDT >= REPLACE(CHAR(CURRENT_DATE - 14 DAYS,ISO),''-'','''')-19000000
AND ((WOTYC =''SR'' AND WOQCD IN (''O'',''M'')) OR (WOTYC =''TC''))
AND WOPOL IN (''1'',''2'',''3'',''4'',''6'',''7'',''E'',''M'',''R'')

Related

Snowflake unsupported subquery when using function

This is the function I created:
CREATE OR REPLACE FUNCTION NS_REPORTS.AP."COUPA_GET_EXCH_RATE"("from_curr_id" NUMBER(38,0), "to_curr_id" NUMBER(38,0), "date" DATE)
RETURNS FLOAT
LANGUAGE SQL
AS '
SELECT
COALESCE((
SELECT
RATE
FROM
(
SELECT
ROW_NUMBER() OVER (PARTITION BY DATE(RATE_DATE) ORDER BY RATE_DATE DESC) ROW_NUM
, RATE
FROM
CONNECTORS.COUPA.EXCHANGE_RATE
WHERE
FROM_CURRENCY_ID = from_curr_id
AND TO_CURRENCY_ID = to_curr_id
AND DATE(RATE_DATE) = date
) R
WHERE
ROW_NUM = 1
), 1)
';
I'm using the ROW_NUMBER function because the RATE_DATE field is actually datetime and so there are multiple records per date.
When I call the function by itself, it works fine. However, when I try to use it in a view, I get the unsupported subquery type error. The view works fine without it. Can anyone think of what I can do to either fix the error or work around it by rewriting the query?
EDIT 1: View code and exact error message
CREATE OR REPLACE VIEW COUPA_REQUISITION
AS
SELECT
RH.ID REQ_NUM
, RL.LINE_NUM REQ_LINE_NUM
, OH.PO_NUMBER
, REPLACE(REPLACE(OH.CUSTOM_FIELDS:"legacy-po-number", '"', ''), '.0', '') LEGACY_PO_NUMBER
, S."NAME" SUPPLIER
, OH.STATUS
, UR.FULLNAME REQUESTED_BY
, UC.FULLNAME CREATED_BY
, OL.RECEIVED
, DATE(RH.SUBMITTED_AT) ORDER_DATE
, DATE(RH.NEED_BY_DATE) NEEDED_BY_DATE
, RL."DESCRIPTION" ITEM
, CAST(NULL AS VARCHAR) CHART_OF_ACCOUNTS
, REPLACE(OH.CUSTOM_FIELDS:"purchase-type", '"', '') PURCHASE_TYPE
, COM."NAME" COMMODITY
, ACT.NS_SUB_NAME SUBSIDIARY
, ACT.NS_ACCT_NAME_FULL "ACCOUNT"
, ACT.NS_DEPT_NAME_FULL DEPARTMENT
, ACT.NS_L3_DEPT_NAME L3_DEPARTMENT
, ACT.NS_LOC_NAME "LOCATION"
, RL.QUANTITY QTY
, OL.LINE_NUM ORDER_LINE_NUM
, RL.TOTAL * NS_REPORTS.AP.COUPA_GET_EXCH_RATE(RL.CURRENCY_ID, 1, DATE(RH.SUBMITTED_AT)) LINE_TOTAL
, RL.TOTAL - OL.INVOICED UNINVOICED_AMOUNT
, OL.INVOICED INVOICED_TOTAL
, RLSUM.TOTAL TOTAL
, REPLACE(IL.CUSTOM_FIELDS:"amortization-schedule"."name", '"', '') AMORTIZATION_SCHEDULE
, CASE WHEN COALESCE(IL.CUSTOM_FIELDS:"amortization-start-date", '') <> '' THEN DATE(REPLACE(IL.CUSTOM_FIELDS:"amortization-start-date", '"', '')) ELSE NULL END AMORTIZATION_START_DATE
, CASE WHEN COALESCE(IL.CUSTOM_FIELDS:"amortization-end-date", '') <> '' THEN DATE(REPLACE(IL.CUSTOM_FIELDS:"amortization-end-date", '"', '')) ELSE NULL END AMORTIZATION_END_DATE
, CASE WHEN COALESCE(OH.CUSTOM_FIELDS:"contract-start-date", '') <> '' THEN DATE(REPLACE(OH.CUSTOM_FIELDS:"contract-start-date", '"', '')) ELSE NULL END CONTRACT_START_DATE
, CASE WHEN COALESCE(OH.CUSTOM_FIELDS:"contract-end-date", '') <> '' THEN DATE(REPLACE(OH.CUSTOM_FIELDS:"contract-end-date", '"', '')) ELSE NULL END CONTRACT_END_DATE
FROM
CONNECTORS.COUPA.REQUISITION_HEADER RH
JOIN CONNECTORS.COUPA.REQUISITION_LINE RL ON RL.REQUISITION_HEADER_ID = RH.ID
JOIN NS_REPORTS.AP.COUPA_ACCOUNT ACT ON ACT.COUPA_ACCT_ID = RL.ACCOUNT_ID
JOIN CONNECTORS.COUPA."USER" UR ON UR.ID = RH.REQUESTED_BY_ID
JOIN CONNECTORS.COUPA."USER" UC ON UC.ID = RH.CREATED_BY_ID
JOIN (
SELECT
REQUISITION_HEADER_ID
, SUM(TOTAL) TOTAL
FROM
CONNECTORS.COUPA.REQUISITION_LINE
GROUP BY
REQUISITION_HEADER_ID
) RLSUM ON RLSUM.REQUISITION_HEADER_ID = RH.ID
LEFT JOIN CONNECTORS.COUPA.ORDER_LINE OL ON OL.ID = RL.ORDER_LINE_ID
LEFT JOIN CONNECTORS.COUPA.ORDER_HEADER OH ON OH.ID = OL.ORDER_HEADER_ID
LEFT JOIN CONNECTORS.COUPA.COMMODITY COM ON COM.ID = OL.COMMODITY_ID
LEFT JOIN CONNECTORS.COUPA.SUPPLIER S ON S.ID = OH.SUPPLIER_ID
LEFT JOIN CONNECTORS.COUPA.INVOICE_LINE IL ON IL.ORDER_LINE_ID = OL.ID
Error message:
SQL Error [2031] [42601]: SQL compilation error:
Unsupported subquery type cannot be evaluated
The error is a correlated subquery and the are not supported (beyond some tiny toy examples)
But the basic form is
SELECT a.a
(select b.b from b where b.a = a.a order by b.y limit 1)
FROM a;
in effect for each row, a sub-query is run on another table to get a value. There are many tricks done in other DB's to make this "work" but in effect there is work done on each row. Snowflake does not types of for each row operations.
The good news is there are other patterns that are effectively the same, that snowflake does support, the two patterns are really the same use a CTE or join to a sub-select which is the same thing.
so the above becomes:
WITH subquery AS (
SELECT b.a, b.b FROM b
QUALIFY row_number() over (partition by b.a order by b.y) = 1
)
SELECT a.a
sq.b
FROM a
JOIN subquery AS sq
ON sq.a = a.a
So we first process/shape "all records" from the other/sub table, and we only keep the rows that have the count/shape we want, and then join to that result. The is very parallelizable, so performs well. The reason Snowflake does not auto translate a sub-query for you, is it rather easy to get it wrong, and they presently are spending there development efforts working on features that do not exist at all, etc etc, and it can be rewritten by you, given you understand your model.
What if you move this to the FROM clause? I would phrase this as:
SELECT COALESCE(MAX(er.rate), 1)
FROM (SELECT er.*
FROM CONNECTORS.COUPA.EXCHANGE_RATE er
WHERE er.FROM_CURRENCY_ID = in_from_curr_id AND
er.TO_CURRENCY_ID = in_to_curr_id AND
DATE(er.RATE_DATE) = in_date
ORDER BY RATE_DATE DESC
LIMIT 1
) er;
Notice that I changed the names of the parameters so they are more obviously input parameters.

JOIN a table with a grouped by table

I have two tables i am trying to join and do a count on, basically to bring over the date onto the Units table. The problem is that the intakes table has duplicates.
SELECT
Units.Clinic,
Units.display_id,
INTAKES.initial_intake_date,
COUNT(case_note_type_desc) AS CountOfUAs
FROM Units
LEFT JOIN (SELECT display_id,Clinic,initial_intake_date
FROM factIntakesAndDischarges
GROUP BY display_id,Clinic,initial_intake_date ) INTAKES
ON Units.display_id = INTAKES.display_id
AND Units.display_id = INTAKES.Clinic
WHERE casenotes_date BETWEEN '4/9/20' AND '5/9/20'
AND case_note_type_desc = '(UA)'
GROUP BY Units.Clinic,
Units.display_id,
INTAKES.initial_intake_date
ORDER BY CountOfUAs desc,Clinic,display_id,initial_intake_date
This gives me the correct count, but the initial_intake_date comes back NULL. The other join i tried gave me the correct initial_intake_date, but the count was off.
Based on your, I would really expect a query more like this:
SELECT u.Clinic, u.display_id, MIN(i.initial_intake_date) as initial_intake_date,
COUNT(*) AS CountOfUAs
FROM Units u LEFT JOIN
factIntakesAndDischarges fid
ON u.display_id = i.display_id AND
u.display_id = INTAKES.display_id
WHERE u.casenotes_date >= '2020-04-09' AND '2020-05-09' AND
u.case_note_type_desc = '(UA)'
GROUP BY u.Clinic, u.display_id,
ORDER BY CountOfUAs desc, Clinic, display_id, initial_intake_date;
Even if the numbers are not quite right, this is a simpler query for starting to fix.
ON Units.display_id = INTAKES.display_id
AND Units.display_id = INTAKES.Clinic
OR
ON Units.display_id = INTAKES.display_id
AND Units.Clinic = INTAKES.Clinic
WITH UnitsTable AS
(
SELECT
Clinic
, display_id
, CountOfUAs = COUNT(case_note_type_desc)
FROM Units
)
, IntakesTable AS
(
SELECT
display_id
, Clinic
, initial_intake_date
FROM factIntakesAndDischarges
-- I am asuming casenotes_date and casenotes_type_Desc belong to Intakes
-- If not, move this WHERE to UnitsTable above
WHERE
casenotes_date BETWEEN '4/9/20' AND '5/9/20'
AND case_note_type_desc = '(UA)'
GROUP BY
display_id
, Clinic
, initial_intake_date
)
SELECT
U.Clinic
, U.display_id
, I.initial_intake_date
, U.CountOfUAs
FROM UnitsTable U
JOIN IntakesTable I ON I.Display_ID = U.Display_ID
AND I.Clinic = U.Clinic
ORDER BY
U.CountOfUAs desc
, U.Clinic
, U.display_id
, I.initial_intake_date

Recursive CTE and SELECT

I have written a fairly simple recursive CTE statement. The purpose is that it looks up a structure and returns the top level item
Here is the code
WITH cte_BOM(parent_serial_id, serial_id, serial_batch_no, sort)
AS (SELECT BOM.parent_serial_id, BOM.serial_id, p.serial_batch_no, 1
FROM serial_status AS BOM
INNER JOIN item_serial_nos p ON BOM.parent_serial_id = p.serial_id
WHERE BOM.serial_id = '16320' AND BOM.is_current = 'Y'
UNION ALL
SELECT
BOM1.parent_serial_id, bom1.serial_id, p1.serial_batch_no, cte_BOM.sort + 1
FROM cte_BOM
INNER JOIN serial_status AS BOM1 ON cte_BOM.parent_serial_id =
BOM1.serial_id
INNER JOIN item_serial_nos p1 ON BOM1.parent_serial_id = p1.serial_id
WHERE BOM1.is_current = 'Y'
)
SELECT TOP 1
cte_BOM.*
FROM
cte_BOM
ORDER BY sort desc
As you can see I just hard code the serial_id at the moment. What I now need to accomplish is to run this cte against a subset of data. I’m now stuck on how I can do this.
So I would produce a list of serial_ids by means of another select statement, and then for each row use this serial_id in place of the ones that is currently hard coded and return the 1st record. Importantly if a serial_id has no parent that should still return a row
The second SELECT would be this:
SELECT serial_id
FROM
item_serial_nos
WHERE
item_serial_nos.item_id = '15683'
Any suggestions appreciated. (using SQL 2008 R2)
If I understand your goal correctly, you can just remove the hardcoded serial_id from the cte and add the start serial_id:
WITH cte_BOM(parent_serial_id, serial_id, serial_batch_no, sort, Original_Serial_id)
AS (
SELECT BOM.parent_serial_id
, BOM.serial_id
, p.serial_batch_no
, 1
, BOM.serial_id
FROM serial_status AS BOM
INNER JOIN item_serial_nos p
ON BOM.parent_serial_id = p.serial_id
WHERE BOM.is_current = 'Y'
UNION ALL
SELECT BOM1.parent_serial_id
, bom1.serial_id
, p1.serial_batch_no
, cte_BOM.sort + 1
, cte_BOM.Original_Serial_id
FROM cte_BOM
INNER JOIN serial_status AS BOM1
ON cte_BOM.parent_serial_id = BOM1.serial_id
INNER JOIN item_serial_nos p1
ON BOM1.parent_serial_id = p1.serial_id
WHERE BOM1.is_current = 'Y'
)
SELECT cte_BOM.*
FROM cte_BOM
INNER JOIN (
SELECT cte_BOM.Original_Serial_id
, MAX(sort) sort_max
FROM cte_BOM
WHERE cte_BOM.Original_Serial_id IN (
SELECT serial_id
FROM item_serial_nos
WHERE item_serial_nos.item_id = '15683'
)
GROUP BY cte_BOM.Original_Serial_id
) max_cte
ON max_cte.Original_Serial_id = cte_BOM.Original_Serial_id
AND max_cte.sort_max = cte_BOM.sort
The recursive CTE is only executed when it's called from the last select, so it is only executed for those records that are selected in the IN query. So you shouldn't suffer a performance hit because of this.

Tereadata Error 3782 Improper column reference in the search condition of a joined table

I made some changes (highlighted below) to some sql I inherited and I'm getting
Error 3782 Improper column reference in the search condition of a
joined table
I'm not sure why I'm getting this message. Any help would be greatly appreciated.
with dqry_cc (mop_cd, mop_desc, group_branch_id, ecr_tmz_name, stn_stn_id , stn_id, grp_brn_id ) as
(select
a.mop_cd ,
a.mop_desc,
so.group_branch_id ,
t.ecr_tmz_name,
so.stn_stn_id,
s.stn_id ,
s.grp_brn_id
from
rfs.stn_ops_hierarchies so,
rfs.mthd_of_pymts a,
rfs.stns s,
rfs.tmzs_map t
where s.stn_id = so.stn_stn_id
and a.mpt_mop_type_code = 'CC'
and s.TMZ = t.TMZS_TMZ
and so.group_id = '01'
and so.region_cd = 'RGN_stl_99'
and so.group_branch_id ='0101')
select *
from
(select
cc.group_branch_id as GpBr,
cc.mop_desc as Descr,
cast(SYSLIB.ERAC_GMT_TO_LCL(ph.pymt_dt, cc.ecr_tmz_name) AS timestamp(6)) as LocalPaydate,
cast(SYSLIB.ERAC_GMT_TO_LCL(ph.pymt_dt, cc.ecr_tmz_name) as date) as ph_pymt_dt,
dr.dvr_srnm as DriverFName,
dr.dvr_frst_name as DriverLName,
ph.name as HolderName,
pd.ticket_no as ECARS2,
cast( case when rb.ecr_lgcy_resv_nbr is null then
case when substr(pd.ticket_no,1,1) = 'D' then
'D'||substr(pd.ticket_no, 2,6)
else
null
end
else 'D'||rb.ecr_lgcy_resv_nbr
end as CHAR(7)) as ECARS1,
rb.rnt_agr_nbr as RntAgrNo,
case when ph.cr_card_trans_typ_cde='R' then
-1*pd.pymt_amt
else
pd.pymt_amt
end as AMOUNT,
pd.cur_curr_cd as Curr,
ph.CR_CARD_NBR as CardNo,
cast(ph.exp_dt as date format 'mm/yy') as ExpireDate,
cast(0 as decimal(15,3)) as AUTH_AMT,
cast(null as date format 'mm/dd/yyyy') as AuthDate,
ph.auth_nbr as AuthNo,
cast(null as char(2)) as Swipe,
cast(null as varchar(60)) as PType,
**pft.Settlement,
pft.First_Six**
from
dqry_cc cc,
rfs_rv.pre_applied_pymts_hdr ph,
rfs_rv.pre_applied_pymts_det pd
left outer join
(select
ra.rnt_agr_nbr,
ra.ecr_ticket_no,
ra.ecre_rent_cntrct_nbr,
ra.ecr_lgcy_resv_nbr,
cc.grp_brn_id --
from
rfs_rv.rnt_agrs ra,
dqry_cc cc
where ra.sta_stn_id_orig_co = cc.stn_id QUALIFY ROW_NUMBER() OVER(PARTITION BY ra.rnt_agr_nbr ORDER BY ra.rnt_agr_nbr) = 1
) rb
on pd.ticket_no = rb.ecr_ticket_no
left outer join
(select
dvr.dvr_srnm,
dvr.dvr_frst_name,
dvr.rdy_rnt_agr_nbr
from rfs_rv.dvr_rras dvr
where dvr.main_dvr_flg = 'MR'
) dr
on rb.rnt_agr_nbr = dr.rdy_rnt_agr_nbr
**left outer join
(select
ft.paymt_mdia_proc_sys_cde as Settlement,
ft.prim_acct_frst_six_dgt_nbr as First_Six,
ft.fin_tran_ref_id
from paymt.fin_tran ft) pft
on pft.fin_tran_ref_id = cast(ph.paph_fin_trans_ref_id as decimal(19,0))**
where ph.pymt_stn_id = cc.stn_stn_id
and ph.mop_mop_cd = cc.mop_cd
and ph.pymt_id = pd.pap_pymt_id
and ph_pymt_dt = 8/5/2015
) z
Your a mixing old and new style join syntax. Your problem would never exist if you followed this simple rule: Never use commas the FROM clause. Always use explicit JOIN syntax.
The problem is the scoping of around the comma operator. Although it is functionally equivalent to a CROSS JOIN, the first part is not a known alias for the second part.
If you fix FROM to remove all commas, your problem will be fixed, even if you only change the comma to a CROSS JOIN. However, I recommend using the proper JOIN.

Return only one row when multiple rows exist

I am working with a database that tracks field trip information for schools. The query will run on a MS SQL 2005 Server. There are a few cases when my query will return multiple rows for the same Field Trip. So, what I want to do is filter my results so that if more than one row per TripID is returned, display only the row with the MIN StartDateTime.
I know there's something I can do with the PARTITION and MIN functions but I'm not sure how to go about it.
Here is my code:
SELECT DISTINCT
dbo.Trip_TripInformation.RecordID AS TripID,
dbo.Trip_TripInformation.TripDate,
Origin.LocationName AS Origin,
dbo.Trip_TripInformation.OriginDepartureTime AS StartDateTime,
dbo.Trip_TripInformation.OriginReturnTime AS ReturnDateTime,
ISNULL(dbo.Trip_TripInformation.NoOfStudents, 0) AS NumberOfStudents,
ISNULL(dbo.Trip_TripInformation.NoOfAdults, 0) AS NumberOfAdults,
ISNULL(dbo.Trip_TripInformation.NoOfStudents, 0) + ISNULL(dbo.Trip_TripInformation.NoOfAdults, 0) AS NumberOfPassengers,
Destination.LocationName AS Destination,
dbo.Vehicles.Vehicle,
Driver.LastName + ', ' + Driver.FirstName AS Driver
FROM dbo.Trip_TripInformation
LEFT JOIN dbo.Trip_Location AS Origin ON Origin.RecordID = dbo.Trip_TripInformation.OriginLocationID
LEFT JOIN dbo.Trip_TripDestinations ON dbo.Trip_TripInformation.RecordID = dbo.Trip_TripDestinations.TripID
LEFT JOIN dbo.Trip_Location AS Destination ON Destination.RecordID = dbo.Trip_TripDestinations.LocationID
LEFT JOIN dbo.Trip_TripDriverVehicle ON dbo.Trip_TripInformation.RecordID = dbo.Trip_TripDriverVehicle.TripID
AND dbo.Trip_TripDriverVehicle.DestinationID = dbo.Trip_TripDestinations.RecordID
LEFT JOIN dbo.Vehicles ON dbo.Vehicles.RecordID = dbo.Trip_TripDriverVehicle.VehicleID
LEFT JOIN dbo.Employees AS Driver ON dbo.Trip_TripDriverVehicle.DriverID = Driver.RecordID
ORDER BY TripID
Order by StartDate and then select the TOP(1)
Try adding a row number to your select and selecting your data into a temp table (or use a CTE):
ROW_NUMBER() OVER ( PARTITION BY dbo.Trip_TripInformation.RecordID
ORDER BY dbo.Trip_TripInformation.OriginDepartureTime asc
) as RowNum
Then you can just select from that where RowNum = 1
You need to GROUP them.
Happy coding
You need to join to a derived table which extracts the unique TripId and earliest departure time for each trip:
SELECT DISTINCT
...
FROM dbo.Trip_TripInformation
INNER JOIN (
SELECT TripID, MIN(OriginDepartureTime) as EarliestDepartureTime
FROM Trip_TripInformation
GROUP BY TripID
) EarliestTripOnly
ON
Trip_TripInformation.TripID = EarliestTripOnly.TripId
AND
Trip_TripInformation.OriginDepartureTime
= EarliestTripOnly.EarliestDepartureTime
LEFT JOIN dbo.Trip_Location AS Origin ON Origin.RecordID =
dbo.Trip_TripInformation.OriginLocationID
...
You can use the Row_Number function to number each start date within each TripID. In addition, I encapsulated the query into a common-table expression so that I could then fitler on only those Trips where their row numbering was 1 which will represent the earliest date should a trip return multiple rows.
With TripInfo As
(
Select TInfo.RecordID As TripID
, TInfo.TripDate
, Origin.LocationName As Origin
, TInfo.OriginDepartureTime As StartDateTime
, TInfo.OriginReturnTime As ReturnDateTime
, Coalesce( TInfo.NoOfStudents, 0 ) As NumberOfStudents
, Coalesce( TInfo.NoOfAdults, 0) As NumberOfAdults
, Coalesce( TInfo.NoOfStudents, 0) + Coalesce(TInfo.NoOfAdults, 0) As NumberOfPassengers
, Dest.LocationName As Destination
, V.Vehicle
, Driver.LastName + ', ' + Driver.FirstName As Driver
, Row_Number() Over ( Partition By TInfo.RecordId
Order By TInfo.OriginDepartureTime ) As TripDateRnk
From dbo.Trip_TripInformation As TInfo
Left Join dbo.Trip_Location AS Origin
On Origin.RecordID = TInfo.OriginLocationID
Left Join dbo.Trip_TripDestinations As TDest
On TInfo.RecordID = TDest.TripID
Left Join dbo.Trip_Location AS Destination
On Destination.RecordID = TDest.LocationID
Left Join dbo.Trip_TripDriverVehicle As TripV
On TInfo.RecordID = TripV.TripID
And TripV.DestinationID = TDest.RecordID
Left Join dbo.Vehicles As V
ON dbo.Vehicles.RecordID = TripV.VehicleID
Left Join dbo.Employees AS Driver
On dbo.Trip_TripDriverVehicle.DriverID = Driver.RecordID
)
Select TripID, TripDate, Origin, StartDateTime, ReturnDateTime
, NumberOfStudents, NumberOfAdults, NumberOfPassengers
, Destination, Vehicle, Driver
From TripInfo
Where TripDateRank = 1
Order By TripID
A couple of other observations:
I notice that every table is using a Left Join. Is it really the case that all the columns in question are nullable? For example, is it really the case that the VehicleID and the DriverID columns in the Trip_TripDriverVehicle table are nullable? You can designate a trip driver vehicle without the vehicle and without a driver?
I would recommend using Coalesce function instead of the awfully named SQL Server-specific function IsNull. They operate pretty much the same but Coalesce is standard and allows for more than two parameters whereas IsNull is restricted to two. It won't make any significant difference with respect to your code or performance. It's just a style improvement.
SELECT * FROM
(SELECT DISTINCT RowNum = ROW_NUMBER() OVER (PARTITION BY TI.RecordID ORDER BY Trip_TripDestinations.DestinationArrivalTime),
TI.RecordID AS TripID,
TI.TripDate,
Origin.LocationName AS Origin,
TI.OriginDepartureTime AS StartDateTime,
TI.OriginReturnTime AS ReturnDateTime,
ISNULL(TI.NoOfStudents, 0) AS NumberOfStudents,
ISNULL(TI.NoOfAdults, 0) AS NumberOfAdults,
ISNULL(TI.NoOfStudents, 0) + ISNULL(TI.NoOfAdults, 0) AS NumberOfPassengers,
Destination.LocationName AS Destination,
Trip_TripDestinations.DestinationArrivalTime AS DestinationArrivalDateTime,
Vehicles.Vehicle,
Driver.LastName + ', ' + Driver.FirstName AS Driver
FROM Trip_TripInformation TI
LEFT OUTER JOIN Trip_Location AS Origin ON Origin.RecordID = TI.OriginLocationID
/*More Joins... */
LEFT OUTER JOIN Employees AS Driver ON Trip_TripDriverVehicle.DriverID = Driver.RecordID) Q1
WHERE Q1.RowNum = 1 and (Q1.TripDate BETWEEN '2010/12/13 00:00:00' AND '2010/12/17 00:00:00')
ORDER BY Q1.DestinationArrivalDateTime