我有一个查询,检查某人是否已填写另一个表中的内容。 它首先检查它是否在表中,然后在UNION之后检查它是否在表中..
我和那些比我更了解SQL的人一起构建了这个查询。 现在我想知道这是否可以缩短?
我在考虑可能是一个案例,然后是0,而不是用2个查询来检查并进行结合
SELECT
l.id,
l.naam,
r.id as revisie,
r.beschrijving as revisiebeschrijving,
"DONE"
FROM lijsten l
JOIN revisies r ON r.lijst_id = l.id
JOIN werknemerlijsten wl ON wl.lijst_id = l.id
WHERE
wl.werknemer_id = :id AND r.actief = 1
AND r.id IN
(
SELECT
r2.id
FROM revisies r2
JOIN antwoorden a ON a.revisie_id = r2.id
WHERE a.werknemer_id = wl.werknemer_id
)
UNION
SELECT
l.id,
l.naam,
r.id as revisie,
r.beschrijving as revisiebeschrijving,
"NOT DONE"
FROM lijsten l
JOIN revisies r ON r.lijst_id = l.id
JOIN werknemerlijsten wl ON wl.lijst_id = l.id
WHERE
wl.werknemer_id = :id AND r.actief = 1
AND r.id NOT IN
(
SELECT
r2.id
FROM revisies r2
JOIN antwoorden a ON a.revisie_id = r2.id
WHERE a.werknemer_id = wl.werknemer_id
)
SELECT l.id
, l.naam
, r.id as revisie
, r.beschrijving as revisiebeschrijving
, CASE WHEN a.werknemer_id IS NULL
THEN 0
ELSE 1 END AS ingevuld
FROM werknemerlijsten AS wl
INNER
JOIN lijsten AS l
ON l.id = wl.lijst_id
INNER
JOIN revisies AS r
ON r.lijst_id = l.id
AND r.actief = 1
LEFT OUTER
JOIN antwoorden AS a
ON a.revisie_id = r.id
AND a.werknemer_id = wl.werknemer_id
WHERE wl.werknemer_id = :id
ORDER BY ingevuld
答案 0 :(得分:1)
你可以使用LEFT JOIN而不是IN / NOT IN,这应该比相关的子查询更好。然后你可以使用CASE语句检查LEFT JOIN中是否有匹配,以确定它应该是DONE还是DONE。
SELECT l.id,
l.naam,
r.id as revisie,
r.beschrijving as revisiebeschrijving,
CASE WHEN a.ID IS NOT NULL THEN "DONE" ELSE "NOT DONE" END
FROM lijsten l
JOIN revisies r
ON r.lijst_id = l.id
JOIN werknemerlijsten wl
ON wl.lijst_id = l.id
LEFT JOIN
( SELECT r2.id, a.werknemer_id
FROM revisies r2
JOIN antwoorden a
ON a.revisie_id = r2.id
) a
ON a.ID = r.ID
AND a.werknemer_id = wl.werknemer_id
WHERE wl.werknemer_id = :id
AND r.actief = 1;
我不是百分百肯定,但我认为这可以进一步简化:
SELECT l.id,
l.naam,
r.id as revisie,
r.beschrijving as revisiebeschrijving,
CASE WHEN a.revisie_id IS NOT NULL THEN "DONE" ELSE "NOT DONE" END
FROM lijsten l
JOIN revisies r
ON r.lijst_id = l.id
JOIN werknemerlijsten wl
ON wl.lijst_id = l.id
LEFT JOIN antwoorden a
ON a.revisie_id = r.iD
AND a.werknemer_id = wl.werknemer_id
WHERE wl.werknemer_id = :id
AND r.actief = 1
这可以避免子查询,并且应该给出相同的结果,避免子查询会提高性能。
修改强>
如果antwoorden
中有重复项,则您需要添加DISTINCT
才能将其删除:
SELECT l.id,
l.naam,
r.id as revisie,
r.beschrijving as revisiebeschrijving,
CASE WHEN a.revisie_id IS NOT NULL THEN "DONE" ELSE "NOT DONE" END
FROM lijsten l
JOIN revisies r
ON r.lijst_id = l.id
JOIN werknemerlijsten wl
ON wl.lijst_id = l.id
LEFT JOIN
( SELECT DISTINCT a.revisie_id, a.werknemer_id
FROM antwoorden a
) a
ON a.revisie_id= r.ID
AND a.werknemer_id = wl.werknemer_id
WHERE wl.werknemer_id = :id
AND r.actief = 1;
编辑2
事实上,我认为可以在没有子查询的情况下解决重复问题:
SELECT l.id,
l.naam,
r.id as revisie,
r.beschrijving as revisiebeschrijving,
CASE WHEN MAX(a.revisie_id) IS NOT NULL THEN "DONE" ELSE "NOT DONE" END AS ingevuld
FROM lijsten l
JOIN revisies r
ON r.lijst_id = l.id
JOIN werknemerlijsten wl
ON wl.lijst_id = l.id
LEFT JOIN antwoorden a
ON a.revisie_id = r.ID
AND a.werknemer_id = wl.werknemer_id
WHERE wl.werknemer_id = :id
AND r.actief = 1
GROUP BY l.id, l.naam, r.id, r.beschrijving
ORDER BY ingevuld;
答案 1 :(得分:1)
您的猜测是正确的,可以使用CASE WHEN...END
缩短,这样您就可以缩短WHERE
并摆脱UNION SELECT
,这也可以提供一些速度优势。
一次快速重写可能导致以下结果:
SELECT
l.id,
l.naam,
r.id as revisie,
r.beschrijving as revisiebeschrijving,
CASE WHEN
(
SELECT
r2.id
FROM revisies r2
JOIN antwoorden a ON a.revisie_id = r2.id
WHERE
a.werknemer_id = wl.werknemer_id
AND r2.id = r.id
) IS NOT NULL THEN
"DONE"
ELSE
"NOT DONE"
END
FROM lijsten l
JOIN revisies r ON r.lijst_id = l.id
JOIN werknemerlijsten wl ON wl.lijst_id = l.id
WHERE
wl.werknemer_id = :id AND r.actief = 1
正如评论中所提到的,LEFT JOIN
在这里也会很好,因此CASE
中的子选择将向下移动到LEFT JOIN
......