1

任何人都可以在 MySQL IN 子句中解释这个逻辑并帮助我理解这个问题

我有一个用户表,这个表用户属于一个或多个组。组表主键引用在用户表中通过逗号(,)分隔值更新,如下所示

Query 1. SELECT * FROM user;
+---------+-----------+-------------------------+-----------+
| user_id | user_name | user_email              | group_id  |
+---------+-----------+-------------------------+-----------+
|       1 | suresh    | xxxx@yyyyyyyyyy.com     | 22        |
|       2 | sundar    | s7sundera@gmail.com     | 2         |
|       3 | tester    | xxxxxxxx@yyyyyyyyyy.com | 1,2,3,4   |
|       4 | gail      | zzzzzz@gmail.com        | 1,2,3,4,5 |
+---------+-----------+-------------------------+-----------+

如果我在 MySQL 中使用 IN 子句和 group id 值为 2 我只得到一个结果

Query 2. SELECT * FROM user WHERE group_id IN(2)
+---------+-----------+---------------------+----------+
| user_id | user_name | user_email          | group_id |
+---------+-----------+---------------------+----------+
|       2 | sundar    | s7sundera@gmail.com | 2        |
+---------+-----------+---------------------+----------+

如果我在 MySQL 中使用 IN 子句和组 id 值作为 (1,2) 我得到三个结果

Query 3. SELECT * FROM user WHERE group_id IN(1,2)
+---------+-----------+-------------------------+-----------+
| user_id | user_name | user_email              | group_id  |
+---------+-----------+-------------------------+-----------+
|       2 | sundar    | s7sundera@gmail.com     | 2         |
|       3 | tester    | xxxxxxxx@yyyyyyyyyy.com | 1,2,3,4   |
|       4 | gail      | zzzzzz@gmail.com        | 1,2,3,4,5 |
+---------+-----------+-------------------------+-----------+

我想获得像以下输出一样的组 id 2 用户,但它没有按预期工作

如果我使用此查询,我需要获得查询 3 结果,这可能吗?

SELECT * FROM user WHERE group_id IN(2)
4

4 回答 4

3

这太长了,不能作为评论,但您需要重新考虑您当前的表格设计。您不应该将group_id值存储为逗号分隔的列表。

您的表的结构应类似于以下内容:

create table user
(
    user_id int,  PK
    user_name varchar(50),
    user_email varchar(100)
);

create table groups
(
    group_id int, PK
    group_name varchar(10)
);

create table user_group
(
    user_id int,
    group_id int
);

user_group表将具有 theuser_id和 the的主键,group_id因此您无法获得重复项,然后这些列应该是各个表的外键。此表将允许您为每个 user_id 拥有多个组。

然后,当您查询表时,查询将是:

select u.user_id, 
  u.user_name,
  u.user_email,
  g.group_id
from user u
inner join user_group ug 
  on u.user_id = ug.user_id
inner join groups g
  on ug.group_id = g.group_id

请参阅SQL Fiddle with Demo

如果您需要出于显示目的group_id在逗号分隔列表中显示值,您可以使用GROUP_CONCAT()

select u.user_id, 
  u.user_name,
  u.user_email,
  group_concat(g.group_id order by g.group_id) group_id
from user u
inner join user_group ug 
  on u.user_id = ug.user_id
inner join groups g
  on ug.group_id = g.group_id
group by u.user_id, u.user_name, u.user_email

请参阅带有演示的 SQL Fiddle

如果你重新设计你的表格,那么当你搜索它会变得更容易:

select u.user_id, 
  u.user_name,
  u.user_email,
  g.group_id
from user u
inner join user_group ug 
  on u.user_id = ug.user_id
inner join groups g
  on ug.group_id = g.group_id
where g.group_id in (1, 2)

请参阅带有演示的 SQL Fiddle

于 2013-03-14T14:59:16.483 回答
2

