Вернуть только одну строку, если существует несколько строк - PullRequest
0 голосов
/ 01 марта 2011

Я работаю с базой данных, которая отслеживает информацию о поездках в школы.Запрос будет выполняться на сервере MS SQL 2005.Есть несколько случаев, когда мой запрос будет возвращать несколько строк для одной и той же поездки.Итак, я хочу отфильтровать результаты так, чтобы , если возвращено более одной строки на 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 ]

3 голосов
/ 01 марта 2011

Order by StartDate и затем выберите TOP(1)

1 голос
/ 01 марта 2011

Попробуйте добавить номер строки к вашему выбору и выбрать ваши данные во временную таблицу (или использовать CTE):

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

Тогда вы можете просто выбрать из того, где RowNum = 1

1 голос
/ 01 марта 2011

Вам нужно сгруппировать их.

Счастливого кодирования

0 голосов
/ 02 марта 2011
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
0 голосов
/ 01 марта 2011

Вы можете использовать функцию Row_Number для нумерации каждой даты начала в каждом TripID. Кроме того, я инкапсулировал запрос в выражении общей таблицы, чтобы затем использовать его только для тех поездок, где их нумерация строк была равна 1, что будет представлять самую раннюю дату, если поездка возвратит несколько строк.

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. Я заметил, что каждая таблица использует левое соединение. Действительно ли так, что все рассматриваемые столбцы обнуляются? Например, действительно ли так, что столбцы VehicleID и DriverID в таблице Trip_TripDriverVehicle обнуляются? Вы можете обозначить водителя транспортного средства без транспортного средства и без водителя?

  2. Я бы рекомендовал использовать функцию Coalesce вместо ужасно названной специфичной для SQL Server функции IsNull. Они работают примерно так же, но Coalesce является стандартным и допускает более двух параметров, тогда как IsNull ограничен двумя. Это не будет иметь существенного значения в отношении вашего кода или производительности. Это просто улучшение стиля.

0 голосов
/ 01 марта 2011

Вам необходимо присоединиться к производной таблице, которая извлекает уникальный 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    
    ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...