2

ユーザーのリストを作成しています。特定のフィールド (メールに一致、メールと種類に一致、名前と種類に一致、またはそれらすべてに一致) に一致するユーザー (およびアイテム) を返したいと考えています。重複ユーザーを減らしたいので、メールとタイプが一致する場合はメールを返さないでください。

サンプルデータ:

+----+---------------------+--------+---------+
| id | email               | type   | name    |
+----+---------------------+--------+---------+
| 1  | rod@example.com     | user   | Rod     |
| 2  | jane@example.com    | user   | Jane    |
| 3  | rod2@example.com    | user   | Rod     |
| 4  | rod3@example.com    | admin  | Rod     |
| 5  | helen@example.com   | admin  | helen   |
+----+---------------------+--------+---------+

$email = 'rod@example.com', $type = 'user', $name = 'Rod' の場合、次の結果を返したいと思います。以下のものを返品したいです。

+----------------+----+
| matches        | id |
+----------------+----+
| 3 (all)        | 1  |
| 2 (name, type) | 3  |
| 1 (name)       | 4  |
+----------------+----+

私は、各マッチ セットに対して個別の SQL クエリを考えていました。メール用に 1 つ、メールとタイプ用に 1 つ、名前とタイプ用に 1 つ、すべてに 1 つです。最後に、php を使用して結果をフィルタリングします。

$users = array();

// match email
$sql = 'SELECT u.*, GROUP_CONCAT(i.name) as items
        FROM users u
        INNER JOIN items i
            ON u.id = i.user_id
        WHERE u.email = '.$email.'
        GROUP BY u.id';
$users[] = mysqli_query($sql);

// match email & type
$sql = 'SELECT u.*, GROUP_CONCAT(i.name) as items
        FROM users u
        INNER JOIN items i
            ON u.id = i.user_id
        WHERE u.email = '.$email.' AND u.type = '.$type.'
        GROUP BY u.id';
$users[] = mysqli_query($sql);

// match name & type
$sql = 'SELECT u.*, GROUP_CONCAT(i.name) as items
        FROM users u
        INNER JOIN items i
            ON u.id = i.user_id
        WHERE u.name = '.$name.' AND u.type = '.$type.'
        GROUP BY u.id';
$users[] = mysqli_query($sql);

// match email, name & type
$sql = 'SELECT u.*, GROUP_CONCAT(i.name) as items
        FROM users u
        INNER JOIN items i
            ON u.id = i.user_id
        WHERE u.email = '.$email.' AND u.name = '.$name.' AND u.type = '.$type.'
        GROUP BY u.id';
$users[] = mysqli_query($sql);

それらを置き換えるために1つのクエリを作成し、phpを使用したフィルタリングを回避する方法が必要だと思います。誰でも提案できますか?

4

3 に答える 3

1

私はこれに行きます:

SELECT id,
  email = 'rod@example.com' EmailMatch,
  type = 'user' TypeMatch,
  name = 'Rod' NameMatch
FROM t
HAVING EmailMatch + TypeMatch + NameMatch > 0
ORDER BY EmailMatch + TypeMatch + NameMatch DESC

出力:

| ID | EMAILMATCH | TYPEMATCH | NAMEMATCH |
|----|------------|-----------|-----------|
|  1 |          1 |         1 |         1 |
|  3 |          0 |         1 |         1 |
|  2 |          0 |         1 |         0 |
|  4 |          0 |         0 |         1 |

ここでフィドル。

テーブル内の実際のフィールドを変更idして、同じクエリから直接データを取得するため、後で結合することを避けることもできます。

行ごとの合計一致数を実際に確認する必要がある場合は、すべての条件を複製して追加する別の行を追加するか、別の select ステートメントでクエリをラップすることができます。どちらの方法も読みにくいか、非効率的です。したがって、行ごとの一致数を確認する必要がある場合は、PHP に一致列を追加することをお勧めします。

于 2013-09-06T17:27:44.273 に答える
0

私は CASE WHEN でそれを実行します (構文が 100% 正しくない場合は申し訳ありません)。

$sql = 'SELECT u.id, 
  CASE WHEN (u.name = ' .$name. ' AND u.type = '.$type.' AND u.email = '.$email.') THEN "3 (all)"
    ELSE WHEN (u.name = ' .$name. ' AND u.type = '.$type.') THEN "2 (name, type)"
    ELSE WHEN (u.name = ' .$name. ' AND u.emal = '.$email.') THEN "2 (name, email)"
    ELSE WHEN (u.type = ' .$type. ' AND u.email = '.$email.') THEN "2 (email,type)"
    ELSE WHEN (u.name = ' .$name. ') THEN "1 (name)"
    ELSE WHEN (u.type = ' .$type. ') THEN "1 (type)"
    ELSE WHEN (u.email = ' .$email. ') THEN "1 (email)"
    ELSE "0" END AS matches
  FROM users u
  HAVING matches != "0"';
于 2013-09-06T17:23:06.470 に答える