传递1,2IN操作员时,您要求使用1and 2; 这就是为什么它将返回所有三个结果。如果您有一列以逗号分隔的值,则您违反了正常形式;因为每一列不应包含多个值。如果要在多值逗号分隔列中查找单个值,则可以使用FIND_IN_SET.

规范化的模式如下所示:

+---------+------------+--------------+
| 用户 ID | 用户名 | 用户邮箱 |
+---------+------------+--------------+
| 2 | 桑达尔| s7sundera@gmail.com |
| 3 | 测试仪 | xxxxxxxx@yyyyyyyyyy.com |
| 4 | 盖尔 | zzzzzz@gmail.com |
+---------+------------+--------------+

+---------+-----------+
| 用户 ID | group_id |
+---------+-----------+
| 2 | 2 |
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
| 3 | 4 |
| 4 | 1 |
| 4 | 2 |
| 4 | 3 |
| 4 | 4 |
| 4 | 5 |
+---------+-----------+

+----------+
| group_id |
+----------+
| 1 |
| 2 |
| 3 |
| 4 |
+----------+
于 2013-03-14T14:56:59.820 回答
2

MySQL 不会将逗号分隔的列表视为字符串以外的任何内容。当您这样做时WHERE group_id IN(2),它会转换group_idINT,因此可以将其与2.

当转换为 时INT,MySQL 在第一个非数字字符处停止。

例如,'1,2,3,4,5' IN (2)变成1 IN (2)。这是错误的。

你可以尝试用FIND_IN_SET它来做你想做的事,但效率不高(因为它不能使用索引;它需要读取每一行以查看是否匹配)。

WHERE FIND_IN_SET(2, group_id)

要搜索多行,请使用OR.

WHERE FIND_IN_SET(1, group_id) OR FIND_IN_SET(2, group_id)

正确的方法是创建一个“链接表”,其中包含每个用户的一个(或多个)行,显示他们所在的组。

于 2013-03-14T15:04:27.683 回答
1

解释

查询的逻辑是什么SELECT * FROM user WHERE group_id IN(1,2);

  • 你给了一个数字列表(1,2)
  • groud_id数字比较
  • 结果出现在第一个逗号之前在数字上匹配 1 或 2 的任何内容

建议

我将要向您展示的内容可能看起来很不正统,但请跟随我...

下面的查询将获取 group_ids 中同时包含 1 和 2 的每一行:

SELECT user.* FROM
(SELECT * FROM (SELECT id,CONCAT(',',group_id ,',') group_ids
FROM user) U WHERE LOCATE(',2,',group_ids)) U1
INNER JOIN
(SELECT * FROM (SELECT id,CONCAT(',',group_id ,',') group_ids
FROM user) U WHERE LOCATE(',4,',group_ids)) U2
ON U1.id = U2.id
INNER JOIN user ON user.id = U2.id;

这是创建我们的示例数据的代码

DROP DATABASE IF EXISTS sundar;
CREATE DATABASE sundar;
use sundar
CREATE TABLE user
(
    id int not null auto_increment,
    user_name VARCHAR(30),
    user_email VARCHAR(70),
    group_id VARCHAR(128),
    PRIMARY KEY (id)
);
INSERT INTO user (user_name,user_email,group_id) VALUES
('suresh' , 'xxxx@yyyyyyyyyy.com'     ,'22'),
('sundar' , 's7sundera@gmail.com'     ,'2'),
('tester' , 'xxxxxxxx@yyyyyyyyyy.com' ,'1,2,3,4'),
('gail'   , 'zzzzzz@gmail.com'        ,'1,2,3,4,5');
SELECT * FROM user;

让我们创建您的示例

mysql> DROP DATABASE IF EXISTS sundar;
Query OK, 1 row affected (0.00 sec)

mysql> CREATE DATABASE sundar;
Query OK, 1 row affected (0.00 sec)

