Postgres从基于查询结果的表中选择

时间:2015-07-15 00:25:15

标签: postgresql postgresql-9.3

我有两个相同列的表,顺序相同。我希望根据子查询条件加入两个表中的一个。例如,假设我有以下架构:

CREATE TABLE b (
    bid SERIAL PRIMARY KEY,
    cid INT NOT NULL
);

CREATE TABLE a1 (
    aid SERIAL PRIMARY KEY,
    bid INT NOT NULL REFERENCES b
);

CREATE TABLE a2 (
    aid SERIAL PRIMARY KEY,
    bid INT NOT NULL REFERENCES b
);

我想要一个查询,根据某些条件在 a1 a2 之间执行连接。类似的东西:

WITH z AS (
  SELECT cid, someCondition FROM someTable
)
SELECT *
FROM CASE z.someCondition THEN a1 ELSE a2 END
JOIN b USING (bid)
WHERE cid = (SELECT cid FROM z);

但是,上述方法并不奏效。是否有某种方法可以有条件地连接 a1 a2 ,具体取决于存储在表 z 中的某些布尔条件?

3 个答案:

答案 0 :(得分:3)

如果条件是独占的(我希望它们是):只需使用智能联合构造两个查询和UNION ALL它们:

WITH z AS (
  SELECT cid
        , (cid %3) AS some_condition -- Fake ... 
        FROM  b
  )
SELECT *
  FROM a1
  JOIN b USING (bid)
 WHERE EXISTS( SELECT * FROM z
        WHERE some_condition = 1 AND cid = b.cid )
UNION ALL
SELECT *
  FROM a2
  JOIN b USING (bid)
 WHERE EXISTS( SELECT * FROM z
        WHERE some_condition = 2 AND cid = b.cid )
        ;

执行相同操作的语法略有不同:

WITH z AS (
  SELECT cid
        , (cid %3) AS some_condition 
        FROM  b
)
SELECT *
  FROM a1
  JOIN b ON a1.bid = b.bid
        AND EXISTS( SELECT * FROM z
        WHERE some_condition = 1 AND cid = b.cid )
UNION ALL
SELECT *
  FROM a2
  JOIN b ON a2.bid = b.bid
        AND EXISTS( SELECT * FROM z
        WHERE some_condition = 2 AND cid = b.cid )
        ;

答案 1 :(得分:2)

SQL语法不允许条件连接。 实现类似效果的最简单方法可能是在plpgsql函数中使用动态查询,如下所示:

create function conditional_select(acid int, some_condition boolean)
returns table (aid int, bid int, cid int)
language plpgsql as $$
declare
    tname text;
begin
    if some_condition then tname = 'a1';
    else tname = 'a2';
    end if;

    return query execute format ($fmt$
        select a.aid, b.bid, b.cid 
        from %s a
        join b using(bid)
        where cid = %s;
        $fmt$, tname, acid);
end $$;


select * from conditional_select(1, true)

答案 2 :(得分:1)

如果在您的示例中,您只想输出几列,则可以对每列使用CASE语句:

SELECT CASE z.someCondition THEN a1.aid ELSE a2.aid END AS aid,
       CASE z.someCondition THEN a1.bid ELSE a2.bid END AS bid
FROM b
JOIN a1 ON a1.bid = b.bid
JOIN a2 ON a2.bid = b.bid
JOIN someTable z USING (cid);

根据表格a1a2的大小以及您必须输出的列数,这可能或者我不会比Klin的具有函数的解决方案更快,这本质上是比纯SQL慢,尤其是因为动态查询。鉴于z.someCondition已经是boolean值,CASE评估将非常快。小桌子+几列=这个解决方案;大表+多列= Klin的解决方案。