SQL查询-连接上的子查询 简介

SQL查询-连接上的子查询 简介,sql,oracle,Sql,Oracle,我需要为Oracle数据库编写一个复杂的查询。为了避免使用公司数据,我试着做了一个类比,所以如果有什么奇怪的事情,请告诉我 桌子 猫 猫ID PK 小猫 小猫身份证 猫咪玩耍 播放ID PK CAT_ID FK至CAT表 小猫标识FK到小猫表 小猫性别串-M或F 播放时间日期 小猫信息 小猫标识FK到小猫表 名称字符串,例如名称 值字符串,例如Duchess 描述 所以基本上,CAT和KITTEN表只保存id和其他一些随机信息。KITTEN_信息包含小猫的名字和其他信息。猫和小猫玩耍记录了猫和小

我需要为Oracle数据库编写一个复杂的查询。为了避免使用公司数据,我试着做了一个类比,所以如果有什么奇怪的事情,请告诉我

桌子 猫

猫ID PK 小猫

小猫身份证 猫咪玩耍

播放ID PK CAT_ID FK至CAT表 小猫标识FK到小猫表 小猫性别串-M或F 播放时间日期 小猫信息

小猫标识FK到小猫表 名称字符串,例如名称 值字符串,例如Duchess 描述 所以基本上,CAT和KITTEN表只保存id和其他一些随机信息。KITTEN_信息包含小猫的名字和其他信息。猫和小猫玩耍记录了猫和小猫玩耍的所有时间

我需要的是编写一个查询,返回最近与一只雄性小猫玩耍的时间在某个日期范围内的所有猫。我们称之为2011年1月1日至2011年1月31日。我还需要包括玩的日期和猫最近玩过的公猫和母猫的名字

目前为止 以下是我目前的情况:

SELECT cat.*, lastMale.PLAY_TIME maleTime, lastFemale.PLAY_TIME femaleTime, maleName.VALUE male, femaleName.VALUE female
FROM CAT cat
LEFT JOIN CAT_KITTEN_PLAY lastMale ON lastMale.CAT_ID = cat.CAT_ID 
                                  AND lastMale.GENDER = 'M'
LEFT JOIN CAT_KITTEN_PLAY lastFemale ON lastFemale.CAT_ID = cat.CAT_ID 
                                    AND lastFemale.GENDER = 'F'
LEFT JOIN KITTEN_INFO femaleName ON femaleName.KITTEN_ID = lastFemale.KITTEN_ID 
                                AND maleName.NAME = 'Name'
LEFT JOIN KITTEN_INFO maleName ON maleName.KITTEN_ID = lastMale.KITTEN_ID 
                              AND femaleName.NAME = 'Name'
    WHERE lastMale.PLAY_TIME BETWEEN '01-JAN-2011 12:00:00 AM'
                                 AND '31-JAN-2011 11:59:59 PM'
问题 这并不能解释一只猫可能不止一次地和一只母猫玩耍。因此,我想将和lastMale.PLAY_TIME=从CAT_KITTEN_PLAY中选择MAXPLAY_TIME,其中CAT_ID=CAT.ID和KITTEN_GENDER='M'添加到第一个连接中,并在第二个连接中添加一个类似的连接。但是联接上不允许子查询


有什么想法吗?请注意,猫可能从未与母猫玩耍过。但如果猫符合标准,则仍应将其包括在内,因此左侧加入。

仅为最后一场比赛的次数,而不是小猫的名字:

SELECT cat.CAT_ID
     , MAX(play.PLAY_TIME) AS maleTime
     , ( SELECT MAX(playf.PLAY_TIME)
         FROM CAT_KITTEN_PLAY AS playf
         WHERE playf.CAT_ID = cat.CAT_ID
           AND playf.KITTEN_GENDER = 'F'
       ) AS femaleTime
FROM CAT AS cat
  JOIN CAT_KITTEN_PLAY AS play
    ON play.CAT_ID = cat.CAT_ID
WHERE play.KITTEN_GENDER = 'M'
GROUP BY cat.CAT_ID 
HAVING MAX(play.PLAY_TIME) BETWEEN '01-JAN-2011 12:00:00 AM'
                               AND '31-JAN-2011 11:59:59 PM'
我完全不确定这是否有效:

SELECT cat.CAT_ID
     , lastplayM.PLAY_TIME AS maleTime
     , lastplayF.PLAY_TIME AS femaleTime
     , kittenM.VALUE AS male
     , kittenF.VALUE AS female
