MySQL:自连接以生成日期对

MySQL:自连接以生成日期对,mysql,select,join,Mysql,Select,Join,我有一个表,其中包含“丢失”和“找到”项目的条目。每行都有事件的日期。我希望通过将表连接到自身来构建一个具有匹配对“itemid”、“lost date”、“find date”的查询 这在一定程度上起作用:不幸的是,如果给定项目有多个丢失和找回对,则每个“丢失日期”都将与其后的所有“找到日期”合并 还和我在一起吗 查询类似于: select c0.ItemId, c0.ChangeDate, c1.ChangeDate from Changes c0 join Changes c1 on

我有一个表,其中包含“丢失”和“找到”项目的条目。每行都有事件的日期。我希望通过将表连接到自身来构建一个具有匹配对“itemid”、“lost date”、“find date”的查询

这在一定程度上起作用:不幸的是,如果给定项目有多个丢失和找回对,则每个“丢失日期”都将与其后的所有“找到日期”合并

还和我在一起吗

查询类似于:

select c0.ItemId, c0.ChangeDate, c1.ChangeDate from Changes c0
join Changes c1 on 
   c0.ItemId = c1.ItemId and c1.ChangeDate >= c0.ChangeDate
where c0.ChangeType = 9 (lost) and c1.ChangeType = 10 (found);
我希望实现的是某种形式的给定“丢失日期”与序列中的下一个“找到日期”配对,或者如果不存在“找到日期”,则为空。我很确定这是可能的,但我看不到路


我想知道如何在第一个连接中放置一个子选择,并使用LIMIT 1只获取一条记录,但我不知道如何将其连接到选择的主要部分中的相应行。MySQL告诉我它不存在。很公平

通常,在处理成对的日期时,例如计划的开始/结束,建议不要将它们放在单独的行中。将它们放在同一行的两列中。看

但也就是说,您可以使用当前模式通过搜索执行另一个自连接来搜索两者之间的变更日期来解决此问题。如果未找到,也就是说,如果c2.*由于外部联接而为空,则c0和c1相邻

select c0.ItemId, c0.ChangeDate, c1.ChangeDate 
from Changes c0
inner join Changes c1 on 
   c0.ItemId = c1.ItemId and c1.ChangeDate > c0.ChangeDate
left outer join Changes c2 on
   c0.ItemId = c2.ItemId and c2.ChangeDate > c0.ChangeDate 
                         and c2.ChangeDate < c1.ChangeDate 
                         and c2.ChangeType IN (9,10) -- edit
where c0.ChangeType = 9 (lost) and c1.ChangeType = 10 (found)
   and c2.ItemId IS NULL;

在上面的示例中,我假设ChangeDate是唯一的,并将>=更改为>。如果ChangeDate不是唯一的,您必须想出一些其他表达式来测试c0和c1之间的c2。

通常在处理成对的日期时(例如,计划的开始/结束),建议是不要将它们放在单独的行中。将它们放在同一行的两列中。看

但也就是说,您可以使用当前模式通过搜索执行另一个自连接来搜索两者之间的变更日期来解决此问题。如果未找到,也就是说,如果c2.*由于外部联接而为空,则c0和c1相邻

select c0.ItemId, c0.ChangeDate, c1.ChangeDate 
from Changes c0
inner join Changes c1 on 
   c0.ItemId = c1.ItemId and c1.ChangeDate > c0.ChangeDate
left outer join Changes c2 on
   c0.ItemId = c2.ItemId and c2.ChangeDate > c0.ChangeDate 
                         and c2.ChangeDate < c1.ChangeDate 
                         and c2.ChangeType IN (9,10) -- edit
where c0.ChangeType = 9 (lost) and c1.ChangeType = 10 (found)
   and c2.ItemId IS NULL;

在上面的示例中,我假设ChangeDate是唯一的,并将>=更改为>。如果ChangeDate不是唯一的,那么您必须想出一些其他表达式来测试c0和c1之间的c2。

