SQL查询-连接上的子查询 简介
我需要为Oracle数据库编写一个复杂的查询。为了避免使用公司数据,我试着做了一个类比,所以如果有什么奇怪的事情,请告诉我 桌子 猫 猫ID PK 小猫 小猫身份证 猫咪玩耍 播放ID PK CAT_ID FK至CAT表 小猫标识FK到小猫表 小猫性别串-M或F 播放时间日期 小猫信息 小猫标识FK到小猫表 名称字符串,例如名称 值字符串,例如Duchess 描述 所以基本上,CAT和KITTEN表只保存id和其他一些随机信息。KITTEN_信息包含小猫的名字和其他信息。猫和小猫玩耍记录了猫和小猫玩耍的所有时间 我需要的是编写一个查询,返回最近与一只雄性小猫玩耍的时间在某个日期范围内的所有猫。我们称之为2011年1月1日至2011年1月31日。我还需要包括玩的日期和猫最近玩过的公猫和母猫的名字 目前为止 以下是我目前的情况:SQL查询-连接上的子查询 简介,sql,oracle,Sql,Oracle,我需要为Oracle数据库编写一个复杂的查询。为了避免使用公司数据,我试着做了一个类比,所以如果有什么奇怪的事情,请告诉我 桌子 猫 猫ID PK 小猫 小猫身份证 猫咪玩耍 播放ID PK CAT_ID FK至CAT表 小猫标识FK到小猫表 小猫性别串-M或F 播放时间日期 小猫信息 小猫标识FK到小猫表 名称字符串,例如名称 值字符串,例如Duchess 描述 所以基本上,CAT和KITTEN表只保存id和其他一些随机信息。KITTEN_信息包含小猫的名字和其他信息。猫和小猫玩耍记录了猫和小
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设计师。哈哈,再次谢谢你。你让我的生活轻松多了=那你怎么加名字呢?似乎有些参考资料丢失了。谢谢你的建议。我选择了艾伦的第一个价值解决方案。在我看来更清楚一点。但是谢谢你的辛勤工作=那么你将如何添加这些名称?似乎有些参考资料丢失了。谢谢你的建议。我选择了艾伦的第一个价值解决方案。在我看来更清楚一点。但是谢谢你的辛勤工作=