三表SQL查询

时间:2013-11-03 09:58:26

标签: sql sql-server

我有一张桌子(车辆),其中包含一系列车辆。

VehicleID
PlateNo
CurrentDriver

我还有一张表(历史记录),其中包含车辆的驾驶员历史记录:

HistoryID
VehicleID
ReceivedDate (vehicle receiving date)
DriverName

我有另一张表(维修),其中包含所有车辆的维修费用:

RepairID
VehicleID
RepairDate
RepairCost

使用SQL Server并基于History表,我想获得给定DriverName的两个日期之间的所有RepairCost值。

例如,我想获得驱动程序'John Doe'的所有RepairCost值,在2013年1月1日到2013年5月1日之间,在那段时间内被分配给三辆不同的车辆。

到目前为止,我的查询是:

SELECT H.DriverName, R.RepairCost, R.RepairDate
  FROM Repairs AS R 
 INNER JOIN Vehicles AS V ON R.VehicleID = V.VehicleID 
 INNER JOIN History H ON H.VehicleID = V.VehicleID 
 WHERE H.DriverName = 'John' 
   AND R.RepairDate BETWEEN '01.01.2013' AND '04.01.2013'

SQL Fiddle中还有一些示例数据。

问题似乎是我得到了两次所有结果。

稍后编辑: 到目前为止我的进展:

DECLARE @Driver varchar(50),@StartDt datetime, @EndDt datetime

SELECT @Driver = 'John Doe',@StartDt = '20130101' ,@EndDt = '20130501'

;With VehicleAllocation
AS
(
SELECT h.*,h1.ChangeDate
FROM History h
OUTER APPLY (SELECT MIN(ReceivedDate) AS ChangeDate
FROM History
WHERE VehicleID = h.VehicleID
AND DriverName <> h.DriverName
AND ReceivedDate > h.ReceivedDate
)h1
WHERE h.DriverName = @Driver
)
SELECT *
FROM VehicleAllocation h
INNER JOIN Repairs r
ON r.VehicleID = h.VehicleID
WHERE DriverName = @Driver
AND RepairDate > = @StartDt
AND RepairDate < @EndDt + 1
AND RepairDate BETWEEN h.ReceivedDate AND COALESCE(h.ChangeDate,RepairDate)

我发现'AND DriverName&lt;&gt;行的问题h.DriverName”。为什么这条线有用?如果我在历史记录表中依次使用相同的驱动程序名称,则会跳过该驱动程序名称的最后一个汽车交付日期。

示例数据:

'历史'表

ReceivedDate  DriverName
04.11.2013    Mike
13.11.2013    Dan
15.11.2013    Dan
17.11.2013    Ryan
20.11.2013    Dan
22.11.2013    Ryan
25.11.2013    Mike
26.11.2013    Dan
29.11.2013    Ryan
04.12.2013    Dan

'维修'表

RepairDate RepairCost
05.11.2013 2615.30
14.11.2013 135.66
16.11.2013 4913.04
18.11.2013 538.92
21.11.2013 152.48
23.11.2013 5946.89
26.11.2013 3697.64
27.11.2013 734.01
30.11.2013 279.62

查询结果

RepairDate RepairCost
07.11.2013 380.00
14.11.2013 135.66
16.11.2013 4913.04
16.11.2013 4913.04
21.11.2013 152.48
27.11.2013 734.01

正如您在查询结果中看到的那样,第3行和第4行具有相同的值/日期。 查询间隔是01-01-2013&lt; - &gt; 31-12-2013。

另外,如果我想从不同的表中获取不同列的SUM,该怎么办? 例如,'Repairs'表中的SUM(Total)列,'Tires'表中的SUM(Value)列...

我该如何调整脚本?

谢谢!

2 个答案:

答案 0 :(得分:2)

我不知道您为什么在查询中包含您的车辆表,因为您不希望从那里获得任何信息。

您获得“双重”结果是因为您将每个修复(例如,1月15日的修复)与具有相同车辆ID的每个记录匹配为历史记录(其中有三个!)。其中两场比赛是为了驱动约翰,所以你得到两个结果。

您想要的是仅匹配根据您的历史记录表在维修时是驱动器的驱动程序!

所以,我首先将每个修复与历史表中实际匹配的Receiveddate匹配:

SELECT R1.Repairdate, Max(H1.ReceivedDate) as ReceivedDate
FROM Repairs R1
JOIN History H1 
  ON R1.VehicleID=H1.VehicleID 
 AND H1.ReceivedDate < R1.RepairDate

GROUP BY R1.RepairDate

然后我在联接中使用该查询来接收所需数据:

SELECT R.RepairDate, H.DriverName, R.RepairCost 
  FROM Repairs AS R 
  JOIN History H ON R.VehicleID=H.VehicleID 
  JOIN (
       SELECT R1.Repairdate, Max(H1.ReceivedDate) as ReceivedDate
         FROM Repairs R1
         JOIN History H1 
           ON R1.VehicleID=H1.VehicleID 
          AND H1.ReceivedDate < R1.RepairDate
        GROUP BY R1.RepairDate) 
        AS H2
    ON R.Repairdate = H2.Repairdate
   AND H.ReceivedDate = H2.Receiveddate
 WHERE R.RepairDate BETWEEN '01.01.2013' AND '04.01.2013' 
   AND H.DriverName = 'John'

这会返回6条记录:http://sqlfiddle.com/#!3/fcebf/62

作为完整性检查,请在完整的WHERE日期和名称上省略,并在选择中包含车辆编号。

您将获得14次维修,其中包含当时驾驶车辆的驾驶员姓名。根据您的历史数据,您可以轻松确认当时链接到车辆的驾驶员是否正确:

DRIVERNAME  VEHICLEID   REPAIRDATE  REPAIRCOST
John    1   January, 15 2013 00:00:00+0000  10
Ryan    2   January, 18 2013 00:00:00+0000  15
Ryan    2   January, 22 2013 00:00:00+0000  15
John    1   February, 03 2013 00:00:00+0000 5
Ryan    2   February, 05 2013 00:00:00+0000 25
John    1   February, 10 2013 00:00:00+0000 10
John    2   February, 26 2013 00:00:00+0000 10
Ryan    1   March, 01 2013 00:00:00+0000    100
John    2   March, 03 2013 00:00:00+0000    30
John    2   March, 08 2013 00:00:00+0000    5
Ryan    1   March, 10 2013 00:00:00+0000    45
Ryan    1   March, 17 2013 00:00:00+0000    25
Ryan    2   March, 25 2013 00:00:00+0000    10
Ryan    2   March, 28 2013 00:00:00+0000    30

答案 1 :(得分:0)

如果您将HistoryID添加到查询中,您会注意到行不重复,但它们具有不同的HistoryID,请尝试此查询

SELECT H.DriverName, R.RepairCost, R.RepairDate , H.HistoryID
FROM
    Repairs AS R
    INNER JOIN Vehicles AS V ON R.VehicleID=V.VehicleID
    INNER JOIN History H ON H.VehicleID=V.VehicleID 
WHERE H.DriverName='John' AND R.RepairDate BETWEEN '01.01.2013' AND '04.01.2013'

所以我认为你的数据有问题。

您可以使用DISTINCT删除这些重复的行,但我建议您仔细检查历史记录表数据