这里的技巧是规定“在丢失和找到的日期之间没有其他丢失或找到的日期”,或者在SQL中:

SELECT c0.ItemId, c0.ChangeDate, c1.ChangeDate
  FROM Changes AS c0
  JOIN Changes AS c1 ON c0.ItemId = c1.ItemId AND c1.ChangeDate >= c0.ChangeDate
 WHERE c0.ChangeType = 9   -- Lost
   AND c1.ChangeType = 10  -- Found
   AND NOT EXISTS(SELECT *
                    FROM Changes AS c2
                   WHERE c2.ItemId = c1.ItemID
                     AND c2.ChangeType IN (9, 10) -- Lost or Found
                     AND c2.ChangeDate BETWEEN c0.ChangeDate AND c1.ChangeDate
                     AND (c2.ChangeDate != c0.ChangeDate AND c2.ChangeDate != c1.ChangeDate)
                 );
因为这是一个相关的子查询,所以它倾向于减慢查询速度,但它应该生成正确的行

关于我消除c0和c1行的方式,有一个重要的警告,即规定c2中行的更改日期应不同于丢失日期或找到日期。但是,主查询似乎允许在项目丢失的同一天找到该项目。可能还有其他一些列(如ChangeId列)未在查询中提及,但可以使用它们:

AND c2.ChangeID NOT IN (c0.ChangeID, c1.ChangeID)

你需要考虑一下,如果一件物品在2011-06-07丢失,然后在2011-06-14再次丢失,直到2011-06-21才被找到,会发生什么情况。如果在2011年6月28日也发现了呢?这些问题应该通过数据输入处理来防止,因此上面的查询假设不会出现这些问题。

这里的技巧是规定“在丢失和找到日期之间没有其他丢失或找到日期”,或者,在SQL中:

SELECT c0.ItemId, c0.ChangeDate, c1.ChangeDate
  FROM Changes AS c0
  JOIN Changes AS c1 ON c0.ItemId = c1.ItemId AND c1.ChangeDate >= c0.ChangeDate
 WHERE c0.ChangeType = 9   -- Lost
   AND c1.ChangeType = 10  -- Found
   AND NOT EXISTS(SELECT *
                    FROM Changes AS c2
                   WHERE c2.ItemId = c1.ItemID
                     AND c2.ChangeType IN (9, 10) -- Lost or Found
                     AND c2.ChangeDate BETWEEN c0.ChangeDate AND c1.ChangeDate
                     AND (c2.ChangeDate != c0.ChangeDate AND c2.ChangeDate != c1.ChangeDate)
                 );
因为这是一个相关的子查询,所以它倾向于减慢查询速度,但它应该生成正确的行

关于我消除c0和c1行的方式,有一个重要的警告,即规定c2中行的更改日期应不同于丢失日期或找到日期。但是,主查询似乎允许在项目丢失的同一天找到该项目。可能还有其他一些列(如ChangeId列)未在查询中提及,但可以使用它们:

AND c2.ChangeID NOT IN (c0.ChangeID, c1.ChangeID)

你需要考虑一下,如果一件物品在2011-06-07丢失,然后在2011-06-14再次丢失,直到2011-06-21才被找到,会发生什么情况。如果在2011年6月28日也发现了呢?这样的问题应该通过数据输入处理来防止,因此上面的查询假设不会有这样的问题。

与我写的非常相似。如果在失物招领日期之间有一个ChangeType 8,比如“电话查询”记录,你将拒绝失物招领记录。这与我写的非常相似。如果在失物招领日期之间有一个ChangeType 8,比如“电话查询”记录,你将拒绝失物招领记录。我选择了这个,因为它看起来更容易阅读。我在使用中所做的更改是将“ChangeType=10”移动到联接中,并将联接设置为单面,这样它将拾取项目仍然丢失的情况。我选择了这一个,因为它看起来更容易阅读。我在使用中所做的更改是将“ChangeType=10”移动到联接中,并将联接设置为单侧,这样它将拾取仍丢失项目的情况。