使用Postgres我有3个表:
CREATE TABLE post (id SERIAL, body TEXT);
CREATE TABLE tag (id SERIAL, name TEXT);
CREATE TABLE post_tag (post_id INT, tag_id INT);
INSERT INTO post(body) values('post 1');
INSERT INTO post(body) values('post 2');
INSERT INTO tag(name) values('a');
INSERT INTO tag(name) values('b');
INSERT INTO post_tag values(1, 1);
INSERT INTO post_tag values(1, 2);
INSERT INTO post_tag values(2, 1);
因此,post 1
标记为a, b
,post 2
标记为a
。
问题:如何选择所有没有标记b
的帖子,这意味着它应该只选择post 2
。
此查询不合适,因为如果post 1
有2个标签a
& b
:
SELECT post.*
FROM post
JOIN post_tag ON post_tag.post_id = post.id
JOIN tag ON tag.id = post_tag.tag_id
WHERE tag.name != 'b';
此查询有效,但错误,因为如果有标记aaaaaaab
,那么它也会匹配它:
SELECT post.id, post.body, string_agg(tag1.name, ', ')
FROM post
JOIN post_tag ON post_tag.post_id = post.id
JOIN tag ON tag.id = post_tag.tag_id
GROUP BY post.id, post.body
HAVING string_agg(tag.name, ', ') not like '%b, %';
我正在寻找一种“正确”且有效的方法。
编辑:查询还应匹配根本没有任何标记的帖子。
答案 0 :(得分:2)
您可以使用查询选择具有聚合标记的帖子:
select p.id, p.body, array_agg(t.name) tags
from post p
left join post_tag pt on pt.post_id = p.id
left join tag t on pt.tag_id = t.id
group by 1, 2;
id | body | tags
----+--------+-------
1 | post 1 | {a,b}
2 | post 2 | {a}
(2 rows)
通过适当的修改,您可以使用查询来过滤数据,例如
select p.id, p.body
from post p
left join post_tag pt on pt.post_id = p.id
left join tag t on pt.tag_id = t.id
group by 1, 2
having 'b' <> all(array_agg(t.name));
-- or to get also posts without tags:
-- having 'b' <> all(array_agg(t.name)) or array_agg(t.name) = '{null}';
id | body
----+--------
2 | post 2
(1 row)
答案 1 :(得分:0)
使用子查询的一个解决方案是:
getData(): Observable<MyData> {
// try to use getRegularData, and return observable for result.
// if getRegularData returns null, get data from getAlternateData()
// instead and return observable for result.
}
我不确定此查询的效率如何,但它绝对不是最具可读性的。