我需要编写一个复杂的查询(对于Oracle DB)。我试图通过类比来避免使用公司数据,所以如果有些事情看起来很奇怪,请告诉我。
CAT
小猫
CAT_KITTEN_PLAY
KITTEN_INFO
基本上,CAT和KITTEN表只保存ID和其他一些随机信息。 KITTEN_INFO保存小猫的名字(以及其他内容)。 CAT_KITTEN_PLAY会记录猫与小猫玩耍的所有时间。
我需要的是编写一个查询,返回所有与男性KITTEN最近播放时间在某个日期范围内的CAT。我们称之为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'
这并不能说明一只猫可能不止一次与一只雌性/雌性小猫玩过。所以,我想在第一个连接上添加“AND lastMale.PLAY_TIME =(SELECT MAX(PLAY_TIME)FROM CAT_KITTEN_PLAY WHERE CAT_ID = cat.ID AND KITTEN_GENDER ='M')”到第二个连接。但是连接上不允许子查询。
有什么想法?请注意,猫可能从未玩过一只雌性小猫。但如果它们符合标准(因此左边连接),猫仍然应该被包括在内。
答案 0 :(得分:3)
分析函数可能是解决问题的最佳方法:
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
...
答案 1 :(得分:1)
上次比赛的时间,而不是小猫的名字:
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
答案 2 :(得分:1)
您可以使用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