如何优化 SQL 查询以检查表中列值的一致性

Posted

技术标签:

【中文标题】如何优化 SQL 查询以检查表中列值的一致性【英文标题】:How to optimise a SQL query to check for consistency of column values across tables 【发布时间】:2015-12-24 11:42:35 【问题描述】:

我想跨多个表检查每个表中是否存在相同的键/相同数量的键。

目前我已经创建了一个解决方案,它检查每个表的键数,当所有表合并在一起时检查键数,然后进行比较。

这个解决方案有效,但我想知道是否有更优化的解决方案......

目前的示例解决方案:

SELECT COUNT(DISTINCT variable) AS num_ids FROM table_a;

SELECT COUNT(DISTINCT variable) AS num_ids FROM table_b;

SELECT COUNT(DISTINCT variable) AS num_ids FROM table_c;

SELECT COUNT(DISTINCT a.variable) AS num_ids
FROM (SELECT DISTINCT VARIABLE FROM table_a) a
  INNER JOIN (SELECT DISTINCT VARIABLE FROM table_b) b ON a.variable = b.variable
  INNER JOIN (SELECT DISTINCT VARIABLE FROM table_c) c ON a.variable = c.variable;

更新:

我在一个查询中将这些放在一起面临的困难是任何表在我要检查的 VARIABLE 上可能不是唯一的,因此我必须在合并之前使用 distinct 以避免扩展加入

【问题讨论】:

如果表A1, 2, 2, 3和表B1, 1, 2, 3,他们认为是相同还是不同? 在你提到的情况下,我希望它们被视为相同 【参考方案1】:

由于我们只是计算,我认为没有必要加入variable 列上的表格。 UNION 应该足够了。 我们仍然必须使用DISTINCT 来忽略/抑制重复,这通常意味着额外的排序。 variable 上的索引应该有助于获取单独表的计数,但对获取组合表的计数没有帮助。

以下是比较两个表的示例:

WITH
CTE_A
AS
(
    SELECT COUNT(DISTINCT variable) AS CountA
    FROM TableA
)
,CTE_B
AS
(
    SELECT COUNT(DISTINCT variable) AS CountB
    FROM TableB
)
,CTE_AB
AS
(
    SELECT COUNT(DISTINCT variable) AS CountAB
    FROM
    (
        SELECT variable
        FROM TableA

        UNION ALL 
        -- sic! use ALL here to avoid sort when merging two tables
        -- there should be only one distinct sort for the outer `COUNT`

        SELECT variable
        FROM TableB
    ) AS AB
)
SELECT
    CASE WHEN CountA = CountAB AND CountB = CountAB 
    THEN 'same' ELSE 'different' END AS ResultAB
FROM
    CTE_A
    CROSS JOIN CTE_B
    CROSS JOIN CTE_AB
;

三个表:

WITH
CTE_A
AS
(
    SELECT COUNT(DISTINCT variable) AS CountA
    FROM TableA
)
,CTE_B
AS
(
    SELECT COUNT(DISTINCT variable) AS CountB
    FROM TableB
)
,CTE_C
AS
(
    SELECT COUNT(DISTINCT variable) AS CountC
    FROM TableC
)
,CTE_ABC
AS
(
    SELECT COUNT(DISTINCT variable) AS CountABC
    FROM
    (
        SELECT variable
        FROM TableA

        UNION ALL 
        -- sic! use ALL here to avoid sort when merging two tables
        -- there should be only one distinct sort for the outer `COUNT`

        SELECT variable
        FROM TableB

        UNION ALL 
        -- sic! use ALL here to avoid sort when merging two tables
        -- there should be only one distinct sort for the outer `COUNT`

        SELECT variable
        FROM TableC
    ) AS AB
)
SELECT
    CASE WHEN CountA = CountABC AND CountB = CountABC AND CountC = CountABC 
    THEN 'same' ELSE 'different' END AS ResultABC
FROM
    CTE_A
    CROSS JOIN CTE_B
    CROSS JOIN CTE_C
    CROSS JOIN CTE_ABC
;

我特意选择了CTE,因为据我所知,Postgres 实现了CTE,在我们的例子中,每个CTE 将只有一行。


使用array_agg with order by 是更好的变体,如果它在 redshift 上可用的话。您仍需要使用DISTINCT,但不必将所有表合并在一起。

WITH
CTE_A
AS
(
    SELECT array_agg(DISTINCT variable ORDER BY variable) AS A
    FROM TableA
)
,CTE_B
AS
(
    SELECT array_agg(DISTINCT variable ORDER BY variable) AS B
    FROM TableB
)
,CTE_C
AS
(
    SELECT array_agg(DISTINCT variable ORDER BY variable) AS C
    FROM TableC
)
SELECT
    CASE WHEN A = B AND B = C
    THEN 'same' ELSE 'different' END AS ResultABC
FROM
    CTE_A
    CROSS JOIN CTE_B
    CROSS JOIN CTE_C
;

【讨论】:

感谢,array_agg 在 postgre 版本的 redshift 中不可用,但即使您提供的第二个解决方案仍然比我的方法更有效。【参考方案2】:

好吧,这可能是我可以为你构建的最糟糕的 SQL 了 :) 我将永远否认我写了这个并且我的 *** 帐户被黑了;)

SELECT
  'All OK'
WHERE
  ( SELECT COUNT(DISTINCT id) FROM table_a ) = ( SELECT COUNT(DISTINCT id) FROM table_b )
  AND ( SELECT COUNT(DISTINCT id) FROM table_b ) = ( SELECT COUNT(DISTINCT id) FROM table_c )

顺便说一句,这不会优化查询 - 它仍在执行三个查询(但我猜它比 4 个更好?)。

更新:根据您的以下用例:新的 sql fiddle http://sqlfiddle.com/#!15/a0403/1

SELECT DISTINCT
  tbl_a.a_count,
  tbl_b.b_count,
  tbl_c.c_count
FROM
  ( SELECT COUNT(id) a_count, array_agg(id order by id) ids FROM table_a) tbl_a,
  ( SELECT COUNT(id) b_count, array_agg(id order by id) ids FROM table_b) tbl_b,
  ( SELECT COUNT(id) c_count, array_agg(id order by id) ids FROM table_c) tbl_c
WHERE
  tbl_a.ids = tbl_b.ids
  AND tbl_b.ids = tbl_c.ids

只有当所有表的行数相同时,上述查询才会返回,确保 IDS 也相同。

【讨论】:

感谢您的回复...别担心,我不会向任何人提及 :) 您建议的解决方案的唯一问题是,虽然不太可能,但如果有相同的号码,它就不会捕获, 但跨表的 id 不同(例如:table_a ids 1,2,3 和 table_b ids 1,2,4 现在才有机会回头看,感谢您的更新,我相信虽然这仍然不会涵盖 id 数量匹配的情况,但 id 本身不同(即 1 ,2,3 => 3 个数字,1,2,4 => 3 个数字,但两组不同) - 如果我遗漏了什么,请纠正我?

以上是关于如何优化 SQL 查询以检查表中列值的一致性的主要内容,如果未能解决你的问题,请参考以下文章

表中列的唯一值组合

基于 SQL Server 2008 中列值的内部联接

SQL 查询以查找具有相同列值的多行

需要帮助修复 Oracle SQL 查询以返回具有最大列值的行

与 SQL 排序依据和空值的数据库一致性

更新查询以根据不同表中的值更改一个表中列的现有值