根据SQL中的连接规则链查找第一条记录

根据SQL中的连接规则链查找第一条记录,sql,postgresql,Sql,Postgresql,我需要通过使用多字段关系找到最适合的记录。 我需要根据3个字段加入,如果失败,使用2个文件,如果失败,使用1个文件条件,等等。 这样的链条可以很长,字段可以变化,等等。 如何做到这一点 下面我提出一些想法,但不知何故我觉得这可以做得更好 第一种方式我不喜欢UNION,因为我猜引擎将执行所有这些命令,而不管LIMIT 1子句是否可以作为stop on First found: SELECT A1, A2, A3, B4 FROM A LEFT OUTER JOIN (SELECT B4 FROM

我需要通过使用多字段关系找到最适合的记录。 我需要根据3个字段加入,如果失败,使用2个文件,如果失败,使用1个文件条件,等等。 这样的链条可以很长,字段可以变化,等等。 如何做到这一点

下面我提出一些想法,但不知何故我觉得这可以做得更好

第一种方式我不喜欢UNION,因为我猜引擎将执行所有这些命令,而不管LIMIT 1子句是否可以作为stop on First found:

SELECT A1, A2, A3, B4 FROM A
LEFT OUTER JOIN (SELECT B4 FROM
      ((SELECT B4, 1 AS ORD FROM B 
            WHERE B.B1 = A.A1 AND B.B2 = A.B2 AND B.B3 = A.A3)
      UNION ALL
      (SELECT B4, 2 AS ORD FROM B 
            WHERE B.B1 = A.A1 AND B.B2 = A.B2)
      UNION ALL
      (SELECT B4, 3 AS ORD FROM B 
            WHERE B.B1 = A.A1)) ORDER BY ORD ASC LIMIT 1); 
第二种方法是,我不喜欢在WHEN和THEN部分重复选择,而且只有在返回单个字段时才好

SELECT A1, A2, A3,
    CASE 
        WHEN EXISTS 
            (SELECT B4 FROM B WHERE B.B1 = A.A1 AND B.B2 = A.B2 AND B.B3 = A.A3) 
            THEN 
            (SELECT B4 FROM B WHERE B.B1 = A.A1 AND B.B2 = A.B2 AND B.B3 = A.A3 LIMIT 1)
        WHEN EXISTS 
            (SELECT B4 FROM B WHERE B.B1 = A.A1 AND B.B2 = A.B2) 
            THEN 
            (SELECT B4 FROM B WHERE B.B1 = A.A1 AND B.B2 = A.B2 LIMIT 1)
        WHEN EXISTS 
            (SELECT B4 FROM B WHERE B.B1 = A.A1) 
            THEN (SELECT B4 FROM B WHERE B.B1 = A.A1 LIMIT 1)
        ELSE NULL
    END AS B4
FROM A;
我使用postgreSQL 9.6,但这些问题应被视为标准SQL问题

要测试的代码:

CREATE TABLE A (A1 INT, A2 INT, A3 INT);
CREATE TABLE B (B1 INT, B2 INT, B3 INT, B4 VARCHAR(2));

INSERT INTO A VALUES 
    (10, 20, 30),
    (11, 21, 31),
    (12, 22, 32),
    (13, 23, 33),
    (14, 24, 34);

INSERT INTO B VALUES 
    (10, 20,    30, 'A1'),
    (11, 21,    0,  'B'),
    (12, 0,     0,  'C'),
    (10, 23,    30, 'A2'),
    (14, 0,     34, 'D');

/*
EXPECTED RESULT
10, 20, 30, A1
11, 21, 31, B
12, 22, 32, C
*/
您可以使用左连接。这里有一个方法:

select a.A1, a.A2, a.A3, coalesce(b1.B4, b2.b4, b3.b4) as b4
from A left join
     b b1
     on b1.b1 = a.a1 and b1.b2 = a.b2 and b1.b3 = a.b3 left join
     b b2
     on b1.b1 = a.a1 and b1.b2 = a.b2 and b1.a1 is null left join
     b b3
     on b1.b1 = a.a1 and b2.b1 is null and b1.b1 is null;
上面的命令可能返回多行。如果只需要一行,则可以尝试:

select a.*,
       (select b.b4
        from b
        where b.b1 = a.a1
        order by (b.b2 = a.a2 and b.b3 = a.a3)::int desc,
                 (b.b2 = a.a2)::int desc
        limit 1
       ) as b4
from a;
这没有那么有效。而且,查询可以表述为横向联接——如果您想返回多个值,这一点特别有用

您可以使用左连接。这里有一个方法:

select a.A1, a.A2, a.A3, coalesce(b1.B4, b2.b4, b3.b4) as b4
from A left join
     b b1
     on b1.b1 = a.a1 and b1.b2 = a.b2 and b1.b3 = a.b3 left join
     b b2
     on b1.b1 = a.a1 and b1.b2 = a.b2 and b1.a1 is null left join
     b b3
     on b1.b1 = a.a1 and b2.b1 is null and b1.b1 is null;
上面的命令可能返回多行。如果只需要一行,则可以尝试:

select a.*,
       (select b.b4
        from b
        where b.b1 = a.a1
        order by (b.b2 = a.a2 and b.b3 = a.a3)::int desc,
                 (b.b2 = a.a2)::int desc
        limit 1
       ) as b4
from a;
这没有那么有效。而且,查询可以表述为横向联接——如果您想返回多个值,这一点特别有用

left join lateral可能对您有用,因为它允许将结果限制为每行一行:

left join lateral可能在这方面对您有用,因为它允许将结果限制为每行一行:

快速示例:

SELECT * FROM (
    SELECT
    CONCAT(B1,"-",B2,"-",B3) AS B_CONDITION1,
    CONCAT(B1,"-",B2) AS B_CONDITION2,
    B1 AS B_CONDITION3,
    b.*
    FROM b
) AS b_tmp
INNER JOIN 
(
    SELECT
    CONCAT(A1,"-",A2,"-",A3) AS A_CONDITION1,
    CONCAT(A1,"-",A2) AS A_CONDITION2,
    A1 AS A_CONDITION3
    FROM a
) AS a_tmp ON 
(a_tmp.A_CONDITION1 = b_tmp.B_CONDITION1 OR a_tmp.A_CONDITION2 = b_tmp.B_CONDITION2 OR a_tmp.A_CONDITION3 = b_tmp.B_CONDITION3)
你必须看到大数据的it行为。。对不起,我的英语,干得好

快速示例:

SELECT * FROM (
    SELECT
    CONCAT(B1,"-",B2,"-",B3) AS B_CONDITION1,
    CONCAT(B1,"-",B2) AS B_CONDITION2,
    B1 AS B_CONDITION3,
    b.*
    FROM b
) AS b_tmp
INNER JOIN 
(
    SELECT
    CONCAT(A1,"-",A2,"-",A3) AS A_CONDITION1,
    CONCAT(A1,"-",A2) AS A_CONDITION2,
    A1 AS A_CONDITION3
    FROM a
) AS a_tmp ON 
(a_tmp.A_CONDITION1 = b_tmp.B_CONDITION1 OR a_tmp.A_CONDITION2 = b_tmp.B_CONDITION2 OR a_tmp.A_CONDITION3 = b_tmp.B_CONDITION3)


你必须看到大数据的it行为。。对不起,我的英语,干得好

请提供一些样品和预期的价格result@maSTAShuFu:done结果的逻辑是什么?我不知道这是如何实现的,但您的字段B4只能有1个字符第一个记录:使用A1、A2、A3的关系,第二个记录:使用A1和A2,第三个仅使用A1。B中的第四条记录未选中我想要一条记录不是全部,第五条未选中-没有规则仅按A1和A3查找请提供一些示例和预期结果result@maSTAShuFu:done结果的逻辑是什么?我不知道这是如何实现的,但字段B4只能有1个字符第一条记录:使用A1、A2、A3的关系,第二条记录:使用A1和A2,第三条记录仅使用A1。B中的第四条记录未选中我想要一条记录不是全部,第五条未选中-没有规则仅按A1和A3查找答案。14 | 24 | 34 | D不在预期结果中,因为B.B2=0,并且没有规则只按A.A1=B.B1和A.A3=B.b3进行查找。横向是SQL标准还是仅为PostgreSQL?我不确定我是否完全理解您的语句中的横向,联接语句ljl*没有相互引用,那么,这与同一个示例有什么不同呢?但是没有使用lateral。lateral是SQL标准的最新修订,但尚未广泛实施。很抱歉,我粘贴了一个不正确的建议版本。横向连接是完全不同的,在这里我使用LEFT-JOIN-LATERAL-ON-TRUE,这允许比select子句中的类似查询更有效地使用相关子查询。14 | 24 | 34 | D出现在我的结果中,因为第三个子查询,当a1=b1时,它只需要在这一列上匹配14的a1和14的b1,在第B4行上匹配D,谢谢你的回答。14 | 24 | 34 | D不在预期结果中,因为B.B2=0,并且没有规则只按A.A1=B.B1和A.A3=B.b3进行查找。横向是SQL标准还是仅为PostgreSQL?我不确定我是否完全理解您的语句中的横向,联接语句ljl*没有相互引用,那么,这与同一个示例有什么不同呢?但是没有使用lateral。lateral是SQL标准的最新修订,但尚未广泛实施。很抱歉,我粘贴了一个不正确的建议版本。横向连接是完全不同的,在这里我使用LEFT-JOIN-LATERAL-ON-TRUE,这允许比select子句中的类似查询更有效地使用相关子查询。14 | 24 | 34 | D出现在我的结果中,因为第三个子查询,当a1=b1时,它只需要在这一列上匹配14的a1和14的b1,在第B4行上匹配“D”,谢谢Gordon,这是一个非常优雅和干净的解决方案。我需要将它的执行计划与某个大型数据集上已由_使用的_发布的横向版本进行比较,这将花费我一些时间,但会返回刚才注意到的结果,这并不局限于在B中找到的单个记录。相反,结果与在B中找到的多个记录相乘。但在合并中返回的值是正确的。顺序是B.b2=a.a2和B.b3=a.a3::int desc,B.b2=a.a2::int desc a表的列以a开头,而不是B.b2=a.b2等,但使用了真/假+1汉克斯Gordon,这
是一种非常优雅和干净的解决方案。我需要将它的执行计划与某个大型数据集上已由_使用的_发布的横向版本进行比较,这将花费我一些时间,但会返回刚才注意到的结果,这并不局限于在B中找到的单个记录。相反,结果与在B中找到的多个记录相乘。但在合并中返回的值是正确的。顺序是B.b2=a.a2和B.b3=a.a3::int desc,B.b2=a.a2::int desc a表的列以a开头,而不是B.b2=a.b2等,但使用了真/假+1
SELECT * FROM (
    SELECT
    CONCAT(B1,"-",B2,"-",B3) AS B_CONDITION1,
    CONCAT(B1,"-",B2) AS B_CONDITION2,
    B1 AS B_CONDITION3,
    b.*
    FROM b
) AS b_tmp
INNER JOIN 
(
    SELECT
    CONCAT(A1,"-",A2,"-",A3) AS A_CONDITION1,
    CONCAT(A1,"-",A2) AS A_CONDITION2,
    A1 AS A_CONDITION3
    FROM a
) AS a_tmp ON 
(a_tmp.A_CONDITION1 = b_tmp.B_CONDITION1 OR a_tmp.A_CONDITION2 = b_tmp.B_CONDITION2 OR a_tmp.A_CONDITION3 = b_tmp.B_CONDITION3)