postgreslq 函数中与输入值的条件连接

mid*_*uru 0 postgresql join

我有三张表:

create table id_table (
    id integer
);

insert into id_table values (1),(2),(3);

create table alphabet_table (
    id integer,
    letter text
);

insert into alphabet_table values (1,'a'),(2,'b'),(3,'c');

create table greek_table (
    id integer,
    letter text
);

insert into greek_table values (1,'alpha'),(2,'beta');
Run Code Online (Sandbox Code Playgroud)

我喜欢创建一个函数,将 id_table 与 id 上的字母表或希腊表连接起来。表的选择取决于函数中指定的输入值。我写:

CREATE OR REPLACE FUNCTION choose_letters(letter_type text)
  RETURNS table (id integer,letter text) AS $$
BEGIN
  RETURN QUERY
  select t1.id,
         case when letter_type = 'alphabet' then t2.letter else t3.letter end as letter
  from id_table t1,
       alphabet_table t2 ,
       greek_table t3 
  where t1.id = t2.id and t1.id = t3.id;

END;
$$LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

我跑了select choose_letter('alphabet')。这段代码的问题在于,当 id_table 与alphabet_table 连接时,它没有选择id,没有3。似乎对alphabet_table 和greek_table 都进行了内部连接(所以它只选择了公共ID,1 和2)。为了避免这个问题,我写道:

CREATE OR REPLACE FUNCTION choose_letters(letter_type text)
  RETURNS table (id integer, letter text) AS $$
BEGIN
  RETURN QUERY
  select t1.id,
         case when letter_type = 'alphabet' then t2.letter else t3.letter end as letter
  from id_table t1
  left join alphabet_table t2 on t1.id=t2.id
  left join greek_table t3 on t1.id=t3.id
  where t2.letter is not null or t3.letter is not null;

END;
$$LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

现在,当 id_table 和alphabet_table 连接时,它会获取所有 3 个 id。但是,当我跑select choose_letter('greek'). 身份证号码 尽管我t3.letter is not null在 where 子句中指定了事实,但 3 在字母列中出现空值。

我正在寻找的是,当我运行时select choose_letters('alphabet'),输出需要是 (1,'a'), (2,'b'),(3,'c')。select choose_letters('greek')应该产生 (1,'alpha'),(2,'beta)。没有缺失值或空值。我怎样才能做到这一点?

Gor*_*off 6

学习使用正确、明确的JOIN语法。简单规则: 永远不要FROM子句中使用逗号。

你可以做你想做的事LEFT JOIN和其他一些逻辑:

select i.id,
       coalesce(a.letter, g.letter) as letter
from id_table i left join
     alphabet_table a
     on i.id = a.id and letter_type = 'alphabet' left join
     greek_table g
     on i.id = g.id and letter_type <> 'alphabet'
where a.id is not null or g.id is not null;
Run Code Online (Sandbox Code Playgroud)

使用条件letter_type需要在on子句中。否则,alphabet_table总会有一场比赛。