FROM CAT AS cat
  JOIN 
    ( SELECT CAT_ID
           , KITTEN_GENDER
           , KITTEN_ID
           , MAX(PLAY_TIME) OVER(PARTITION BY CAT_ID, KITTEN_GENDER) AS PLAY_TIME
      FROM CAT_KITTEN_PLAY
      WHERE PLAY_TIME = MAX(PLAY_TIME) OVER(PARTITION BY CAT_ID, KITTEN_GENDER)
    ) AS lastplayM
    ON lastplayM.CAT_ID = cat.CAT_ID
    AND lastplayM.KITTEN_GENDER = 'M'
    AND lastplayM.PLAY_TIME BETWEEN '01-JAN-2011 12:00:00 AM'
                               AND '31-JAN-2011 11:59:59 PM'
  JOIN KITTEN_INFO AS kittenM
    ON kittenM.KITTEN_ID = lastplayM.KITTEN_ID

  LEFT JOIN 
    ( SELECT CAT_ID
           , KITTEN_GENDER
           , KITTEN_ID
           , MAX(PLAY_TIME) OVER(PARTITION BY CAT_ID, KITTEN_GENDER) AS PLAY_TIME
      FROM CAT_KITTEN_PLAY
      WHERE PLAY_TIME = MAX(PLAY_TIME) OVER(PARTITION BY CAT_ID, KITTEN_GENDER)
    ) AS lastplayF
    ON lastplayF.CAT_ID = cat.CAT_ID
    AND lastplayF.KITTEN_GENDER = 'F'
  JOIN KITTEN_INFO AS kittenF
    ON kittenF.KITTEN_ID = lastplayF.KITTEN_ID

只是最后一场比赛的时间,而不是小猫的名字:

SELECT cat.CAT_ID
     , MAX(play.PLAY_TIME) AS maleTime
     , ( SELECT MAX(playf.PLAY_TIME)
         FROM CAT_KITTEN_PLAY AS playf
         WHERE playf.CAT_ID = cat.CAT_ID
           AND playf.KITTEN_GENDER = 'F'
       ) AS femaleTime
FROM CAT AS cat
  JOIN CAT_KITTEN_PLAY AS play
    ON play.CAT_ID = cat.CAT_ID
WHERE play.KITTEN_GENDER = 'M'
GROUP BY cat.CAT_ID 
HAVING MAX(play.PLAY_TIME) BETWEEN '01-JAN-2011 12:00:00 AM'
                               AND '31-JAN-2011 11:59:59 PM'
我完全不确定这是否有效:

SELECT cat.CAT_ID
     , lastplayM.PLAY_TIME AS maleTime
     , lastplayF.PLAY_TIME AS femaleTime
     , kittenM.VALUE AS male
     , kittenF.VALUE AS female
FROM CAT AS cat
  JOIN 
    ( SELECT CAT_ID
           , KITTEN_GENDER
           , KITTEN_ID
           , MAX(PLAY_TIME) OVER(PARTITION BY CAT_ID, KITTEN_GENDER) AS PLAY_TIME
      FROM CAT_KITTEN_PLAY
      WHERE PLAY_TIME = MAX(PLAY_TIME) OVER(PARTITION BY CAT_ID, KITTEN_GENDER)
    ) AS lastplayM
    ON lastplayM.CAT_ID = cat.CAT_ID
    AND lastplayM.KITTEN_GENDER = 'M'
    AND lastplayM.PLAY_TIME BETWEEN '01-JAN-2011 12:00:00 AM'
                               AND '31-JAN-2011 11:59:59 PM'
  JOIN KITTEN_INFO AS kittenM
    ON kittenM.KITTEN_ID = lastplayM.KITTEN_ID

  LEFT JOIN 
    ( SELECT CAT_ID
           , KITTEN_GENDER
           , KITTEN_ID
           , MAX(PLAY_TIME) OVER(PARTITION BY CAT_ID, KITTEN_GENDER) AS PLAY_TIME
      FROM CAT_KITTEN_PLAY
      WHERE PLAY_TIME = MAX(PLAY_TIME) OVER(PARTITION BY CAT_ID, KITTEN_GENDER)
    ) AS lastplayF
    ON lastplayF.CAT_ID = cat.CAT_ID
    AND lastplayF.KITTEN_GENDER = 'F'
  JOIN KITTEN_INFO AS kittenF
    ON kittenF.KITTEN_ID = lastplayF.KITTEN_ID

