SQL查询太大了 - 我可以合并吗?

时间:2013-08-08 20:41:37

标签: sql postgresql optimization union

我有下面的查询似乎有效,但我觉得我应该能够以更简单的方式做到这一点。基本上我有一个订单表和一个production_work表。我想查找所有未完成的订单,这意味着在production_work表中没有订单条目,或者有条目和工作总和等于订单要求的订单。

SELECT q.* FROM (
    SELECT o.ident, c."name" AS cname, s."name" as sname, o.number, o.created, o.due, o.name, o.ud, o.dp, o.swrv, o.sh, o.jmsw, o.sw, o.prrv, o.mhsw, o.bmsw, o.mp, o.pr, o.st
    FROM orders o
    INNER JOIN stations s on s.ident = o.station_id
    INNER JOIN clients c ON s.client_id = c.ident
    INNER JOIN (
        SELECT p.order_id, SUM(p.ud) AS ud, SUM(p.dp) AS dp, SUM(p.swrv) AS swrv, SUM(p.sh) AS sh, SUM(p.jmsw) AS jmsw, SUM(p.sw) AS sw, SUM(p.prrv) AS prrv,
            SUM(p.mhsw) AS mhsw, SUM(p.bmsw) AS bmsw, SUM(p.mp) AS mp, SUM(p.pr) AS pr, SUM(p.st) AS st
        FROM production_work p
        GROUP BY p.order_id
    ) pw ON o.ident = pw.order_id
    WHERE o.ud <> pw.ud OR o.dp <> pw.dp OR o.swrv <> pw.swrv OR o.sh <> pw.sh OR o.jmsw <> pw.jmsw OR o.sw <> pw.sw OR o.prrv <> pw.prrv OR
            o.mhsw <> pw.mhsw OR o.bmsw <> pw.bmsw OR o.mp <> pw.mp OR o.pr <> pw.pr OR o.st <> pw.st

    UNION

    SELECT o.ident, c."name" AS cname, s."name" as sname, o.number, o.created, o.due, o.name, o.ud, o.dp, o.swrv, o.sh, o.jmsw, o.sw, o.prrv, o.mhsw, o.bmsw, o.mp, o.pr, o.st
    FROM orders o
    INNER JOIN stations s on s.ident = o.station_id
    INNER JOIN clients c ON s.client_id = c.ident
    WHERE NOT EXISTS (
        SELECT 1 FROM production_work p WHERE p.ident = o.ident
    )
) q ORDER BY due DESC

3 个答案:

答案 0 :(得分:1)

以下是我最终的查询:

WITH work_totals AS (
    SELECT p.order_id, SUM(p.ud + p.dp + p.swrv + p.sh + p.jmsw + p.sw + p.prrv + p.mhsw + p.bmsw + p.mp + p.pr + p.st) AS total
    FROM production_work p
    GROUP BY p.order_id
), order_totals AS (
    SELECT ident, SUM(ud + dp + swrv + sh + jmsw + sw + prrv + mhsw + bmsw + mp + pr + st) AS total
    FROM orders
    GROUP BY ident
) 
SELECT o.ident, c."name" AS cname, s."name" as sname, o.number, o.created, o.due, o.name,      o.ud, o.dp, o.swrv, o.sh, o.jmsw, o.sw, o.prrv, o.mhsw, o.bmsw, o.mp, o.pr, o.st
FROM orders o
INNER JOIN stations s on s.ident = o.station_id
INNER JOIN clients c ON s.client_id = c.ident
INNER JOIN order_totals ot ON o.ident = ot.ident
LEFT OUTER JOIN work_totals w ON o.ident = w.order_id
WHERE w.order_id IS NULL OR ot.total <> w.total

答案 1 :(得分:0)

此表单的查询:显示另一个表中没有匹配项的行。

可以这样做:

select <columns>
from <table1>
left outer join <table2> on <join_condition>
where table2.column IS NULL

这将从table1中找到与table2中没有任何匹配连接条件的行。

对于你的求和查询,我会做这样的事情......

select table1.order_number, total = sum(table2.order_amount)
from table1
left outer join table2 on table1.order_number = table2.order_number
group by order_number
having total < (some_number) OR total is null

结合获得没有匹配的订单,并获得少于总订单数量的订单。

答案 2 :(得分:0)

您的UNION中的两个查询几乎相同,因此您可以将它们合并到单个查询中,如下所示。我刚刚将JOIN更改为pw子查询为OUTER LEFT JOIN - 它与你的union有相同的reslut因为我在WHERE语句中添加了一个额外的OR子句来返回这些在pw子查询中没有记录的命令

SELECT o.ident, c."name" AS cname, s."name" as sname, o.number, o.created, o.due, o.name, o.ud, o.dp, o.swrv, o.sh, o.jmsw, o.sw, o.prrv, o.mhsw, o.bmsw, o.mp, o.pr, o.st
FROM orders o
INNER JOIN stations s on s.ident = o.station_id
INNER JOIN clients c ON s.client_id = c.ident
LEFT OUTER JOIN (
    SELECT p.order_id, SUM(p.ud) AS ud, SUM(p.dp) AS dp, SUM(p.swrv) AS swrv, SUM(p.sh) AS sh, SUM(p.jmsw) AS jmsw, SUM(p.sw) AS sw, SUM(p.prrv) AS prrv,
        SUM(p.mhsw) AS mhsw, SUM(p.bmsw) AS bmsw, SUM(p.mp) AS mp, SUM(p.pr) AS pr, SUM(p.st) AS st
    FROM production_work p
    GROUP BY p.order_id
) pw ON o.ident = pw.order_id
WHERE (o.ud <> pw.ud OR o.dp <> pw.dp OR o.swrv <> pw.swrv OR o.sh <> pw.sh OR o.jmsw <> pw.jmsw OR o.sw <> pw.sw OR o.prrv <> pw.prrv OR
        o.mhsw <> pw.mhsw OR o.bmsw <> pw.bmsw OR o.mp <> pw.mp OR o.pr <> pw.pr OR o.st <> pw.st
       )
OR  pw.order_id IS NULL
ORDER BY due DESC