【问题标题】:SQL Server Filtering JOIN DataSQL Server 过滤 JOIN 数据
【发布时间】:2014-03-30 13:15:52
【问题描述】:

我的过程仪表数据有两个表, 第一个表有机器 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 的结果,注意机器 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

【问题讨论】:

  • 如果我正确理解您的情况,第二个表中的每个“开始时间”都对应于第一个表中的一个“行程时间”。那么你的数据库模式一开始就是错误的;你应该把它们都放在一张桌子上。
  • 当出现这种情况时,您要过滤掉哪些记录? IOW,在此示例中,您对机器 XA-065 期望什么结果? Start Time 是否应该总是晚于Trip Time 才能产生有效结果?
  • 我只期待第一行和第三行,XA-065 03-20-2014 09:40:098 03-20-2014 12:40:098 3Hours XA-065 03-24- 2014 18:33:040 03-24-2014 20:33:040 2 小时

标签: sql-server inner-join


【解决方案1】:

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

查询

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

建议

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

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

您的架构非常容易出错。

【讨论】:

  • 嗯,我真的很感谢你的回答“还没有尝试过”,我什至没有做过 SQL 查询,我不知道什么是模式,我试图创建一个表的主键,外键,但我不能。我想我应该读一下这个,如果你能建议一个开始的来源,我将不胜感激。
  • 不是问题,但请记住,当您工作/学习使用任何 RDBMS 时,您必须非常了解表之间的外键/关系。如果你不知道这就像在不知道如何从跑道起飞的情况下学习驾驶飞机:)。阅读这里FOREIGN KEY Constraints
【解决方案2】:

您也可以通过连接和聚合来做到这一点。如果您缺少记录或连续有多个开始记录,这会更加稳健。

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 上试用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多