存在多行时仅返回一行

时间:2011-03-01 17:10:29

标签: sql sql-server tsql

我正在使用一个跟踪学校实地考察信息的数据库。该查询将在MS SQL 2005 Server上运行。在某些情况下,我的查询将返回同一Field Trip的多行。所以,我想要做的是过滤我的结果,以便如果每个TripID返回多行,则只显示MIN StartDateTime的行。

我知道我可以用PARTITION和MIN函数做些什么,但我不知道该怎么做。

这是我的代码:

 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

6 个答案:

答案 0 :(得分:3)

Order by StartDate然后选择TOP(1)

答案 1 :(得分:1)

你需要对它们进行分组。

快乐编码

答案 2 :(得分:1)

尝试在您的选择中添加行号并将数据选择到临时表(或使用CTE):

ROW_NUMBER() OVER ( PARTITION BY dbo.Trip_TripInformation.RecordID 
                    ORDER BY dbo.Trip_TripInformation.OriginDepartureTime asc
                  ) as RowNum

然后你可以从RowNum = 1

的地方选择

答案 3 :(得分:0)

您需要加入一个派生表,该表格为每次旅行提取唯一的TripId和最早的出发时间:

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    
    ...

答案 4 :(得分:0)

您可以使用Row_Number函数为每个TripID中的每个开始日期编号。另外,我将查询封装到一个公用表表达式中,这样我就可以在那些行编号为1的Trips上装配,这将代表一个行程返回多行的最早日期。

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

其他一些观察结果:

  1. 我注意到每个表都使用了Left Join。是否所有列都可以为空?例如,Trip_TripDriverVehicle表中的VehicleID和DriverID列是否可以为空?您可以在没有车辆且没有驾驶员的情况下指定行车司机车辆吗?

  2. 我建议使用Coalesce函数,而不是名称特定于SQL Server的函数IsNull。它们的操作几乎相同,但Coalesce是标准的,允许两个以上的参数,而IsNull仅限于两个。它不会对您的代码或性能产生任何重大影响。这只是一种风格改进。

答案 5 :(得分:0)

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
相关问题