如何使用左外连接 select 最小 UUID?
How to select minimum UUID with left outer join?
我正在尝试 select 来自 table 的一行,其中:
- 具有最小 UUID
- 未在另一个 table
中引用
但是我在尝试强制执行第一个约束时遇到了问题。
以下是对整数按预期工作的所有内容:
首先,创建如下所示的 tables:
t1
+----+---------+
| id | content |
+----+---------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+---------+
和
t2
+----+---------+
| id | t1_id |
+----+---------+
| 1 | 1 |
+----+---------+
postgres=# create table t1(id int, content varchar(10), primary key (id));
CREATE TABLE
postgres=# create table t2(id int, t1_id int, foreign key (t1_id) references t1(id));
CREATE TABLE
postgres=# insert into t1 values (1, 'a');
INSERT 0 1
postgres=# insert into t1 values (2, 'b');
INSERT 0 1
postgres=# insert into t1 values (3, 'c');
INSERT 0 1
postgres=# insert into t2 values (1, 1);
INSERT 0 1
现在,我想 select t1
中具有最低 id
的行,它不会在 t2
中显示为外键。我想 select t1
中有 id = 2
的行,它按预期工作:
postgres=# select min(t1.id) from t1 left outer join t2 on t1.id = t2.t1_id where t2.id is null;
min
-----
2
(1 row)
但是,当我对 UUID 进行相同的尝试时,最终查询根本无法 return 任何内容。请注意,我使用 answer from this post 定义了一种查找最小 UUID 的方法:
CREATE OR REPLACE FUNCTION min(uuid, uuid)
RETURNS uuid AS $$
BEGIN
IF IS NULL OR > THEN
RETURN ;
END IF;
RETURN ;
END;
$$ LANGUAGE plpgsql;
create aggregate min(uuid) (
sfunc = min,
stype = uuid,
combinefunc = min,
parallel = safe,
sortop = operator (<)
);
现在,像以前一样构建 table,使用 gen_random_uuid
自动生成 UUID:
postgres=# drop table t2;
postgres=# drop table t1;
postgres=# create table t1(id uuid default gen_random_uuid(), content varchar(10), primary key (id));
postgres=# create table t2(id int, t1_id uuid, foreign key (t1_id) references t1(id));
postgres=# insert into t1(content) ('a');
postgres=# insert into t1(content) values ('a');
postgres=# insert into t1(content) values ('b');
postgres=# insert into t1(content) values ('c');
我们已经在 t1
中成功输入了三个条目。添加一个条目到 t2
:
postgres=# select * from t1;
id | content
--------------------------------------+---------
b6148ae3-db56-4a4a-8d46-d5b4f04277ac | a
03abd324-8626-4fb1-9cb0-593373abf9ca | b
9f12b297-3f60-48a7-8282-e27c3aff1152 | c
(3 rows)
postgres=# insert into t2 values(1, '9f12b297-3f60-48a7-8282-e27c3aff1152');
尝试 select t1
中最小 ID 未出现在 t2
中的行,请注意,这会失败。
postgres=# select min(t1.id) from t1 left outer join t2 on t1.id = t2.t1_id where t2.id is null;
min
-----
(1 row)
这里我们表明我们可以 select t1
中的两个未引用的条目并且我们可以 select 独立的最小 UUID:
postgres=# select t1.id from t1 left outer join t2 on t1.id = t2.t1_id where t2.id is null;
id
--------------------------------------
03abd324-8626-4fb1-9cb0-593373abf9ca
b6148ae3-db56-4a4a-8d46-d5b4f04277ac
(2 rows)
postgres=# select min(id) from t1;
min
--------------------------------------
03abd324-8626-4fb1-9cb0-593373abf9ca
(1 row)
因此,当我尝试 select 最小 UUID 同时还尝试执行左外连接时,发生了一些有趣的事情。
编辑:使用 not exists
时存在同样的问题:
postgres=# select min(id) from t1 where not exists (select t1_id from t2 where t2.t1_id = t1.id);
min
-----
(1 row)
但是使用not in
时没有出现问题:
postgres=# select min(id) from t1 where id not in (select t1_id from t2);
min
--------------------------------------
03abd324-8626-4fb1-9cb0-593373abf9ca
(1 row)
找到解决方案,结果发现比较this post的UUID的函数不正确。这是我写的函数,它可能性能较差,它通过了之前失败的所有情况:
CREATE FUNCTION min_uuid(uuid, uuid)
RETURNS uuid AS $$
BEGIN
-- if they're both null, return null
IF IS NULL AND IS NULL THEN
RETURN NULL ;
END IF;
-- if just 1 is null, return the other
IF IS NULL THEN
RETURN ;
END IF ;
IF IS NULL THEN
RETURN ;
END IF;
-- neither are null, return the smaller one
IF > THEN
RETURN ;
END IF;
RETURN ;
END;
$$ LANGUAGE plpgsql;
create aggregate min(uuid) (
sfunc = min_uuid,
stype = uuid,
combinefunc = min_uuid,
parallel = safe,
sortop = operator (<)
);
我正在尝试 select 来自 table 的一行,其中:
- 具有最小 UUID
- 未在另一个 table 中引用
但是我在尝试强制执行第一个约束时遇到了问题。
以下是对整数按预期工作的所有内容: 首先,创建如下所示的 tables:
t1
+----+---------+
| id | content |
+----+---------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+---------+
和
t2
+----+---------+
| id | t1_id |
+----+---------+
| 1 | 1 |
+----+---------+
postgres=# create table t1(id int, content varchar(10), primary key (id));
CREATE TABLE
postgres=# create table t2(id int, t1_id int, foreign key (t1_id) references t1(id));
CREATE TABLE
postgres=# insert into t1 values (1, 'a');
INSERT 0 1
postgres=# insert into t1 values (2, 'b');
INSERT 0 1
postgres=# insert into t1 values (3, 'c');
INSERT 0 1
postgres=# insert into t2 values (1, 1);
INSERT 0 1
现在,我想 select t1
中具有最低 id
的行,它不会在 t2
中显示为外键。我想 select t1
中有 id = 2
的行,它按预期工作:
postgres=# select min(t1.id) from t1 left outer join t2 on t1.id = t2.t1_id where t2.id is null;
min
-----
2
(1 row)
但是,当我对 UUID 进行相同的尝试时,最终查询根本无法 return 任何内容。请注意,我使用 answer from this post 定义了一种查找最小 UUID 的方法:
CREATE OR REPLACE FUNCTION min(uuid, uuid)
RETURNS uuid AS $$
BEGIN
IF IS NULL OR > THEN
RETURN ;
END IF;
RETURN ;
END;
$$ LANGUAGE plpgsql;
create aggregate min(uuid) (
sfunc = min,
stype = uuid,
combinefunc = min,
parallel = safe,
sortop = operator (<)
);
现在,像以前一样构建 table,使用 gen_random_uuid
自动生成 UUID:
postgres=# drop table t2;
postgres=# drop table t1;
postgres=# create table t1(id uuid default gen_random_uuid(), content varchar(10), primary key (id));
postgres=# create table t2(id int, t1_id uuid, foreign key (t1_id) references t1(id));
postgres=# insert into t1(content) ('a');
postgres=# insert into t1(content) values ('a');
postgres=# insert into t1(content) values ('b');
postgres=# insert into t1(content) values ('c');
我们已经在 t1
中成功输入了三个条目。添加一个条目到 t2
:
postgres=# select * from t1;
id | content
--------------------------------------+---------
b6148ae3-db56-4a4a-8d46-d5b4f04277ac | a
03abd324-8626-4fb1-9cb0-593373abf9ca | b
9f12b297-3f60-48a7-8282-e27c3aff1152 | c
(3 rows)
postgres=# insert into t2 values(1, '9f12b297-3f60-48a7-8282-e27c3aff1152');
尝试 select t1
中最小 ID 未出现在 t2
中的行,请注意,这会失败。
postgres=# select min(t1.id) from t1 left outer join t2 on t1.id = t2.t1_id where t2.id is null;
min
-----
(1 row)
这里我们表明我们可以 select t1
中的两个未引用的条目并且我们可以 select 独立的最小 UUID:
postgres=# select t1.id from t1 left outer join t2 on t1.id = t2.t1_id where t2.id is null;
id
--------------------------------------
03abd324-8626-4fb1-9cb0-593373abf9ca
b6148ae3-db56-4a4a-8d46-d5b4f04277ac
(2 rows)
postgres=# select min(id) from t1;
min
--------------------------------------
03abd324-8626-4fb1-9cb0-593373abf9ca
(1 row)
因此,当我尝试 select 最小 UUID 同时还尝试执行左外连接时,发生了一些有趣的事情。
编辑:使用 not exists
时存在同样的问题:
postgres=# select min(id) from t1 where not exists (select t1_id from t2 where t2.t1_id = t1.id);
min
-----
(1 row)
但是使用not in
时没有出现问题:
postgres=# select min(id) from t1 where id not in (select t1_id from t2);
min
--------------------------------------
03abd324-8626-4fb1-9cb0-593373abf9ca
(1 row)
找到解决方案,结果发现比较this post的UUID的函数不正确。这是我写的函数,它可能性能较差,它通过了之前失败的所有情况:
CREATE FUNCTION min_uuid(uuid, uuid)
RETURNS uuid AS $$
BEGIN
-- if they're both null, return null
IF IS NULL AND IS NULL THEN
RETURN NULL ;
END IF;
-- if just 1 is null, return the other
IF IS NULL THEN
RETURN ;
END IF ;
IF IS NULL THEN
RETURN ;
END IF;
-- neither are null, return the smaller one
IF > THEN
RETURN ;
END IF;
RETURN ;
END;
$$ LANGUAGE plpgsql;
create aggregate min(uuid) (
sfunc = min_uuid,
stype = uuid,
combinefunc = min_uuid,
parallel = safe,
sortop = operator (<)
);