Sql 当存在多行时,仅返回一行
我正在使用一个数据库来跟踪学校的实地考察信息。查询将在MS SQL 2005服务器上运行。在一些情况下,我的查询将为同一次实地考察返回多行。因此,我要做的是过滤我的结果,以便如果每个TripID返回多行,则仅显示具有最小StartDateTime的行。 我知道我可以用分区和MIN函数做一些事情,但我不知道该怎么做 这是我的密码:Sql 当存在多行时,仅返回一行,sql,sql-server,tsql,Sql,Sql Server,Tsql,我正在使用一个数据库来跟踪学校的实地考察信息。查询将在MS SQL 2005服务器上运行。在一些情况下,我的查询将为同一次实地考察返回多行。因此,我要做的是过滤我的结果,以便如果每个TripID返回多行,则仅显示具有最小StartDateTime的行。 我知道我可以用分区和MIN函数做一些事情,但我不知道该怎么做 这是我的密码: SELECT DISTINCT dbo.Trip_TripInformation.RecordID AS TripID, db
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
你需要把他们分组
快乐编码您需要对它们进行分组
快乐编码
按起始日期排序
,然后选择顶部(1)
按起始日期排序
,然后选择顶部(1)尝试在选择中添加行号,并将数据选择到临时表中(或使用CTE):
然后,您可以从RowNum=1的位置进行选择,尝试向select中添加行号,并将数据选择到临时表中(或使用CTE):
然后,您可以从RowNum=1中选择,您需要连接到一个派生表,该表提取每次旅行的唯一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
...
您需要加入一个派生表,该表提取每次旅行的唯一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
...
您可以使用Row_Number函数对每个TripID中的每个开始日期进行编号。此外,我将查询封装到一个公共表表达式中,这样我就可以只对那些行编号为1的行程进行fitler,如果行程返回多行,那么这些行程将表示最早的日期
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
还有几个其他的观察结果:
我注意到每个表都使用左连接。是否所有相关列都可以为空?例如,Trip_TripDriverHicle表中的VehicleID和DriverID列是否真的可以为空?您可以指定一辆没有车辆和没有驾驶员的行车驾驶员车辆
我建议使用Coalesce
函数,而不要使用命名错误的SQL Server特定函数IsNull
。它们的操作基本相同,但Coalesce是标准的,允许两个以上的参数,而IsNull
仅限于两个。它不会对您的代码或性能产生任何重大影响。这只是风格上的改进
您可以使用Row_Number函数对每个TripID中的每个开始日期进行编号。此外,我将查询封装到一个公共表表达式中,这样我就可以只对那些行编号为1的行程进行fitler,如果行程返回多行,那么这些行程将表示最早的日期
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
还有几个其他的观察结果:
我注意到每个表都使用左连接。是否所有相关列都可以为空?例如,Trip_TripDriverHicle表中的VehicleID和DriverID列是否真的可以为空?您可以指定一辆没有车辆和没有驾驶员的行车驾驶员车辆
我建议使用Coalesce
函数,而不要使用命名错误的SQL Server特定函数IsNull
。它们的操作基本相同,但Coalesce是标准的,允许两个以上的参数,而IsNull
仅限于两个。它不会对您的代码或性能产生任何重大影响。这只是风格上的改进
杜德。。。表别名将使其更具可读性。而且标签是正确的--“microsoft”太通用了欢迎使用堆栈溢出:DDuude。。。表别名将使其更具可读性。标记是正确的--“microsoft”太通用了欢迎使用堆栈溢出:在这个实例中,COALESCE
不会有任何区别。@Martin-不过,看看链接,这可能可以通过重写查询来处理,将子查询放入派生表中,然后使用COALESCE。合并转化为案例。。When是SQL spec的一部分。@Martin-值得注意的是,Connect文章是三年前的。我想知道它是在R2中寻址还是将在Denali中寻址。在这个例子中,COALESCE
不会有任何区别。@Martin-不过,看看链接,这可能可以通过重写查询来处理,将子查询放入派生表中,然后使用COALESCE。合并转化为案例。。When是SQL spec的一部分。@Martin-值得注意的是,Connect文章是三年前的。我不知道它是用R2写的还是会用Denali写的。我认为这行不通。我可能有一次带多个目的地的实地考察。这将为该TripID生成两行(即TripID 1)。这可能会发生在另一次旅行中(假设TripID=2),我不想只返回整个表的顶部,而是按DestinationArrivalDateTime的顺序返回每个TripID的顶部。我认为这行不通。我可能有一次带多个目的地的实地考察。这将为该TripID生成两行(即TripID 1)。这可能会发生在另一次旅行中(假设TripID=2),我不想只返回整个表的顶部,而是返回DestinationArrivalDateTime命令的每个TripID的顶部。