分析函数可能是解决您的问题的最佳答案:

SELECT DISTINCT
       cat.*, 
       first_value(lastMale.PLAY_TIME) 
          over (partition by cat.id 
                order by lastMale.PLAY_TIME desc nulls last) maleTime,
       first_value(lastFemale.PLAY_TIME) 
          over (partition by cat.id 
                order by lastFemale.PLAY_TIME desc nulls last) femaleTime,
       first_value(maleName.VALUE)  
          over (partition by cat.id 
                order by lastMale.PLAY_TIME desc nulls last) male,
       first_value(femaleName.VALUE)  
          over (partition by cat.id 
                order by lastFemale.PLAY_TIME desc nulls last) female
...

分析函数可能是解决您的问题的最佳答案:

SELECT DISTINCT
       cat.*, 
       first_value(lastMale.PLAY_TIME) 
          over (partition by cat.id 
                order by lastMale.PLAY_TIME desc nulls last) maleTime,
       first_value(lastFemale.PLAY_TIME) 
          over (partition by cat.id 
                order by lastFemale.PLAY_TIME desc nulls last) femaleTime,
       first_value(maleName.VALUE)  
          over (partition by cat.id 
                order by lastMale.PLAY_TIME desc nulls last) male,
       first_value(femaleName.VALUE)  
          over (partition by cat.id 
                order by lastFemale.PLAY_TIME desc nulls last) female
...

您可以使用WITH子句来简化这一过程

WITH MAX_MALE_KITTEN AS
(

     SELECT
        CAT_ID,
        MAX(PLAY_TIME) PLAY_TIME
     FROM
        CAT_KITTEN_PLAY
     WHERE
        KITTEN_GENDER = 'M'
     GROUP BY
        CAT_ID
),
MAX_FEMALE_KITTEN AS
(

     SELECT
        CAT_ID,
        MAX(PLAY_TIME) PLAY_TIME
     FROM
        CAT_KITTEN_PLAY
     WHRE
        KITTEN_GENDER = 'F'
     GROUP BY
        CAT_ID
)

SELECT
    C.CAT_ID,
    F_K_I.NAME LastFemaleName,
    F_PLAY_INFO.PLAY_TIME LastFemalePlayTime,
    M_K_I.NAME LastMaleName,
    M_PLAY_INFO.PLAY_TIME LastMalePlayTime

FROM
    CAT C
    LEFT JOIN CAT_KITTEN_PLAY F_PLAY_INFO
    ON C.CAT_ID = F_PLAY_INFO.CAT_ID
    AND F_PLAY_INFO.KITTEN_GENER= 'F'
    LEFT JOIN MAX_FEMALE_KITTEN M_F_K
    ON F_PLAY_INFO.CAT_ID = M_F_K.CAT_ID
    AND F_PLAY_INFO.PLAY_TIME = M_F_K.PLAY_TIME
    LEFT JOIN KITTEN_INFO F_K_I
    ON F_PLAY_INFO.KITTEN_ID = F_K_I.KITTEN_ID

    INNER JOIN CAT_KITTEN_PLAY M_PLAY_INFO
    ON C.CAT_ID = M_PLAY_INFO.CAT_ID
    AND M_PLAY_INFO.KITTEN_GENER= 'M'
    LEFT JOIN MAX_MALE_KITTEN M_F_K
    ON M_PLAY_INFO.CAT_ID = M_F_K.CAT_ID
    AND M_PLAY_INFO.PLAY_TIME = M_F_K.PLAY_TIME
    LEFT JOIN KITTEN_INFO M_K_I
    ON M_PLAY_INFO.KITTEN_ID = M_K_I.KITTEN_ID
WHERE 
       MAX_MALE_KITTEN.PLAY_TIME    BETWEEN '01-JAN-2011 12:00:00 AM'
                           AND '31-JAN-2011 11:59:59 PM

您可以使用WITH子句来简化这一过程

WITH MAX_MALE_KITTEN AS
(

     SELECT
        CAT_ID,
        MAX(PLAY_TIME) PLAY_TIME
     FROM
        CAT_KITTEN_PLAY
     WHERE
        KITTEN_GENDER = 'M'
     GROUP BY
        CAT_ID
),
MAX_FEMALE_KITTEN AS
(

     SELECT
        CAT_ID,
        MAX(PLAY_TIME) PLAY_TIME
     FROM
        CAT_KITTEN_PLAY
     WHRE
        KITTEN_GENDER = 'F'
     GROUP BY
        CAT_ID
)

