缩短此小查询

时间:2013-09-25 08:56:21

标签: mysql sql union

我有一个查询,检查某人是否已填写另一个表中的内容。 它首先检查它是否在表中,然后在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
        )

最终解决方案

这是最终解决方案,而ORDER BY在此版本中运行,没有subquerys

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

2 个答案:

答案 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 ......