Roc*_*nja 6 postgresql postgresql-9.3
WITH upd AS (
UPDATE univ.products
SET source = source::int[] || _source
WHERE project_id = _project_id AND product_id = _products AND NOT(_source = ANY(source))
RETURNING id
)
, ins AS (
INSERT INTO univ.products(project_id, product_id, source, tracked)
SELECT _project_id, _product_id, ARRAY[_source], _tracked
WHERE NOT EXISTS (SELECT 1 FROM upd)
RETURNING id
)
SELECT id
FROM upd NATURAL FULL OUTER JOIN ins
INTO _project_product_id;
Run Code Online (Sandbox Code Playgroud)
我的情况,我有这个函数,其中包含上述所有内容以及更多内容,我试图避免重复项目/产品对,但同时通过附加新源来更新源。现在每个产品/项目对的源必须是唯一的,这就是我添加的原因NOT(_source = ANY(source))
,但如果这是真的,select 1 from up
将不会返回任何内容,因此将尝试将记录插入数据库以避免这种情况,我添加了以下内容例外。
EXCEPTION WHEN UNIQUE_VIOLATION THEN
EXIT;
END;
Run Code Online (Sandbox Code Playgroud)
这几乎是我想要的,但没有返回任何 id 有没有更好的方法来做到这一点?
我还注意到,如果我插入一条记录,那么我会插入具有不同源的相同记录(行id将为1),然后我插入另一条记录,行id将为3而不是2;
[编辑] 我通过执行以下操作解决了我的问题:
SET source = CASE WHEN NOT(source::int[] @> ARRAY[_source]) THEN source::int[] || _source ELSE source END
Run Code Online (Sandbox Code Playgroud)
有更好的解决方案吗?这个好像有点慢。
小智 1
它不是超级高效,但您可以将解决方案之类的东西定义为函数:
create or replace function set_append(anyarray, anyelement)
returns anyarray
immutable
PARALLEL safe
language sql as
$$
select case when $2=any($1) then $1 else $1 || $2 end;
$$;
Run Code Online (Sandbox Code Playgroud)
您还可以使用它来定义聚合:
CREATE AGGREGATE set_agg( ANYELEMENT ) (
SFUNC = set_append,
STYPE = ANYARRAY,
INITCOND = '{}');
Run Code Online (Sandbox Code Playgroud)
这将使您select set_agg(x order by y)
能够控制您无法控制的不同元素的顺序select array_agg(distinct x order by y)
。