mysql> use sundar
Database changed
mysql> CREATE TABLE user
    -> (
    ->     id int not null auto_increment,
    ->     user_name VARCHAR(30),
    ->     user_email VARCHAR(70),
    ->     group_id VARCHAR(128),
    ->     PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.04 sec)

mysql> INSERT INTO user (user_name,user_email,group_id) VALUES
    -> ('suresh' , 'xxxx@yyyyyyyyyy.com'     ,'22'),
    -> ('sundar' , 's7sundera@gmail.com'     ,'2'),
    -> ('tester' , 'xxxxxxxx@yyyyyyyyyy.com' ,'1,2,3,4'),
    -> ('gail'   , 'zzzzzz@gmail.com'        ,'1,2,3,4,5');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql>

这就是它的样子

mysql> SELECT * FROM user;
+----+-----------+-------------------------+-----------+
| id | user_name | user_email              | group_id  |
+----+-----------+-------------------------+-----------+
|  1 | suresh    | xxxx@yyyyyyyyyy.com     | 22        |
|  2 | sundar    | s7sundera@gmail.com     | 2         |
|  3 | tester    | xxxxxxxx@yyyyyyyyyy.com | 1,2,3,4   |
|  4 | gail      | zzzzzz@gmail.com        | 1,2,3,4,5 |
+----+-----------+-------------------------+-----------+
4 rows in set (0.00 sec)

mysql>

同样,这里是一个凌乱的查询,可以得到你想要的:

SELECT user.* FROM
(SELECT * FROM (SELECT id,CONCAT(',',group_id ,',') group_ids
FROM user) U WHERE LOCATE(',1,',group_ids)) U1
INNER JOIN
(SELECT * FROM (SELECT id,CONCAT(',',group_id ,',') group_ids
FROM user) U WHERE LOCATE(',2,',group_ids)) U2
ON U1.id = U2.id
INNER JOIN user ON user.id = U2.id;

在这里执行:

mysql> SELECT user.* FROM
    -> (SELECT * FROM (SELECT id,CONCAT(',',group_id ,',') group_ids
    -> FROM user) U WHERE LOCATE(',1,',group_ids)) U1
    -> INNER JOIN
    -> (SELECT * FROM (SELECT id,CONCAT(',',group_id ,',') group_ids
    -> FROM user) U WHERE LOCATE(',2,',group_ids)) U2
    -> ON U1.id = U2.id
    -> INNER JOIN user ON user.id = U2.id;
+----+-----------+-------------------------+-----------+
| id | user_name | user_email              | group_id  |
+----+-----------+-------------------------+-----------+
|  3 | tester    | xxxxxxxx@yyyyyyyyyy.com | 1,2,3,4   |
|  4 | gail      | zzzzzz@gmail.com        | 1,2,3,4,5 |
+----+-----------+-------------------------+-----------+
2 rows in set (0.00 sec)

mysql>

好的,要不要找(2,4)

mysql> SELECT user.* FROM
    -> (SELECT * FROM (SELECT id,CONCAT(',',group_id ,',') group_ids
    -> FROM user) U WHERE LOCATE(',2,',group_ids)) U1
    -> INNER JOIN
    -> (SELECT * FROM (SELECT id,CONCAT(',',group_id ,',') group_ids
    -> FROM user) U WHERE LOCATE(',4,',group_ids)) U2
    -> ON U1.id = U2.id
    -> INNER JOIN user ON user.id = U2.id;
+----+-----------+-------------------------+-----------+
| id | user_name | user_email              | group_id  |
+----+-----------+-------------------------+-----------+
|  3 | tester    | xxxxxxxx@yyyyyyyyyy.com | 1,2,3,4   |
|  4 | gail      | zzzzzz@gmail.com        | 1,2,3,4,5 |
+----+-----------+-------------------------+-----------+
2 rows in set (0.00 sec)

mysql>

看起来它有效。

试试看 !!!

于 2013-03-14T16:10:48.807 回答