【问题标题】:SQL Child relation query helpSQL 子关系查询帮助
【发布时间】:2010-11-06 20:26:53
【问题描述】:

我有一个看起来像这样的一对多关系:

| Parent |  | Child  |
|   id   |  |   id   |
|        |  |parentID|
|        |  |  date  |

我正在尝试构建一个查询,以便我获取所有有孩子记录的父母,这些记录的日期都在指定日期之前。

像这样的

SELECT * FROM parent
JOIN child on child.parentid = parent.id
WHERE child.date <= '10/13/2010'

但问题是我得到的父母有孩子的日期在指定日期之前,而孩子的记录日期在指定日期之后,而我只想要日期在给定日期之前的孩子的父母。

有人对如何处理这种情况有一些建议吗?

谢谢!

【问题讨论】:

    标签: sql database


    【解决方案1】:

    用途:

    SELECT p.*
      FROM PARENT p
     WHERE EXISTS(SELECT NULL
                    FROM CHILD c
                   WHERE c.parentid = p.id
                     AND c.date <= '2010-10-13')
       AND NOT EXISTS(SELECT NULL
                        FROM CHILD c
                       WHERE c.parentid = p.id
                         AND c.date > '2010-10-13')
    

    每个人都会告诉你使用 JOIN,“因为它们更快”,但通常他们不知道使用它们的影响——如果你不需要来自支持表,你不应该加入它。这是因为在这种情况下不止一个孩子会产生重复的 PARENT 记录。 JOIN 和 DISTINCT 或 GROUP BY 与 IN 或 EXISTS 之间的权衡可能是同等的,但没有正确处理重复数据的麻烦。

    【讨论】:

    • 这不会仍然吸引那些有孩子的父母在给定日期之前和之后的日期都有孩子吗?我只想要孩子日期在任何时候之前的父母
    • 你是冠军,之前不知道exists运算符和在sql中选择null。非常感谢!
    • 在考虑性能时,还需要考虑使用相关子查询的影响,也就是你上面使用的。实际上,连接可能更快。 (我知道这完全取决于数据模型、索引、键等。)确定的唯一方法是分析查询。
    • @beach:相关的 EXISTS 与相关的 IN 子查询的工作方式不同 - EXISTS 退出匹配条件的第一个实例。除了我现有的关于使用 JOIN 造成的创纪录通货膨胀以及所涉及的性能权衡之外,这还不包括在内。
    • 示例中的轻微错字。 NOT EXISTS 语句之前的“WHERE”应该是 AND。
    【解决方案2】:
    SELECT
      *
    FROM
      Parent
    WHERE
      EXISTS (SELECT * FROM Child WHERE Child.ParentId = Parent.Id AND [date] <= '2010-10-13')
      AND
      NOT EXISTS (SELECT * FROM Child WHERE Child.ParentId = Parent.Id AND [date] > '2010-10-13')
    

    【讨论】:

      【解决方案3】:

      我仔细阅读了您的问题并总结如下:

      • 子行可能存在于日期 X 之前、之后或之后
      • 我希望所有孩子的父母都有一个日期 X 日期/之前的日期

      见下面的代码。我们使用 HAVING 语句来确保孩子在 X 之后没有日期。

      SELECT P.*
      FROM Parent P
      WHERE P.id IN
      (
          SELECT C.parentID
          FROM Child C
          GROUP BY C.parentID
          HAVING MAX(CASE WHEN date > '2010-10-13' THEN 1 ELSE 0 END) = 0
          /* do not return children that have a date after 2010-10-13 */
      )   
      

      为那些想要一起玩的人提供示例架构。 (SQL 服务器)

      (“date”被称为“mydate”以避免必须转义保留字。)

      CREATE TABLE Parent (id INT PRIMARY KEY);
      CREATE TABLE Child (id INT IDENTITY PRIMARY KEY, parentID INT NOT NULL REFERENCES Parent(id), mydate DATE );
      
      INSERT INTO Parent VALUES (1);
      INSERT INTO Parent VALUES (2);
      INSERT INTO Parent VALUES (3);
      INSERT INTO Parent VALUES (4);
      
      INSERT INTO Child (parentID, mydate) VALUES (1,'2010-10-11')
      INSERT INTO Child (parentID, mydate) VALUES (1,'2010-10-12')
      INSERT INTO Child (parentID, mydate) VALUES (1,'2010-10-13')
      
      INSERT INTO Child (parentID, mydate) VALUES (2,'2010-10-12')
      INSERT INTO Child (parentID, mydate) VALUES (2,'2010-10-13')
      INSERT INTO Child (parentID, mydate) VALUES (2,'2010-10-14')
      
      INSERT INTO Child (parentID, mydate) VALUES (3,'2010-10-14')
      INSERT INTO Child (parentID, mydate) VALUES (3,'2010-10-15')
      INSERT INTO Child (parentID, mydate) VALUES (3,'2010-10-16')
      

      【讨论】:

      • 我应该注意这是通过 Child 表的单次传递吗?