【问题标题】:Complex SQL join Query according to given structure根据给定结构复杂的 SQL 连接查询
【发布时间】:2019-03-12 07:53:08
【问题描述】:

我有两张桌子postscategory_relationships。我需要根据以下逻辑从中得到一些复杂的结果。

帖子表

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 表

post_id    cat_id  
---------|---------|
   1000  |   201   | 
   1000  |   202   | 
   1000  |   211   | 
   1001  |   201   | 
   1001  |   211   | 
   1002  |   202   | 
   1002  |   212   | 

首先我将尝试解释我的类别结构。我有如下三层结构。 (为简单起见,我这里不包括任何类别表)

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 类别或任何孩子/孩子的帖子。

我需要排除标记为economy (ID:201) 的帖子;

  1. 但是,如果它的同级之一(businessfirst)被标记,它应该仍然在结果集中。
  2. 不应该考虑标记alliance或其子/子的帖子如果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

希望您对这个问题有清晰的认识,任何帮助都会非常感激。

【问题讨论】:

  • “问题是它正在删除所有标记为经济的帖子” - 为什么这是一个问题?这是一项要求 - “我需要排除标记为经济 (ID:201) 的帖子”
  • @PaulSpiegel 很抱歉造成混淆,实际上根据上面的行,它应该满足我在正文中提到的两个规则。
  • 我想通了.. 但不是很明显。

标签: mysql sql database jointable


【解决方案1】:

因此,您的条件之一是“它没有类别 201 或它具有类别 202 或 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

【讨论】:

  • OR 条件有意义,我想这就是我要找的。​​span>
【解决方案2】:

这是group byhaving 的好候选:

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 
           );

【讨论】:

    【解决方案3】:

    将条件从 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) ) 
    

    【讨论】:

    • @janitgchinthana 你的开场白自相矛盾,所以我们不知道
    猜你喜欢
    • 2010-11-02
    • 2023-03-08
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-29
    • 1970-01-01
    相关资源
    最近更新 更多