选择拥有狗和猫的用户

时间:2010-03-17 15:46:45

标签: mysql

我有这个样本表:

CREATE TABLE `dummy` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userId` int(11) NOT NULL,
  `pet` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;


INSERT INTO `dummy` (`id`, `userId`, `pet`) VALUES(1, 1, 'dog');
INSERT INTO `dummy` (`id`, `userId`, `pet`) VALUES(2, 1, 'cat');
INSERT INTO `dummy` (`id`, `userId`, `pet`) VALUES(3, 2, 'dog');
INSERT INTO `dummy` (`id`, `userId`, `pet`) VALUES(4, 2, 'cat');
INSERT INTO `dummy` (`id`, `userId`, `pet`) VALUES(5, 3, 'cat');
INSERT INTO `dummy` (`id`, `userId`, `pet`) VALUES(6, 4, 'dog');

如何在mysql中编写以下语句:

  • 检索拥有狗和猫的所有用户
  • 检索拥有狗或猫的所有用户
  • 检索所有只拥有猫的用户
  • 检索所有没有猫的用户

编辑:在dbemerlin的帮助下,我有前两个语句的解决方案。他们在这里:

  • 检索拥有狗和猫的所有用户:

     SELECT * FROM dummy WHERE pet = 'cat' OR pet = 'dog' GROUP BY userId HAVING COUNT(*) = 2
    
  • 检索拥有狗或猫的所有用户:

     SELECT * FROM dummy WHERE pet = 'cat' OR pet = 'dog' GROUP BY userId
    

我找到了解决方案3:

  • 检索仅拥有猫的所有用户:

    SELECT * FROM dummy WHERE userId IN (SELECT userId FROM dummy WHERE pet = 'cat' GROUP BY userId) GROUP BY userId HAVING COUNT(*) = 1
    

    但阿德里亚诺有更好的解决方案:

    SELECT * FROM dummy WHERE pet = 'cat' AND userId NOT IN (SELECT userId FROM dummy WHERE pet != 'cat');
    

但最后一句话仍有问题:

  • 检索所有没有猫的用户:

     SELECT * FROM dummy WHERE pet != 'cat' GROUP BY userId
    

    这也不起作用。我真正需要的是检索所有没有猫但可能有其他宠物的用户。

谢谢!

编辑:这不是家庭作业。我试图在这里简化问题并解决问题。真实的情况是我正在尝试检索点击2个不同链接(存储为url字符串)等的用户。如果这是一个家庭作业,那么在这里询问如何实现这一点有什么不对?如果我有一个拥有MySQL知识的朋友,请问他告诉我解决方案并解释而不是问这里有什么不同?

4 个答案:

答案 0 :(得分:1)

1

SELECT u.user_id
FROM   user u
INNER JOIN dummy d
USING (user_id)
WHERE d.pet = 'cat'
OR d.pet = 'dog'
GROUP BY user_id
HAVING COUNT(*) = 2

2:

SELECT u.user_id
FROM   user u
INNER JOIN dummy d
USING (user_id)
WHERE d.pet = 'cat'
OR d.pet = 'dog'
GROUP BY user_id

3:

SELECT u.user_id
FROM   user u
INNER JOIN dummy d
USING (user_id)
WHERE d.pet = 'cat'

4:

SELECT u.user_id
FROM   user u
INNER JOIN dummy d
USING (user_id)
WHERE d.pet = 'dog'

答案 1 :(得分:1)

解决后一问题的一个方法是:

SELECT * 
FROM dummy 
WHERE pet = 'cat' 
AND userId NOT IN (
    SELECT userId 
    FROM dummy 
    WHERE pet != 'cat'
);

仅限有猫的用户。

这使您可以使用单个变量来表示您想要选择的宠物类型。

此处的结果,以及您发布的数据:

mysql> select * from dummy where pet = 'cat' and userId not in \
    -> (select userId from dummy where pet != 'cat');
+----+--------+-----+
| id | userId | pet |
+----+--------+-----+
|  5 |      3 | cat |
+----+--------+-----+
1 row in set (0.00 sec)

编辑: 对于您的上一个问题,您只需撤消选择中的=!=即可。在询问之前,请尝试考虑一下。

编辑: 你想知道性能。 MySQL提供的一个工具是EXPLAIN。使用关键字EXPLAIN对查询进行前缀将分析其性能,可能的执行路径,涉及的密钥和索引等。在这种情况下:

mysql> explain select * from dummy where pet = 'cat' and userId not in (select userId from dummy where pet != 'cat');
+----+--------------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type        | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+--------------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | PRIMARY            | dummy | ALL  | NULL          | NULL | NULL    | NULL |    6 | Using where |
|  2 | DEPENDENT SUBQUERY | dummy | ALL  | NULL          | NULL | NULL    | NULL |    6 | Using where |
+----+--------------------+-------+------+---------------+------+---------+------+------+-------------+
2 rows in set (0.00 sec)

mysql> explain SELECT * FROM dummy WHERE userId IN (SELECT userId FROM dummy WHERE pet = 'cat' GROUP BY userId) GROUP BY userId HAVING COUNT(*) = 1;
+----+--------------------+-------+------+---------------+------+---------+------+------+----------------------------------------------+
| id | select_type        | table | type | possible_keys | key  | key_len | ref  | rows | Extra                                        |
+----+--------------------+-------+------+---------------+------+---------+------+------+----------------------------------------------+
|  1 | PRIMARY            | dummy | ALL  | NULL          | NULL | NULL    | NULL |    6 | Using where; Using temporary; Using filesort |
|  2 | DEPENDENT SUBQUERY | dummy | ALL  | NULL          | NULL | NULL    | NULL |    6 | Using where; Using temporary; Using filesort |
+----+--------------------+-------+------+---------------+------+---------+------+------+----------------------------------------------+
2 rows in set (0.00 sec)

您会注意到您的查询在“额外”列中添加了“使用临时,使用filesort”。简而言之,这意味着效率较低,因为必须创建临时表,并且必须进行排序才能计算结果。您可以阅读this manpage了解更多信息。

答案 2 :(得分:1)

SELECT * FROM `dummy`
WHERE `pet` IN ('dog', 'cat')
GROUP BY `userId`
HAVING COUNT(DISTINCT `pet`) == 2

获取唯一身份用户列表 谁有狗或猫 但将其限制为至少有2个不同值pet的用户 这将是一只狗和一只猫,因为你将它限制在那两个选项

答案 3 :(得分:0)

第一个问题有几种解决方案,“至少有一只狗和一只猫的用户。”

  select * 
    from dummy
    where userId in (select userId from dummy where pet = 'dog')
     and  userId in (select userId from dummy where pet = 'cat');

使用相关子查询:

    select * 
    from dummy
    where exists (select 1 from dummy p where p.userId = d.userId and pet = 'dog')
     and  exists (select 1 from dummy p where p.userId = d.userId and pet = 'cat')

性能取决于优化器。它们可能都有相同的执行计划。

  select d.* 
    from dummy d
    join (select distinct userId, pet from dummy where pet = 'dog') as g
    using (userId)
    join (select distinct userId, pet from dummy where pet = 'cat') as c
    using (userId);

最后一个使用Oracle称之为“内联视图”的内容。其他数据库供应商有不同的名称。如果这些查询在mySql中不起作用,请告诉我。