我在列a和b. 我需要这样的东西:
insert into my_table (a, b) values (1, 2), (1, 2)
on conflict (a) do update set c = 'a_violation'
on conflict (b) do update set c = 'b_violation'
Run Code Online (Sandbox Code Playgroud)
所以一般我想根据冲突目标进行不同的更新 - 不支持上面的语法(只支持一个on conflict语句)。有没有其他方法可以做到这一点?
我想将用户 ID 存储在自定义会话变量中,并在触发器过程中使用(读取)它来授权用户操作。我发现了这样的东西:
set session "myapp.user" = '12345';
...
SELECT current_setting('myapp.user');
Run Code Online (Sandbox Code Playgroud)
它似乎有效 - 我认为“myapp.user”应该在 .conf 文件中声明,但似乎我可以即时创建会话变量(我根本没有更改 .conf 文件)。
这样做有什么坏处吗?
初始化测试数据:
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE TABLE docs (data JSONB NOT NULL DEFAULT '{}');
-- generate 200k documents, ~half with type: "type1" and another half with type: "type2", unique incremented index and random uuid per each row
INSERT INTO docs (data)
SELECT json_build_object('id', gen_random_uuid(), 'type', (CASE WHEN random() > 0.5 THEN 'type1' ELSE 'type2' END) ,'index', n)::JSONB
FROM generate_series(1, 200000) n;
-- inset one more row with explicit uuid to query by it later
INSERT INTO docs (data) …Run Code Online (Sandbox Code Playgroud) 我有下表:
create table test (
company_id integer not null,
client_id integer not null,
client_status text,
unique (company_id, client_id)
);
insert into test values
(1, 1, 'y'), -- company1
(2, 2, null), -- company2
(3, 3, 'n'), -- company3
(4, 4, 'y'), -- company4
(4, 5, 'n'),
(5, 6, null), -- company5
(5, 7, 'n')
;
Run Code Online (Sandbox Code Playgroud)
基本上,有 5 家不同的公司,每家公司都有一个或多个客户,每个客户的状态为:“y”或“n”(也可能为空)。
我必须做的是为(company_id, client_id)至少有一个客户的状态不是“n”(“y”或 null)的所有公司选择所有对。所以对于上面的示例数据,输出应该是:
company_id;client_id
1;1
2;2
4;4
4;5
5;6
5;7
Run Code Online (Sandbox Code Playgroud)
我尝试了一些使用窗口函数的东西,但我无法弄清楚如何将所有客户端的数量与带有STATUS = 'n'.
select company_id,
count(*) over (partition …Run Code Online (Sandbox Code Playgroud) 表jtest有 200k 行,每行包含 jsonb { id: "<uuid>", key: <index> }(<index>每行递增 1-200k 的整数)。上还有btree索引data->'key'。
create extension if not exists pgcrypto;
create table jtest (data jsonb not null default '{}');
insert into jtest (data)
select json_build_object('id', gen_random_uuid(), 'key', i)::jsonb
FROM generate_series(1,200000) i;
create index jtest_key on jtest ((data->'key'));
Run Code Online (Sandbox Code Playgroud)
第一个查询(快速):
EXPLAIN ANALYZE
select j.data
from jtest j
order by j.data->'key'
limit 20;
-- "Limit (cost=0.42..1.43 rows=20 width=74) (actual time=0.023..0.044 rows=20 loops=1)"
-- " -> Index Scan using …Run Code Online (Sandbox Code Playgroud) create function test(a integer, b integer)
returns table (a integer, b integer) as $$
begin
return query select 1, 2;
end;
$$ language plpgsql;
Run Code Online (Sandbox Code Playgroud)
抛出异常:
ERROR: parameter name "a" used more than once
CONTEXT: compilation of PL/pgSQL function "test" near line 1
Run Code Online (Sandbox Code Playgroud)
为什么会发生这种情况?我认为函数参数名称与返回的表列名称无关。是否有一种解决方法可以让函数参数命名为“a”,并且在从函数返回的表中还有名为“a”的列?
我知道我可以返回,setof record但是我必须明确地“定义”从选择查询中的函数返回的列:
create function test(a integer, b integer)
returns setof record as $$
begin
return query select 1, 2;
end;
$$ language plpgsql;
select * from test(1, 2) as (a integer, b integer)
Run Code Online (Sandbox Code Playgroud) 我正在尝试LEFT JOIN使用数组unnest()函数实现类似的功能。如果数组为空,我希望查询返回具有空值的行。因此,通过使用CASE构造,如果源数组为空,我想传递具有单个空元素的假数组,但它无法按预期工作:
查询 1
select element
from (
select array['a']::text[] as arr --< single non-null element
) sub, unnest(
(
case when array_length(sub.arr, 1) <= 0 then (array[null])::text[]
else sub.arr
end
)
) element
-- returns 1 row with element = "a"
Run Code Online (Sandbox Code Playgroud)
查询 2
select element
from (
select array[]::text[] as arr --< empty array
) sub, unnest(
(
case when array_length(sub.arr, 1) <= 0 then (array[null])::text[]
else sub.arr
end
)
) element
-- …Run Code Online (Sandbox Code Playgroud) create or replace function test()
returns void as $$
begin
update tbl set col1 = true where col2 = false;
-- now I want to raise exception if update query affected more than 2 rows to rollback the update
end;
$$ language plpgsql;
Run Code Online (Sandbox Code Playgroud)
如何在函数中为变量选择受影响的行数?
我正在尝试将中文字符粘贴到 psql 终端中:
$ psql
=> \encoding
=> UTF8
# Ctrl+v (?????)
=> ???????
Run Code Online (Sandbox Code Playgroud)
粘贴到普通终端(Max OS)时,它工作正常:
$ # Ctrl+v (?????)
$ ?????
Run Code Online (Sandbox Code Playgroud)
可能有什么问题?
我正在使用Postgres 9.3.
当我更新表中的行时,我的流程如下所示:
SELECT * FROM tbl WHERE id = 1)UPDATE tbl SET .... WHERE id = 1)问题是old数据可能在第 2 点期间发生变化,因此验证,即使通过也可能是outdated在第 3 点(更新行)期间。我知道我可以执行这样的更新UPDATE .... WHERE id = 1 AND column1='oldValue'以确保某些字段不会更改,但是我的验证(也比较新旧值)非常复杂,我无法在 SQL UPDATE 语句中“编写”它。
所以我想到了这样的事情:
BEGINSELECT * FROM tbl WHERE id = 1UPDATE SET=... WHERE id = 1COMMITCOMMIT如果在事务执行期间 id = 1 的行发生更改,我想失败。是否可以使用这样的交易?如果不是,其他解决方案是什么?
WITH upsert AS (UPDATE tbl SET a = 2 WHERE a = 1 RETURNING tbl.*)
INSERT INTO tbl (a)
SELECT 1 WHERE NOT EXISTS( SELECT * FROM upsert )
RETURNING *
Run Code Online (Sandbox Code Playgroud)
这个“upsert”语句有效,但是我想检索 UPDATE 或 INSERTED 值。当 upsert 执行INSERT(行尚未在 db 中)时,插入的值将从查询中正确返回。
但是,当UPDATE执行时,不会返回任何值(但行是更新的)。我试过添加,RETURNING upsert.*但它产生错误missing FROM-clause entry for table \"upsert\"。
这是示例:
drop table if exists tst;
create table tst (
num integer not null
);
insert into tst values (1), (2), (3);
-- window functions WITH order by clause
select *, max(num) over (partition by true order by num asc), array_agg(num) over (partition by true order by num asc) as test
from tst;
-- window functions WITHOUT order by clause
select *, max(num) over (partition by true), array_agg(num) over (partition by true) as test
from tst;
Run Code Online (Sandbox Code Playgroud)
结果如下:
为什么order by子句对聚合功能有影响?
在我的应用程序中执行了两种类型的查询:
DELETE FROM tbl1 WHERE user_id = 1;
INSERT INTO tbl1 VALUES (...), (...), ...;
Run Code Online (Sandbox Code Playgroud)
和
UPDATE tbl2 WHERE id = 1 SET ...;
DELETE FROM tbl3 WHERE tbl2_id = 1;
INSERT INTO tbl3 VALUES (...), (...), ...;
DELETE FROM tbl4 WHERE tbl2_id = 1;
INSERT INTO tbl4 VALUES (...), (...), ...;
Run Code Online (Sandbox Code Playgroud)
我使用的 ORM 自动将事务隔离级别设置为REPEATABLE READ,我想知道它是否是最佳性能的正确选择。我的目标是只执行全部或不执行(来自上面的 2 个事务),我不关心任何读取...
那么在我的情况下哪种隔离级别最适合最佳性能?