【问题标题】:MySQL Query Question.. I give up!MySQL查询问题..我放弃了!
【发布时间】:2009-12-10 02:14:17
【问题描述】:

*UPDATE,似乎已经给出了答案,但是 SQL 查询他的错误..有人可以帮忙吗?看到第一个答案,我把问题贴在那里。

简单地说。我有 3 张桌子。一个“item”表和一个“tag”表。然后我还有一个“item_tag”表,将两者联系在一起。

我想进行一个查询,列出所有分配有特定标签的项目。所以我希望查询列出所有应用了标签 x 和标签 y 的项目。

这是我目前为止的想法。除了这将列出任何匹配标签 id 148 或标签 id 152 的内容。如果我让它说“AND”,它不会显示任何结果。

SELECT *
FROM (`item`)
RIGHT OUTER JOIN `item_tag` ON `item`.`id` = `item_tag`.`fk_item_id`
WHERE `item_tag`.`fk_tag_id` = "152" OR `item_tag`.`fk_tag_id` = "148"
GROUP BY `item`.`id`

【问题讨论】:

  • 大声笑。当然,当您在查询中有 id=152 AND id=148 时,它不会返回任何内容。这在逻辑上是不可能的。
  • 那么...也许可以提供一个解决方案?
  • 我正在努力。很抱歉这么粗鲁。
  • 哇。你的权利。我什至不知道我为什么质疑那部分哈哈.. woops

标签: php sql mysql database


【解决方案1】:

使用 JOIN:

 SELECT it.fk_item_id
   FROM ITEM i
   JOIN ITEM_TAG it1 ON it1.fk_item_id = i.id
                    AND it1.fk_tag_id = 148
   JOIN ITEM_TAG it2 ON it2.fk_item_id = i.id
                    AND it2.fk_tag_id = 152

使用 GROUP BY/HAVING COUNT:

  SELECT it.fk_item_id
    FROM ITEM_TAG it
   WHERE it.fk_tag_id IN (148, 152)
GROUP BY it.fk_item_id
  HAVING COUNT(*) = 2

买者自负
查询的GROUP BY/HAVING COUNT 版本取决于您的数据模型,该数据模型具有为所涉及的两列(fk_item_idfk_tag_id)定义的唯一或主复合键。如果这没有到位,数据库将不会停止添加重复项。如果数据中可能存在重复行,则此版本可能会返回误报,因为 item_id 可能与 tag_id 148 有 2 个关联 - 这将满足 HAVING COUNT(*) = 2

【讨论】:

  • 我更喜欢使用 JOIN 的方法,比较 stackoverflow.com/questions/621884/… "5. Favoring aggregation over joins"
  • @VolkerK:我自己倾向于 JOIN,但 GROUP BY 过去在 SO 上的投票率更高:/
【解决方案2】:

您可以使用此查询获取具有您想要的所有标签的项目的 ID:

SELECT fk_item_id
FROM item_tag
WHERE fk_tag_id IN (5,10,15)
GROUP BY fk_item_id
HAVING COUNT(*) = 3

然后就

SELECT * 
FROM item 
WHERE id 
IN 
(
    SELECT fk_item_id
    FROM item_tag
    WHERE fk_tag_id IN (5,10,15)
    GROUP BY fk_item_id
    HAVING COUNT(*) = 3
)

您只需要修改 id 和 3 这是这些 id 的计数。

当您的表没有UNIQUE 约束(它应该有)并且特定项目中可能有相同的标签时,您应该将查询修改为:

SELECT * 
FROM item 
WHERE id 
IN 
(
    SELECT fk_item_id
    FROM ( SELECT DISTINCT fk_item_id, fk_tag_id FROM item_tag ) someAlias
    WHERE fk_tag_id IN (5,10,15)
    GROUP BY fk_item_id
    HAVING COUNT(*) = 3
)

