避免在select查询中重复条件

时间:2017-12-13 14:14:30

标签: sql postgresql

我在postgresql上执行以下查询

SELECT COUNT(DISTINCT id_client) FROM contract c
INNER JOIN bundle b ON c.bundle_id = b.id
INNER JOIN payment_method pm ON pm.id = c.payment_method_id
WHERE country_id=1 AND b.platform_id=1  AND pm.name <> 'RIB'
  AND CONDITION_1
  AND id_client NOT IN (
    SELECT id_client FROM contract c1
    INNER JOIN bundle b1 ON (c1.bundle_id = b1.id)
    INNER JOIN payment_method pm1 ON pm1.id = c1.payment_method_id
    WHERE c1.country_id=1 AND b1.platform_id=1 AND pm1.name <> 'RIB'
      AND CONDITION_2);

我不喜欢它,因为除了CONDITION_1和CONDITION_2之外,它重复了两次相同的查询(我还有另一个重复3次的例子)。

它也很慢。

我尝试将其重写如下:

WITH
filter_cpm AS (
    SELECT * FROM contract c
    INNER JOIN bundle b ON b.id = c.bundle_id
    INNER JOIN payment_method pm ON pm.id = c.payment_method_id
      WHERE c.country_id = 1 AND b.platform_id = 1 AND pm.name <> 'RIB'
)
SELECT COUNT(DISTINCT id_client) FROM filter_cpm
    WHERE CONDITION_1
      AND id_client NOT IN (
        SELECT id_client FROM filter_cpm
        WHERE CONDITION_2);

现在它干了但速度慢了两倍。

如何重新编写查询以获得相同(或更好)的性能?

编辑:我不能用AND加入两个条件。例如,如果CONDITION_1和CONDITION_2是VIP,那么我想选择从NOT VIP重新认证到VIP的客户。

1 个答案:

答案 0 :(得分:1)

您可以使用外部联接从公共表表达式中选择两次:

WITH filter_cpm AS (SELECT *
                      FROM CONTRACT c
                      INNER JOIN BUNDLE b
                        ON b.ID = c.BUNDLE_ID
                      INNER JOIN PAYMENT_METHOD pm
                        ON pm.ID = c.PAYMENT_METHOD_ID
                      WHERE c.COUNTRY_ID = 1 AND
                            b.PLATFORM_ID = 1 AND
                            pm.NAME <> 'RIB')
SELECT COUNT(DISTINCT fc1.ID_CLIENT)
  FROM filter_cpm fc1
  LEFT OUTER JOIN filter_cpm fc2
    ON fc2.ID_CLIENT = fc1.ID_CLIENT AND
       CONDITION_2
  WHERE fc1.CONDITION_1 AND
        fc2.ID_CLIENT IS NULL

祝你好运。