PostgreSQL函数从联接表中返回计算字符串

时间:2019-09-04 11:26:22

标签: sql postgresql

我有3张桌子。

Table A   |   Table B   |   Table C
----------|-------------|------------
name      |   name      |   name
phrase    |   phrase    |   phrase
field 1   |   include   |   include
field 2   |   exclude   |   exclude
field 3   |   field 1   |   field 1

表A,B,C也包含许多其他列,但我仅对Table B (include and exclude)Table C (include and exclude)感兴趣。

我正在尝试编写一个函数,该函数将表A的namephrase作为参数,并在Table BTable C上进行查询以获取{{1两个表的}}和include列,其中excludeTable B (name and phrase)等于参数Table C (name and phrase)name

include和exclude列为布尔值,我想使用phraseB.includeB.excludeC.include返回字符串。

到目前为止,我所写的是,但是我不确定是否正确。

C.exclude

我是新来编写函数的人,真的不知道我是否做对了。有人可以帮我指出正确的方向。

3 个答案:

答案 0 :(得分:1)

我不建议您为此编写函数。功能往往是性能的杀手。

相反,您可以编写视图,使用left join将表放在一起:

对于您编写的逻辑,您似乎想要:

select a.*,
       (case when b.include then 'B included' 
             when b.exclude then 'B excluded' 
             when c.include then 'C included' 
             when c.exclude then 'C excluded' 
        end) as string
from a left join
     b
     on a.name = b.name and a.phrase = b.phrase left join
     c
     on a.name = c.name and a.phrase = c.phrase;

这将返回标志上的第一个匹配项。我可能希望您希望以某种方式将字符串串联在一起,但这不是您编写的伪代码。

答案 1 :(得分:0)

我仍在学习,我在原始问题中写的是学习和试用代码。我最终写了这样的东西。...

CREATE OR REPLACE FUNCTION createString(name text, phrase text) RETURNS TEXT AS
$$
DECLARE
    moInclude boolean;
    moExcluded boolean;
    modaidInclude boolean;
    modaidExclude boolean;
    result text := 'None';
BEGIN
    select mo.include, mo.exclude, modaid.include, modaid.exclude INTO moInclude, moExcluded, modaidInclude, modaidExclude
    from (tableB AS mo JOIN tableC AS modaid on mo.text = modaid.text and mo.phrase = modaid.phrase)
    where mo.text = text and mo.phrase = phrase;

    IF moInclude = true AND modaidInclude = true THEN
        result := 'INCLUDED';
    ELSEIF (moExcluded = true) THEN
        result := 'EXCLUDED';
    ELSEIF ((moInclude = false AND modaidInclude = true AND modaidExclude = false) OR
        (moInclude = false AND modaidInclude = false AND modaidExclude = true) OR
        (moInclude = true AND modaidInclude = false AND modaidExclude = true) OR
        (moInclude = true AND modaidInclude = false AND modaidExclude = false)) THEN
        result := 'PARTIAL';
    ELSE
        result := 'NONE';
    END IF;

RETURN result;
END;
$$ LANGUAGE plpgsql;

在创建视图时调用此函数。

谢谢大家的帮助。

答案 2 :(得分:0)

@GordonLinoff是正确的,认为仅使用SQL而不是函数会更好。但是,如果必须具有一个函数,则可以创建一个SQL函数-具有language sql的函数。以下内容将转换您的最后一个函数,并将其重现为SQL函数。 另外,由于“包含”和“排除”列已定义为布尔值,因此它们不需要相等的撤离。也就是说,“ if include ...”将产生与“ if include = true”相同的结果。但是对于false值,您需要取反该值,这样“ if include = false”就变成“ not include”。我已经用过了,但是很容易替换。

-- create tables and gen test data 
create table tableA (name text, phase text, field1 text, field2 text, field3 text) ;
create table TableB (name text, phase text, include boolean, exclude boolean, field1 text);
create table TableC (name text, phase text, include boolean, exclude boolean, field1 text);


insert into tableA (name,phase)
     values ('n1','p1') 
          , ('n2','p1') 
          , ('n3','p1') 
          , ('n4','p1')
          , ('n5','p1')
          , ('n6',null);           

insert into tableB(name, phase, include, exclude)
     values ('n1','p1',true,true)
          , ('n2','p1',true,false)
          , ('n3','p1',false,true)
          , ('n4','p1',false,false)
          , ('n5','p1',false,false);

insert into tableC(name, phase, include, exclude) 
     values ('n1','p1',true,true)
          , ('n2','p1',true,false)
          , ('n3','p1',false,true)
          , ('n4','p1',false,false) 
          , ('n5','p1',true,false);

-------------------------------------------------------------------------------------------------------------
create or replace function createString(name_in text, phase_in text) 
returns text
language sql strict
as $$
    select case when (mo.include and modaid.include)                                     then 'INCLUDED'
                when (mo.exclude)                                                        then 'EXCLUDED'
                when (   (not mo.include and modaid.include and not modaid.exclude)  
                      or (not mo.include and not modaid.include and modaid.exclude) 
                      or (mo.include     and not modaid.include and modaid.exclude) 
                      or (mo.include     and not modaid.include and not modaid.exclude)) then 'PARTIAL'
                else 'NONE' 
            end   
     from tableb as mo 
     join tablec as modaid on (    mo.name  = modaid.name 
                               and mo.phase = modaid.phase
                              )
    where mo.name  = name_in
      and mo.phase = phase_in
$$; 

-------------------------------------------------------------------------------------------------------------
-- test
select name, phase, createString(name, phase) 
  from tableA;