【讨论】:

  • HAVING COUNT(DISTINCT *) 更安全,以防标签可能多次关联。
  • “HAVING COUNT(DISTINCT *)”是什么意思?还有..我假设“IN”与“WHERE”语句中的“OR”相同?
  • 刚刚遇到了查询问题。检查屏幕截图.. thougH 并没有真正解释错误:(sensenich.bythepixel.com/error.gif 如果我取出查询运行的“具有计数(disticnt)行。
  • 问题出在DISTINCT。当您删除它时,它会起作用。但是,如果在您的表中,可以使用相同的标签多次标记一项,您可以再进行一次 SELECT。我将编辑我的答案。
  • 是的,您可以添加UNIQUE 约束。喜欢这个ALTER TABLE item_tag ADD UNIQUE(fk_item_id,fk_tag_id)。它不允许同一对(项目、标签)出现两次。
【解决方案3】:

我将系统放在 tem 表中,将编程语言放在标签中。使用此查询,您会得到以下结果:

SELECT *
FROM (`item`)
INNER JOIN `item_tag` ON `item`.`id` = `item_tag`.`fk_item_id`
INNER JOIN `tag` ON `item_tag`.`fk_tag_id` = `tag`.`id`
WHERE `tag`.`desc` = 'Java' or `tag`.`desc` = 'C++'

结果:

1, 'Sistem A', 1, 1, 1, 'Java'
1, 'Sistem A', 1, 3, 3, 'C++'
2, 'Sistem B', 2, 1, 1, 'Java'
2, 'Sistem B', 2, 3, 3, 'C++'

在这种情况下,系统 A 和系统 B 使用 Java 和 C++。为了简化使用 distinct 子句

SELECT distinct item.desc
FROM (`item`)
INNER JOIN `item_tag` ON `item`.`id` = `item_tag`.`fk_item_id`
INNER JOIN `tag` ON `item_tag`.`fk_tag_id` = `tag`.`id`
WHERE `tag`.`desc` = 'Java' or `tag`.`desc` = 'C++'

结果:

System A
System B

【讨论】:

    【解决方案4】:

    我希望这将为您的表格建模(您提到 3 个表格,但我只有 2 个)

    -- drop table item ;
    -- drop table item_tag ;
    
    create table item (
        id int not null auto_increment 
        , primary key ( id )
    );
    create table item_tag (
        fk_item_id int not null
    ,   fk_tag_id int not null
    );
    
    insert into item values ( 1 );
    insert into item values ( 2 );
    insert into item values ( 3 );
    
    insert into item_tag values ( 1, 148 );
    insert into item_tag values ( 1, 152 );
    
    insert into item_tag values ( 2, 148 );
    
    insert into item_tag values ( 3, 152 );
    
    select i.id, a.fk_tag_id, b.fk_tag_id
    from item i, item_tag a, item_tag b
    where i.id = a.fk_item_id 
      and i.id = b.fk_item_id 
      and a.fk_tag_id = 148 
      and b.fk_tag_id = 152 
    ;
    

    产生输出

    +----+-----------+-----------+
    | id | fk_tag_id | fk_tag_id |
    +----+-----------+-----------+
    |  1 |       148 |       152 | 
    +----+-----------+-----------+
    1 row in set (0.00 sec)
    

    【讨论】:

    • 这也限制了他使用两个相等的标签。
    【解决方案5】:
    select * from item, item_tag a, item_tag b
    where item.id = a.fk_item_id and a.fk_tag_id = 148 and
    item.id = b.fk_item_id and b.fk_tag_id = 152;
    

    【讨论】:

    • 不。他必须将两个标签都分配给该项目。
    • 如果他有两个以上的标签怎么办?
    • 对不起。我不是想成为一个坏蛋,我现在并不比你聪明......;)
    • 我认为这个问题只需要两个标签。如果他需要两个以上,我得考虑一下。
    【解决方案6】:

    select * from item where item.id = itemtag.fk_item_id and item_tag.fk_tag_id = "152" or item_tag.fk_tag_id = "148" 按 item.id 分组

    【讨论】:

    • 现在不是必须是AND吗?
    猜你喜欢
    • 2017-06-23
    • 2011-11-14
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    相关资源
    最近更新 更多