SELECT
    C.CAT_ID,
    F_K_I.NAME LastFemaleName,
    F_PLAY_INFO.PLAY_TIME LastFemalePlayTime,
    M_K_I.NAME LastMaleName,
    M_PLAY_INFO.PLAY_TIME LastMalePlayTime

FROM
    CAT C
    LEFT JOIN CAT_KITTEN_PLAY F_PLAY_INFO
    ON C.CAT_ID = F_PLAY_INFO.CAT_ID
    AND F_PLAY_INFO.KITTEN_GENER= 'F'
    LEFT JOIN MAX_FEMALE_KITTEN M_F_K
    ON F_PLAY_INFO.CAT_ID = M_F_K.CAT_ID
    AND F_PLAY_INFO.PLAY_TIME = M_F_K.PLAY_TIME
    LEFT JOIN KITTEN_INFO F_K_I
    ON F_PLAY_INFO.KITTEN_ID = F_K_I.KITTEN_ID

    INNER JOIN CAT_KITTEN_PLAY M_PLAY_INFO
    ON C.CAT_ID = M_PLAY_INFO.CAT_ID
    AND M_PLAY_INFO.KITTEN_GENER= 'M'
    LEFT JOIN MAX_MALE_KITTEN M_F_K
    ON M_PLAY_INFO.CAT_ID = M_F_K.CAT_ID
    AND M_PLAY_INFO.PLAY_TIME = M_F_K.PLAY_TIME
    LEFT JOIN KITTEN_INFO M_K_I
    ON M_PLAY_INFO.KITTEN_ID = M_K_I.KITTEN_ID
WHERE 
       MAX_MALE_KITTEN.PLAY_TIME    BETWEEN '01-JAN-2011 12:00:00 AM'
                           AND '31-JAN-2011 11:59:59 PM


注意:添加和lastFemale.PLAY\u TIME=选择MAXPLAY\u TIME,其中。。。etc到最后都不起作用,因为这将删除所有没有与母猫玩耍的猫。为什么猫的性别存储在猫的玩耍中?它本质上不是猫咪信息的一部分吗?记住,类比。在我的模型中更有意义。注意:添加和lastFemale.PLAY\u TIME=选择MAXPLAY\u TIME,其中。。。etc到最后都不起作用,因为这将删除所有没有与母猫玩耍的猫。为什么猫的性别存储在猫的玩耍中?它本质上不是猫咪信息的一部分吗?记住,类比。在我的模型中更有意义。如果我这样做,并且任何播放时间值为空,则列中的所有值都返回为空。可能是因为它总是抓取第一个,而不管猫的ID是什么?是的,看起来所有的femaleTime值都是第一个值为空或否的值。请参见以下内容。这些列始终包含相同的值:您看到空列的原因是我在上次查看编辑时指定了desc而不使用null。通过添加partition by可以获得指定条件下的值。如果没有测试,很难提供一个经过全面测试的解决方案。太棒了,看起来它正在工作。非常感谢。希望我能将此扩展到整个查询。它包含大约10亿个连接。该死的DB设计师。哈哈,再次谢谢你。你让我的生活轻松多了=如果我这样做,并且任何PLAY_TIME值为空,则列中的所有值都返回为空。可能是因为它总是抓取第一个,而不管猫的ID是什么?是的,看起来所有的femaleTime值都是第一个值为空或否的值。请参见以下内容。这些列始终包含相同的值:您看到空列的原因是我在上次查看编辑时指定了desc而不使用null。通过添加partition by可以获得指定条件下的值。如果没有测试,很难提供一个经过全面测试的解决方案。太棒了,看起来它正在工作。非常感谢。希望我能将此扩展到整个查询。它包含大约10亿个连接。该死的DB设计师。哈哈,再次谢谢你。你让我的生活轻松多了=那你怎么加名字呢?似乎有些参考资料丢失了。谢谢你的建议。我选择了艾伦的第一个价值解决方案。在我看来更清楚一点。但是谢谢你的辛勤工作=那么你将如何添加这些名称?似乎有些参考资料丢失了。谢谢你的建议。我选择了艾伦的第一个价值解决方案。在我看来更清楚一点。但是谢谢你的辛勤工作=