Complex SQL join 根据给定结构查询
Complex SQL join Query according to given structure
我有两个 table posts
和 category_relationships
。我需要根据以下逻辑从中得到有点复杂的结果集。
个帖子table
id | post
-----|------------------------------|
1000 | Lorem ipsum dolor sit amet |
1001 | consectetur adipiscing elit |
1002 | sed do eiusmod tempor ut |
1004 | abore et dolore magna aliqua |
category_relationships table
post_id cat_id
---------|---------|
1000 | 201 |
1000 | 202 |
1000 | 211 |
1001 | 201 |
1001 | 211 |
1002 | 202 |
1002 | 212 |
首先我将尝试解释我的类别结构。我有如下的三层结构。 (为简单起见,我不包括任何类别table)
flight [level 1] [ID : 100]
- class [level 2] [ID : 200]
-- economy [level 3] [ID : 201]
-- business [level 3] [ID : 202]
-- first [level 3] [ID : 203]
- alliance [level 2] [ID : 210]
-- star [level 3] [ID : 211]
-- oneworld [level 3] [ID : 212]
-- skyteam [level 3] [ID : 213]
现在算法:
我需要根据以下规则将所有帖子标记为 flight
类别或任何 child/children。
我需要排除标记为 economy
(ID:201);
的帖子
- 但是,如果它的兄弟姐妹之一(
business
或 first
)被标记,它应该仍然在结果集中。
- 不应考虑
alliance
或其 child/children 被标记的帖子 IF economy
也被标记在相同的帖子
请注意,我可以根据结构获取类别 ID 并在查询中使用它们。
我目前的做法:
SELECT posts.ID FROM posts
LEFT JOIN category_relationships AS tt1 ON (posts.ID = tt1.post_id)
WHERE tt1.cat_id IN (100,200,201,202,203,210,211,212,213)
AND posts.ID NOT IN ( SELECT post_id FROM category_relationships WHERE cat_id IN (201) )
但这里的问题是它正在删除所有标记为 economy
的帖子。但是,它不满足规则编号 1。
理想的结果集如下所示;
1000 - rule number 1
1002 - anyway no `economy` tagged
不包括:
1001 - rule number 2
1004 - no tagged
希望您对这个问题有清晰的认识,如有任何帮助,我们将不胜感激。
将您的条件从 where 子句移动到 ON 子句
SELECT posts.ID FROM posts
LEFT JOIN category_relationships AS tt1 ON (posts.ID = tt1.post_id)
and tt1.cat_id IN (100,200,201,202,203,210,211,212,213)
AND posts.ID NOT IN ( SELECT post_id FROM category_relationships WHERE cat_id IN (201) )
所以你的条件之一是"It has not category 201 OR it has category 202 or 203"。您缺少 OR 条件 OR tt1.cat_id IN (202, 203)
:
SELECT DISTINCT posts.ID FROM posts
JOIN category_relationships AS tt1 ON (posts.ID = tt1.post_id)
WHERE tt1.cat_id IN (100,200,201,202,203,210,211,212,213)
AND (
posts.ID NOT IN ( SELECT post_id FROM category_relationships WHERE cat_id IN (201) )
OR
tt1.cat_id IN (202, 203)
)
请注意,您的 LEFT JOIN 没有任何意义,将由引擎转换为 INNER JOIN。
但是 - 我将按以下方式编写查询:
SELECT posts.ID
FROM posts
JOIN category_relationships AS tt1 ON posts.ID = tt1.post_id
WHERE tt1.cat_id IN (100,200,201,202,203,210,211,212,213)
GROUP BY posts.ID
HAVING SUM(tt1.cat_id = 201) = 0
OR SUM(tt1.cat_id = 202) > 0
OR SUM(tt1.cat_id = 203) > 0
这是 group by
和 having
的良好候选者:
SELECT cr.post_id
FROM category_relationships cr
GROUP BY cr.post_id
HAVING SUM(cr.tag_id = 100) > 0 AND -- flight
(SUM(cr.tag_id = 201) > 0 OR -- economy
SUM(cr.tag_id IN (202, 203)) > 0 -- business/first
) AND
NOT (SUM(cr.tag_id = 201) > 0 OR -- economy
SUM(cr.tag_id IN (210, 211, 212, 213) = 0 -- alliance
);
使用标记可能更容易理解:
SELECT cr.post_id
FROM (SELECT cr.*,
(cr.tag_id = 100) as is_flight,
(cr.tag_id = 201) as is_economy,
(cr.tag_id in (202, 203)) as is_first_business,
(cr.tag_id IN (210, 211, 212, 213)) as is_alliance
FROM category_relationships cr
) cr
GROUP BY cr.post_id
HAVING SUM(is_flight) > 0 AND
(SUM(is_economy) > 0 OR
SUM(is_business_first) > 0
) AND
NOT (SUM(is_economy) > 0 OR
SUM(is_alliance) > 0
);
我有两个 table posts
和 category_relationships
。我需要根据以下逻辑从中得到有点复杂的结果集。
个帖子table
id | post
-----|------------------------------|
1000 | Lorem ipsum dolor sit amet |
1001 | consectetur adipiscing elit |
1002 | sed do eiusmod tempor ut |
1004 | abore et dolore magna aliqua |
category_relationships table
post_id cat_id
---------|---------|
1000 | 201 |
1000 | 202 |
1000 | 211 |
1001 | 201 |
1001 | 211 |
1002 | 202 |
1002 | 212 |
首先我将尝试解释我的类别结构。我有如下的三层结构。 (为简单起见,我不包括任何类别table)
flight [level 1] [ID : 100]
- class [level 2] [ID : 200]
-- economy [level 3] [ID : 201]
-- business [level 3] [ID : 202]
-- first [level 3] [ID : 203]
- alliance [level 2] [ID : 210]
-- star [level 3] [ID : 211]
-- oneworld [level 3] [ID : 212]
-- skyteam [level 3] [ID : 213]
现在算法:
我需要根据以下规则将所有帖子标记为 flight
类别或任何 child/children。
我需要排除标记为 economy
(ID:201);
- 但是,如果它的兄弟姐妹之一(
business
或first
)被标记,它应该仍然在结果集中。 - 不应考虑
alliance
或其 child/children 被标记的帖子 IFeconomy
也被标记在相同的帖子
请注意,我可以根据结构获取类别 ID 并在查询中使用它们。
我目前的做法:
SELECT posts.ID FROM posts
LEFT JOIN category_relationships AS tt1 ON (posts.ID = tt1.post_id)
WHERE tt1.cat_id IN (100,200,201,202,203,210,211,212,213)
AND posts.ID NOT IN ( SELECT post_id FROM category_relationships WHERE cat_id IN (201) )
但这里的问题是它正在删除所有标记为 economy
的帖子。但是,它不满足规则编号 1。
理想的结果集如下所示;
1000 - rule number 1
1002 - anyway no `economy` tagged
不包括:
1001 - rule number 2
1004 - no tagged
希望您对这个问题有清晰的认识,如有任何帮助,我们将不胜感激。
将您的条件从 where 子句移动到 ON 子句
SELECT posts.ID FROM posts
LEFT JOIN category_relationships AS tt1 ON (posts.ID = tt1.post_id)
and tt1.cat_id IN (100,200,201,202,203,210,211,212,213)
AND posts.ID NOT IN ( SELECT post_id FROM category_relationships WHERE cat_id IN (201) )
所以你的条件之一是"It has not category 201 OR it has category 202 or 203"。您缺少 OR 条件 OR tt1.cat_id IN (202, 203)
:
SELECT DISTINCT posts.ID FROM posts
JOIN category_relationships AS tt1 ON (posts.ID = tt1.post_id)
WHERE tt1.cat_id IN (100,200,201,202,203,210,211,212,213)
AND (
posts.ID NOT IN ( SELECT post_id FROM category_relationships WHERE cat_id IN (201) )
OR
tt1.cat_id IN (202, 203)
)
请注意,您的 LEFT JOIN 没有任何意义,将由引擎转换为 INNER JOIN。
但是 - 我将按以下方式编写查询:
SELECT posts.ID
FROM posts
JOIN category_relationships AS tt1 ON posts.ID = tt1.post_id
WHERE tt1.cat_id IN (100,200,201,202,203,210,211,212,213)
GROUP BY posts.ID
HAVING SUM(tt1.cat_id = 201) = 0
OR SUM(tt1.cat_id = 202) > 0
OR SUM(tt1.cat_id = 203) > 0
这是 group by
和 having
的良好候选者:
SELECT cr.post_id
FROM category_relationships cr
GROUP BY cr.post_id
HAVING SUM(cr.tag_id = 100) > 0 AND -- flight
(SUM(cr.tag_id = 201) > 0 OR -- economy
SUM(cr.tag_id IN (202, 203)) > 0 -- business/first
) AND
NOT (SUM(cr.tag_id = 201) > 0 OR -- economy
SUM(cr.tag_id IN (210, 211, 212, 213) = 0 -- alliance
);
使用标记可能更容易理解:
SELECT cr.post_id
FROM (SELECT cr.*,
(cr.tag_id = 100) as is_flight,
(cr.tag_id = 201) as is_economy,
(cr.tag_id in (202, 203)) as is_first_business,
(cr.tag_id IN (210, 211, 212, 213)) as is_alliance
FROM category_relationships cr
) cr
GROUP BY cr.post_id
HAVING SUM(is_flight) > 0 AND
(SUM(is_economy) > 0 OR
SUM(is_business_first) > 0
) AND
NOT (SUM(is_economy) > 0 OR
SUM(is_alliance) > 0
);