使用每列的一列比较两个表函数的结果

时间:2015-03-02 11:34:19

标签: sql postgresql postgresql-9.3 set-returning-functions

根据说明here,我创建了两个使用EXECUTE FORMAT的函数,并返回(int,smallint)的同一个表。

样本定义:

CREATE OR REPLACE FUNCTION function1(IN _tbl regclass, IN _tbl2 regclass, 
IN field1 integer) 
RETURNS TABLE(id integer, dist smallint)

CREATE OR REPLACE FUNCTION function2(IN _tbl regclass, IN _tbl2 regclass, 
IN field1 integer) 
RETURNS TABLE(id integer, dist smallint)

两个函数都返回完全相同的行数。样本结果(将始终按dist排序):

(49,0)
(206022,3)
(206041,3)
(92233,4)

有没有办法比较两个函数中相同行的第二个字段的值,以确保两个结果都相同:

例如:

SELECT
function1('tblp1','tblp2',49),function2('tblp1_v2','tblp2_v2',49)

返回类似的内容:

(49,0)      (49,0)
(206022,3)  (206022,3)
(206041,3)  (206041,3)
(92233,4)   (133,4)

虽然我不期待相同的结果(每个函数都是 topK 查询,并且我有任意关系/在第二个函数中进行一些优化以获得更快性能的关系)我可以确保这两个函数返回正确的结果,如果对于每一行,结果中的第二个数字是相同的。在上面的例子中,我可以确保得到正确的结果,因为:

1st row 0 = 0,
2nd row 3 = 3,
3rd row 3 = 3,
4th row 4 = 4

尽管第4行92233!=133

有没有办法只获得每个函数结果的第二个字段,批量比较它们,例如有类似的东西:

SELECT COUNT(*)
FROM 
(SELECT
function1('tblp1','tblp2',49).field2,
function2('tblp1_v2','tblp2_v2',49).field2 ) n2
WHERE  function1('tblp1','tblp2',49).field2 != function1('tblp1','tblp2',49).field2;

我正在使用PostgreSQL 9.3。

3 个答案:

答案 0 :(得分:1)

无法保证从函数返回行的顺序。如果您可以从函数返回row_number()(以下示例中的rn),那么:

select
    count(f1.dist is null or f2.dist is null or null) as diff_count
from
    function1('tblp1','tblp2',49) f1
    inner join
    function2('tblp1_v2','tblp2_v2',49) f2 using(rn)

答案 1 :(得分:1)

  

有没有办法只获得每个函数结果的第二个字段,批量比较它们?

以下所有答案均假设行以 匹配 顺序返回。

Postgres 9.3

具有从SRF函数中爆炸行的奇特功能,并行返回相同行数:

SELECT count(*) AS mismatches
FROM  (
   SELECT function1('tblp1','tblp2',49) AS f1
        , function2('tblp1_v2','tblp2_v2',49) AS f2
   ) sub
WHERE  (f1).dist <> (f2).dist;  -- note the parentheses!

行类型周围的括号是消除可能的表引用的必要条件所必需的。 Details in the manual here.

如果返回的行数不相同(这将完全打破它),则默认为行的笛卡尔乘积。

Postgres 9.4

WITH ORDINALITY即时生成行号

您可以使用WITH ORDINALITY动态生成行号,而无需依赖于SELECT列表中SRF函数的结果配对:

SELECT count(*) AS mismatches
FROM      function1('tblp1','tblp2',49)       WITH ORDINALITY AS f1(id,dist,rn)
FULL JOIN function2('tblp1_v2','tblp2_v2',49) WITH ORDINALITY AS f2(id,dist,rn) USING (rn)
WHERE  f1.dist IS DISTINCT FROM f2.dist;

这适用于每个函数的相同行数以及不同的数字(将被视为不匹配)。

相关:

ROWS FROM加入逐行设置

SELECT count(*) AS mismatches
FROM   ROWS FROM (function1('tblp1','tblp2',49)
                , function2('tblp1_v2','tblp2_v2',49)) t(id1, dist1, id2, dist2)
WHERE  t.dist1 IS DISTINCT FROM t.dist2;

相关答案:

除了:
EXECUTE FORMAT不是设置plpgsql功能。 RETURN QUERY是。 format()只是构建查询字符串的一个方便函数,可以在SQL或plpgsql中的任何地方使用。

答案 2 :(得分:0)

供将来参考:

检查行数差异:

SELECT 
ABS(count(f1a.*)-count(f2a.*))  
FROM
(SELECT f1.dist, row_number()  OVER(ORDER BY f1.dist) rn
FROM
function1('tblp1','tblp2',49) f1)
f1a FULL JOIN 

(SELECT f2.dist, row_number() OVER(ORDER BY f2.dist) rn
FROM
function2('tblp1_v2','tblp2_v2',49) f2) f2a
USING (rn);

检查相同有序行的dist差异:

SELECT 
COUNT(*)  

FROM

(SELECT f1.dist, row_number()  OVER(ORDER BY f1.dist) rn
FROM
function1('tblp1','tblp2',49) f1)
f1a 
(SELECT f2.dist, row_number() OVER(ORDER BY f2.dist) rn
FROM
function2('tblp1_v2','tblp2_v2',49) f2) f2a
WHERE f1a.rn=f2a.rn
AND f1a.distance <> f2a.distance;

一个简单的OVER()也可能有效,因为函数的结果已经被排序但是被添加以进行额外的检查。