SELECT 行的结果等于来自 DISTINCT 的值列表
SELECT rows HAVING result equal to a list of values from DISTINCT
我想要 return 结果与 key
匹配,其中所有 parts
都存在。鉴于:
create table things (
id int not null,
key int not null,
part character varying(1),
details character varying(64),
CONSTRAINT things_pkey PRIMARY KEY (id)
);
还有这个:
id
key
part
details
1
1
a
1a details
2
1
b
1b details
3
1
c
1c details
4
2
a
2a details
5
2
b
2b details
6
2
c
2c details
7
3
a
3a details
8
3
c
3c details
9
4
b
4b details
10
5
b
5b details
11
6
b
6b details
12
6
c
6c details
13
7
a
7a details
14
8
a
8a details
我可以做到这一点:
id
key
part
details
1
1
a
1a details
2
1
b
1b details
3
1
c
1c details
4
2
a
2a details
5
2
b
2b details
6
2
c
2c details
使用此查询:
select *
from things t
where t.key in (
select x.key
from things x
group by x.key
having count(distinct part) = 3
);
但我真的很想匹配不同的部分,而不仅仅是它的计数,例如having distinct part = ['a', 'b', 'c']
。我可以在查询中执行此操作还是仅在应用程序代码中执行此操作?
http://sqlfiddle.com/#!17/38b399/6
编辑
本质上,我所追求的是一大块行,其中存在 thing
的所有 part
。一件事有八个部分。它们将被处理并删除 table 中的记录。永远重复。
这是来自 pgAdmin 的 CREATE
脚本(减少噪音):
CREATE TABLE public.things (
id uuid PRIMARY KEY,
key character varying(255) COLLATE pg_catalog."default" NOT NULL,
part character varying(3) COLLATE pg_catalog."default" NOT NULL,
details character varying(1024) COLLATE pg_catalog."default",
timezone character varying(128) COLLATE pg_catalog."default",
client_id uuid,
CONSTRAINT things_client_id_fkey FOREIGN KEY (client_id)
REFERENCES public.clients (id)
);
CREATE INDEX things_client_id_index ON public.things (client_id);
CREATE UNIQUE INDEX unique_things ON public.things (key, part, client_id);
我认为 count(distinct)
可以满足您的要求。如果你想明确指定部分,你可以使用:
where t.key in (
select x.key
from things x
group by x.key
having array_agg(distinct part order by part)::text[] = array['a', 'b', 'c']
);
基本上这可以转换为 relational-division.
的情况
检查每个键的部件的不同计数的查询必须处理 table 的 所有 行。另外,distinct 计数是昂贵的。聚合和比较数组的成本更高。
如果大多数行都符合条件,那不会有太大的区别,因为整个 table 无论如何都会被处理。对于一小部分选择,任何此类方法的表现都非常糟糕。相比之下,可以使用 indexes 的替代查询技术会大放异彩。
理想情况下,您有一个单独的 table 键,每个相关键一行。然后使用这样的东西:
SELECT *
FROM keys k
WHERE EXISTS (SELECT FROM things WHERE key = k.key AND part = 'a')
AND EXISTS (SELECT FROM things WHERE key = k.key AND part = 'b')
AND EXISTS (SELECT FROM things WHERE key = k.key AND part = 'c');
Table things
需要 (part, key)
上的多列索引以使其快速。
即使你没有 keys
table:
SELECT t1.key
FROM things t1
JOIN things t2 USING (key)
JOIN things t3 USING (key)
WHERE t1.part = 'a'
AND t2.part = 'b'
AND t3.part = 'c';
db<>fiddle here
最佳查询取决于您对过滤器和结果格式的精确 要求,以及精确 架构定义。
相关:
- How to filter SQL results in a has-many-through relation
我想要 return 结果与 key
匹配,其中所有 parts
都存在。鉴于:
create table things (
id int not null,
key int not null,
part character varying(1),
details character varying(64),
CONSTRAINT things_pkey PRIMARY KEY (id)
);
还有这个:
id | key | part | details |
---|---|---|---|
1 | 1 | a | 1a details |
2 | 1 | b | 1b details |
3 | 1 | c | 1c details |
4 | 2 | a | 2a details |
5 | 2 | b | 2b details |
6 | 2 | c | 2c details |
7 | 3 | a | 3a details |
8 | 3 | c | 3c details |
9 | 4 | b | 4b details |
10 | 5 | b | 5b details |
11 | 6 | b | 6b details |
12 | 6 | c | 6c details |
13 | 7 | a | 7a details |
14 | 8 | a | 8a details |
我可以做到这一点:
id | key | part | details |
---|---|---|---|
1 | 1 | a | 1a details |
2 | 1 | b | 1b details |
3 | 1 | c | 1c details |
4 | 2 | a | 2a details |
5 | 2 | b | 2b details |
6 | 2 | c | 2c details |
使用此查询:
select *
from things t
where t.key in (
select x.key
from things x
group by x.key
having count(distinct part) = 3
);
但我真的很想匹配不同的部分,而不仅仅是它的计数,例如having distinct part = ['a', 'b', 'c']
。我可以在查询中执行此操作还是仅在应用程序代码中执行此操作?
http://sqlfiddle.com/#!17/38b399/6
编辑
本质上,我所追求的是一大块行,其中存在 thing
的所有 part
。一件事有八个部分。它们将被处理并删除 table 中的记录。永远重复。
这是来自 pgAdmin 的 CREATE
脚本(减少噪音):
CREATE TABLE public.things (
id uuid PRIMARY KEY,
key character varying(255) COLLATE pg_catalog."default" NOT NULL,
part character varying(3) COLLATE pg_catalog."default" NOT NULL,
details character varying(1024) COLLATE pg_catalog."default",
timezone character varying(128) COLLATE pg_catalog."default",
client_id uuid,
CONSTRAINT things_client_id_fkey FOREIGN KEY (client_id)
REFERENCES public.clients (id)
);
CREATE INDEX things_client_id_index ON public.things (client_id);
CREATE UNIQUE INDEX unique_things ON public.things (key, part, client_id);
我认为 count(distinct)
可以满足您的要求。如果你想明确指定部分,你可以使用:
where t.key in (
select x.key
from things x
group by x.key
having array_agg(distinct part order by part)::text[] = array['a', 'b', 'c']
);
基本上这可以转换为 relational-division.
的情况检查每个键的部件的不同计数的查询必须处理 table 的 所有 行。另外,distinct 计数是昂贵的。聚合和比较数组的成本更高。
如果大多数行都符合条件,那不会有太大的区别,因为整个 table 无论如何都会被处理。对于一小部分选择,任何此类方法的表现都非常糟糕。相比之下,可以使用 indexes 的替代查询技术会大放异彩。
理想情况下,您有一个单独的 table 键,每个相关键一行。然后使用这样的东西:
SELECT *
FROM keys k
WHERE EXISTS (SELECT FROM things WHERE key = k.key AND part = 'a')
AND EXISTS (SELECT FROM things WHERE key = k.key AND part = 'b')
AND EXISTS (SELECT FROM things WHERE key = k.key AND part = 'c');
Table things
需要 (part, key)
上的多列索引以使其快速。
即使你没有 keys
table:
SELECT t1.key
FROM things t1
JOIN things t2 USING (key)
JOIN things t3 USING (key)
WHERE t1.part = 'a'
AND t2.part = 'b'
AND t3.part = 'c';
db<>fiddle here
最佳查询取决于您对过滤器和结果格式的精确 要求,以及精确 架构定义。
相关:
- How to filter SQL results in a has-many-through relation