SQL Server筛选JOIN数据

时间:2014-03-30 13:15:53

标签: sql-server inner-join

我的流程工具数据有两张表, 第一个表有机器ID,跳闸时间,跳闸原因

Machine ID  Trip Time              Trip Reason
XA-065      03-20-2014 09:40:098    ANY
XA-065      03-24-2014 18:33:040    ANY
XA-765      03-23-2014 22:16:002    ANY
XA-070      03-21-2014 15:17:023    ANY

第二个表有机器ID,开始时间。

Machine ID  Start Time             Operator
XA-065      03-20-2014 12:40:098    ANY
XA-065      03-24-2014 20:33:040    ANY
XA-765      03-23-2014 23:16:002    ANY
XA-070      03-21-2014 18:17:023    ANY

我要加入这两个表,所以,对于每台机器,我可以获得机器ID,跳闸时间,开始时间,然后我可以添加一个计算列来获得停机时间“开始时间 - 旅行时间” 问题是,当同一台机器启动并多次跳闸时,JOIN操作会匹配所有可能的跳闸/启动组合。这导致错误的停机时间计算。 这是My Join的结果,注意Machine XA-065会发生什么:

Machine ID  Trip Time               Start Time              Downtime
XA-065      03-20-2014 09:40:098    03-20-2014 12:40:098    3 Hours
XA-065      03-20-2014 09:40:098    03-24-2014 20:33:040    **11 hours**
XA-065      03-24-2014 18:33:040    03-20-2014 12:40:098    **-6 Hours**
XA-065      03-24-2014 18:33:040    03-24-2014 20:33:040    2 Hours
XA-765      03-23-2014 22:16:002    03-23-2014 23:16:002    1 Hour
XA-070      03-21-2014 15:17:023    03-21-2014 18:17:023    3 Hours

因为JOIN将采用相同机器ID的所有可能组合,我得到错误的数据,11小时,-6小时的停机时间“第二和第三行”。 我怎样才能过滤JOIN操作以摆脱这种情况? 我按降序对这两个表进行了排序,因此,正确的值排在第一位,但我仍然得到错误的JOINED行。

非常感谢您的帮助。 A.A

2 个答案:

答案 0 :(得分:2)

试试这个。但如果在任一表中只有一条缺失记录,结果可能会有所不同。

<强>查询

SELECT A.MachineID
      ,A.TripTime
      ,B.StartTime
      ,DATEDIFF(HOUR, A.TripTime,B.StartTime) AS DownTime
FROM 
  (
  SELECT * 
    ,ROW_NUMBER() OVER (PARTITION BY MachineID ORDER BY TripTime ASC) AS RN
  FROM dbo.MachineTrip
  ) A
      INNER JOIN
  (
   SELECT * 
       ,ROW_NUMBER() OVER (PARTITION BY MachineID ORDER BY StartTime ASC) AS RN
   FROM dbo.MachineStart
   )B
ON A.MachineID = B.MachineID AND A.RN = B.RN

结果集

╔═══════════╦═════════════════════════╦═════════════════════════╦══════════╗
║ MachineID ║        TripTime         ║        StartTime        ║ DownTime ║
╠═══════════╬═════════════════════════╬═════════════════════════╬══════════╣
║ XA-065    ║ 2014-03-20 09:40:00.097 ║ 2014-03-20 12:40:00.097 ║        3 ║
║ XA-065    ║ 2014-03-24 18:33:00.040 ║ 2014-03-24 20:33:00.040 ║        2 ║
║ XA-070    ║ 2014-03-21 15:17:00.023 ║ 2014-03-21 18:17:00.023 ║        3 ║
║ XA-765    ║ 2014-03-23 22:16:00.003 ║ 2014-03-23 23:16:00.003 ║        1 ║
╚═══════════╩═════════════════════════╩═════════════════════════╩══════════╝

Working SQL FIDDLE

<强>建议

您的架构需要一些认真的关注。你应该在这两个表之间有一个外键约束,它将一个表中的记录绑定到另一个表中的记录。

您可以将一个表中的所有记录与一个将两个相关行绑定在一起的列和一个列(可能是一个位列)组成,该列指示记录是开始时间还是行程时间。

您的架构非常容易出错。

答案 1 :(得分:0)

您也可以通过加入和聚合来执行此操作。如果连续丢失记录或多个开始记录,这会更加健壮。

select mt.MachineId, mt.TripTime, min(ms.StartTime) as StartTime,
       datediff(hour, mt.TripTime, min(ms.StartTime)) as HoursDifference
from MachineTrip mt join
     MachineStart ms
     on mt.MachineId = ms.MachineId and
        mt.TripTime < ms.StartTime
group by mt.MachineId, mt.TripTime;

注意我使用了与Ali相同的命名约定,因此您可以在SQL Fiddle上尝试它。