web-dev-qa-db-ja.com

MySQL Selectステートメント、WHERE'IN '句

現在、テーブルに次の行があります。

         course_data:
             user_id        days     <-- This is a varchar column.
               405          1,3,5

そして、私は次のSELECTステートメントを実装しようとしています。

SELECT usrID, usrFirst, usrLast, usrEmail
    FROM tblUsers
    WHERE usrID NOT IN
    (
        SELECT users.usrID
            FROM
                `course_data` courses,
                `tblUsers` users
            WHERE
                days IN ('$day')
    )
    GROUP BY usrID
    ORDER BY usrID

基本的に、$ day変数に「1、3、または5」が含まれている場合は、その行(ユーザー405)を省略します。

たとえば、$day = "1"の場合、空のクエリを返す必要があります(数値「1」が列「1,3,5」にあるため)。

しかし、私はこれが事実であるとは思いませんでした。 $day = "1"であっても、その行を返します。

行を返さない唯一の方法は、$day= "1,3,5."の場合です。それでも、IN()句は変数の任意の部分を取り、それをその列に適用すると思いました。

私がここで間違っていることについての洞察はありますか?ありがとう。

7
Dodinas

Charフィールドの部分一致を行うには、 likeキーワード を使用する必要があります。

where days like '%1%'

編集:VolkerKとLukasLalinskyはどちらもMySQLのfind_in_set、これはおそらくlikeよりもやりたいことの方が良いでしょう。ただし、データベースの正規化に関する次の推奨事項は引き続き適用されます。

ただし、単一のデータベースフィールドに複数の値を格納しないでください。代わりに、次の2つのテーブルの使用を検討してください。

course_data:
    user_id

course_days:
    user_id
    day_number

次に、次のデータがあります。

course_data:
    user_id
    405

course_days
    user_id    day_number
    405        1
    405        3
    405        5

その後、このスキーマを正しくクエリできます。例えば:

select  cd.user_id
from    course_data as cd
where   cd.user_id not in
    (
        select  course_days.user_id
        from    course_days
        where   course_days.user_id = cd.user_id
            and course_days.day_number = 1
    )

(または、それは近いはずです。私はあなたが何を達成しようとしているのか、またはスキーマの残りの部分がどのように見えるのか正確にわからないので、これは最良の推測です) 。

11
James McNellis

INステートメントの引用符を削除します。構文は次のとおりです。

... WHERE column IN (1,2,3) 

あなたがそれを使ったようにではなく

... WHERE column IN ('1,2,3')

INの documentation も参照してください。他にも例があります。

13
theomega

私はあなたが望むクエリは次のとおりだと思います:

SELECT usrID, usrFirst, usrLast, usrEmail
FROM tblUsers
WHERE usrID NOT IN (
    SELECT user_id 
    FROM course_data
    WHERE find_in_set(?, days) > 0
)
ORDER BY usrID

ただし、データベースを正規化して、毎日独自の行を持つようにすることを真剣に検討する必要があります。

5

私があなたの質問を正しく理解している場合は、varcharフィールドの内容をコンマ区切りのリストとして扱い、このリストに特定の値が含まれていないかどうかをテストする必要があります。そのためには find_in_set(str、strlist) 関数が必要です。
ただし、その場合、MySQLはインデックスを使用できず、クエリでは常に全表スキャンが必要になることに注意してください。それ かもしれない 構造化データを単一の列に格納する(および単一の要素で比較を実行する)のではなく、他の応答で提案されているように別のテーブルとJOINを使用することをお勧めします。

2
VolkerK

daysは文字列のリストを保持しません。単一の文字列を保持します。文字列「1,3,5」は{'1'}の文字列の1つに含まれていますか?明らかに答えはノーです。日を別のテーブルにリファクタリングするか、より多くの文字列操作を行う準備をしてください

0
Yuliy