1

誰でもMySQLIN句でこのロジックの背後にある説明をし、この問題を理解するのを手伝ってくれます

ユーザーテーブルがあり、このテーブルのユーザーは1つまたは複数のグループに属しています。グループテーブルの主キー参照は、次のようにカンマ(、)で区切られた値によってユーザーテーブルで更新されます

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句とグループID値を2として使用すると、1つの結果しか得られませんでした

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)として使用すると、3つの結果が得られました

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 |
+---------+-----------+-------------------------+-----------+

次の出力のようにグループID2ユーザーを取得したいのですが、期待どおりに機能していません

このクエリを使用する場合、クエリ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両方の主キーがあるため、重複を取得できず、これらの列はそれぞれのテーブルへの外部キーである必要があります。このテーブルを使用すると、各 user_id に対して複数のグループを持つことができます。user_idgroup_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

MySQLは、カンマ区切りのリストを単なる文字列以外のものとして扱いません。を実行するとWHERE group_id IN(2)、に変換group_idされるINTため、と比較でき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)

これを行う正しい方法は、ユーザーごとに1つ(または複数)の行を含む「リンクテーブル」を作成し、ユーザーがどのグループに属しているかを示すことです。

于 2013-03-14T15:04:27.683 に答える
2

1,2オペレーターに渡すときIN、あなたはとを求めてい1ます2; これが、3つの結果すべてを返す理由です。値がコンマで区切られた列がある場合は、通常の形式に違反しています。各列に複数の値を含めることはできません。複数値のコンマ区切り列で単一の値を検索する場合は、を使用できますFIND_IN_SET

正規化されたスキーマは次のようになります。

+ --------- + ----------- + ------------------------- +
| user_id | user_name | user_email |
+ --------- + ----------- + ------------------------- +
| 2 | サンダー| s7sundera@gmail.com |
| 3 | テスター| xxxxxxxx@yyyyyyyyyy.com |
| 4 | ゲイル| zzzzzz@gmail.com |
+ --------- + ----------- + ------------------------- +

+ --------- + ----------- +
| user_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 に答える
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>

OK、探してみ(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 に答える