【问题标题】:SQL between subquery子查询之间的 SQL
【发布时间】:2012-08-09 08:15:39
【问题描述】:

我想知道如何运行一个返回事件的 SQL 查询,该事件的时间在有效段中。

比如我有两张表,

活动

event_id event_time
0        134
1        434
2        4300

细分

segment_type segment_start_time segment_end_time
data1         100                130
data1         200                500
data1         700                8000
veto1         400                440
data2         150                450
data2         4000               5000
veto2         175                200

我想要一个可以返回的查询

event_id event_time
1        434
2        4300

我在想类似的事情

SELECT * 
FROM event
WHERE 
    event.event_time > (SELECT segment.segment_start_time FROM segment)
    AND 
    event.event_time < (SELECT segment.segment_end_time FROM segment)

但这只是什么都不返回。我做错了什么?

我要做的下一步是找到事件时间;

在“数据”段开始时间和结束时间之间 AND 不在“否决”段开始时间和结束时间之间

最后,我实际上有两种类型的数据段和否决段。我想返回有时间的事件;

在“data1”段开始时间和结束时间之间与

在“data2”段开始时间和结束时间之间与

不在“veto1”段开始时间和结束时间之间并且

不在“veto2”段的开始时间和结束时间之间

所以从我上面的示例表中,我想要的输出是

event_id event_time
2        4300

【问题讨论】:

  • 不同的片段会重叠吗? eventssegements 会有更多记录吗?
  • 您使用的是什么数据库和版本?
  • 片段可能重叠,但只有不同“类型”的片段 - 请参阅下面的评论。我正在使用 SQlite 3.7.13

标签: sql subquery


【解决方案1】:

我将假设事件表中的条目通常比段表中的条目多。

这允许伪代码“对于每个段,检查哪些事件是有效的”。这允许在事件表上进行范围搜索。

SELECT
  event.event_id, event.event_time
FROM
  segment
INNER JOIN
  event
    ON  event.event_time >= segment.segment_start_time
    AND event.event_time <  segment.segment_end_time
GROUP BY
  event.event_id, event.event_time

仅当segment 中的不同条目可以重叠时才需要GROUP BY


另一种方法是使用伪代码“对于每个事件,检查是否有任何片段与其重叠”。

但是,这样做将不允许范围搜索(请参阅我对@MarkByers 回答的评论)


编辑在编辑问题后...

据我了解更改,只有在以下情况下才应返回事件......

  • 事件时间在至少之内(一个data1段和一个data2段)
  • 事件时间不在(任何 veto1 段或任何 veto2 段)内


SELECT
  event.event_id, event.event_time
FROM
  segment
INNER JOIN
  event
    ON  event.event_time >= segment.segment_start_time
    AND event.event_time <  segment.segment_end_time
GROUP BY
  event.event_id, event.event_time
HAVING
      0 = SUM(CASE WHEN segment_type = 'veto1' THEN 1 ELSE 0 END)
  AND 0 = SUM(CASE WHEN segment_type = 'veto2' THEN 1 ELSE 0 END)
  AND 1 = SUM(CASE WHEN segment_type = 'data1' THEN 1 ELSE 0 END)
  AND 1 = SUM(CASE WHEN segment_type = 'data2' THEN 1 ELSE 0 END)

【讨论】:

  • 谢谢@Dems。这似乎有效。是的,有些部分可以重叠。但更准确地说,段表有四种不同的段; data1 和 data2,veto1 和 veto2。我实际上想列出时间在 ((data1 - veto1) 交集 (data2 - veto1)) 中的事件。
  • @ShaunH - 我不确定你所说的 ((data1 - veto1) intersection (data2 - veto1)) 是什么意思。请您使用示例数据和演示真实场景的所需输出来更新您的问题?
  • 我已经编辑了这个问题。对不起,如果这听起来很复杂,这就是为什么我一开始没有说明所有这些
  • @ShaunH - 添加了一个 HAVING 子句,因为我最了解你的示例。
  • 抱歉,这不起作用。但我认为逻辑是错误的。事件时间必须在两种数据段的 intersection 中(即它有一个 data1 段和一个 data2 段)。我想我已经使用查询解决了这个问题 - 见下文。
【解决方案2】:

使用WHERE EXISTS 或加入。

SELECT event_id, event_time
FROM event
WHERE EXISTS
(
   SELECT *
   FROM segment
   WHERE event.event_time BETWEEN segment_start_time AND segment_end_time
)

【讨论】:

  • 假设索引为segment(start, end),这意味着从0event.event_time 的每个segmentstart 都需要检查其end。半笛卡尔积...
【解决方案3】:

如果段不重叠,您也可以使用它(适应 TOPLIMIT 或任何专有语法,如果您的 DBMS 已实现 OFFSET / FETCH 语法):

SELECT
    event_id, event_time
FROM
    event AS e
WHERE 
    event_time <
    ( SELECT 
          s.segment_end_time
      FROM 
          segment AS s
      WHERE
          s.segment_start_time <= e.event_time
      ORDER BY 
          s.segment_start_time DESC
        OFFSET 1 ROWS
        FETCH NEXT 1 ROWS ONLY
    ) ;

【讨论】:

    【解决方案4】:

    我认为这是我正在寻找的查询,但我不是 100% 确定。

    SELECT *
    FROM event
    WHERE EXISTS
    (
       SELECT *
       FROM segment
       WHERE (event.time BETWEEN segment.start_time AND segment.end_time
                         AND segment.type IN ("data1", "data2"))
    ) AND EXISTS
    (
       SELECT *
       FROM segment
       WHERE (event.time NOT BETWEEN segment.start_time AND segment.end_time 
                         AND segment.type ("veto1", "veto2"))
    )
    

    【讨论】:

    • 对于第二个EXISTS,如果event_time 不在否决权的ANY 之外,它将返回TRUE。因此,即使它与 veto1 冲突,它仍然在 veto2 之外,因此整体条件为真,即使您希望它为假。查看此链接...sqlfiddle.com/#!5/f6957/1 (我的仅返回事件 2,您的返回事件 1 和 2)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 2010-12-21
    相关资源
    最近更新 更多