3

私はSQLが初めてで、この問題を自分で解決しようとしましたが、成功しませんでした...誰かが助けてくれることを願っています。

私は3つのテーブルを持っています:

認証ユーザー

+--------------+--------------+------+-----+---------+----------------+
| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| id           | int(11)      | NO   | PRI | NULL    | auto_increment |
| username     | varchar(30)  | NO   | UNI | NULL    |                |
| first_name   | varchar(30)  | NO   |     | NULL    |                |
| last_name    | varchar(30)  | NO   |     | NULL    |                |
| email        | varchar(75)  | NO   |     | NULL    |                |
| password     | varchar(128) | NO   |     | NULL    |                |
| is_staff     | tinyint(1)   | NO   |     | NULL    |                |
| is_active    | tinyint(1)   | NO   |     | NULL    |                |
| is_superuser | tinyint(1)   | NO   |     | NULL    |                |
| last_login   | datetime     | NO   |     | NULL    |                |
| date_joined  | datetime     | NO   |     | NULL    |                |
+--------------+--------------+------+-----+---------+----------------+

catalog_presents

+-------------+----------------------+------+-----+---------+----------------+
| Field       | Type                 | Null | Key | Default | Extra          |
+-------------+----------------------+------+-----+---------+----------------+
| id          | int(11)              | NO   | PRI | NULL    | auto_increment |
| name        | varchar(48)          | NO   |     | NULL    |                |
| slug        | varchar(50)          | NO   | UNI | NULL    |                |
| amount      | smallint(5) unsigned | NO   |     | 0       |                |
| points      | smallint(5) unsigned | NO   |     | 500     |                |
| created_at  | datetime             | NO   |     | NULL    |                |
| updated_at  | datetime             | NO   |     | NULL    |                |
| active      | tinyint(1)           | NO   |     | NULL    |                |
| image       | varchar(100)         | YES  |     | NULL    |                |
| description | longtext             | YES  |     | NULL    |                |
+-------------+----------------------+------+-----+---------+----------------+

カタログ注文

+------------+----------------------+------+-----+---------+----------------+
| Field      | Type                 | Null | Key | Default | Extra          |
+------------+----------------------+------+-----+---------+----------------+
| id         | int(11)              | NO   | PRI | NULL    | auto_increment |
| user_id    | int(11)              | NO   | MUL | NULL    |                |
| status     | smallint(5) unsigned | NO   |     | 0       |                |
| present_id | int(11)              | NO   | MUL | NULL    |                |
| address_id | int(11)              | NO   | MUL | NULL    |                |
| created_at | datetime             | NO   |     | NULL    |                |
| updated_at | datetime             | NO   |     | NULL    |                |
+------------+----------------------+------+-----+---------+----------------+

私はユーザーを選択し、彼が特定のプレゼントを注文したかどうかを確認し、それに応じて行に書き込み、別のものをチェックし、別のものなどをチェックしようとしています。

基本的に、結果は次のようになります。

id present1 present2 present3 present4
1 1 0 0
2 1 1 1
3 0 0 0
4 1 0 1

ここで、1 はユーザーがその種類のプレゼントを注文したことを示し、0 は注文しなかったことを示します。

私のクエリは次のようになります

select auth_user.id, case when present_id = 1 from auth_user 
left join catalog_orders on catalog_orders.user_id = auth_user.id 
left join catalog_presents on catalog_presents.id = catalog_orders.present_id

問題は、ユーザーによるすべての異なる注文が、次のように複数の行に並べ替えられることです。

id present1 present2 present3 present4
1 1 0 0
2 1 0 0
2 0 1 0
2 0 0 1
3 0 0 0
4 1 0 0
4 0 0 1

誰かがこれを解決するのを手伝ってもらえますか? 前もって感謝します!

4

1 に答える 1

1

これはピボットテーブルの一種です。

あなたは正しい道を進んでいますが、結果をユーザーごとに 1 行にまとめる必要があります。

集約MAX()perauth_user.idを使用して、それらを単一の行に折りたたみます。はCASE各プレゼントに 0 または 1 を提供し、MAX()は のすべての行の最大値を選択します。auth_user.idこれは1、プレゼントが購入された場合と0そうでない場合です。

SELECT
  auth_user.id,
  MAX(CASE WHEN present_id = 1 THEN 1 ELSE 0 END) AS present1,
  MAX(CASE WHEN present_id = 2 THEN 1 ELSE 0 END) AS present2,
  MAX(CASE WHEN present_id = 3 THEN 1 ELSE 0 END) AS present3,
  MAX(CASE WHEN present_id = 4 THEN 1 ELSE 0 END) AS present4
FROM
   auth_user
   LEFT JOIN catalog_orders on catalog_orders.user_id = auth_user.id 
   LEFT JOIN catalog_presents on catalog_presents.id = catalog_orders.present_id
GROUP BY auth_user.id
ORDER BY auth_user.id

CASE特にMySQLの場合、ブール比較present_id = 1はそれ自体で1または0を返すため、は必要ありません。ただし、これは他のすべての RDBMS に移植できるわけではありません。上記の方法が望ましいです。

SELECT
  auth_user.id,
  /* MySQL ok, not all other RDBMS will do this - boolean comparison returns 1 or 0 */
  MAX(present_id = 1) AS present1,
  MAX(present_id = 2) AS present2,
  MAX(present_id = 3) AS present3,
  MAX(present_id = 4) AS present4
FROM
   auth_user
   LEFT JOIN catalog_orders on catalog_orders.user_id = auth_user.id 
   LEFT JOIN catalog_presents on catalog_presents.id = catalog_orders.present_id
GROUP BY auth_user.id
ORDER BY auth_user.id
于 2012-11-17T20:42:47.050 に答える