1

私たちのデータベースには、ユーザー テーブルと、他のデータ用のキー値テーブルがあります。kv テーブルのキーを列見出しとして、値をフィールドとして取得して、2 つを結合するクエリを考え出そうとしています。

現時点での唯一の解決策はGROUP_CONCAT、各ユーザーのキーと値のペアを列として、クエリが出力された後にそれらを解析することです。遅くて悪いです...

一般的な設定は次のとおりです。

User.db テーブル:

------------------------------
| uid | firstname | lastname |
------------------------------
| 01 | john       | doe      |
| 02 | jane       | doe      |
------------------------------

-----------------------------
| uid | question  |  answer |
-----------------------------
|  01 | question1 | answer1 |
|  01 | question2 | answer2 |
|  02 | question1 | answer3 |
|  02 | question2 | answer4 |
-----------------------------

取得したいクエリ結果:

------------------------------------------------------
| uid | firstname | lastname | question1 | question2 |
------------------------------------------------------
|  01 | john      | doe      | answer1   | answer2   |
|  02 | jane      | doe      | answer3   | answer4   |
------------------------------------------------------

これを行う簡単な方法があることを願っていますが、何も見つけることができませんでした。すべてのヘルプは大歓迎です。

4

3 に答える 3

4

他のデータベースでは関数を使用できますPIVOTが、MySQL にはその関数がないため、集計関数とCASEステートメントを使用して複製する必要があります。すべての値がわかっている場合は、次のように値をハードコーディングできます。

select u.uid, u.firstname, u.lastname,
  max(case when question='question1' then answer else null end) as question1,
  max(case when question='question2' then answer else null end) as question2
from users u 
left join kv 
  on u.uid = kv.uid
group by u.uid, u.firstname, u.lastname;

デモで SQL Fiddle を参照してください

ただし、不明な値がある場合は、準備済みステートメントを使用して動的 SQL を生成できます。

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(case when question = ''',
      question,
      ''' then answer else NULL end) AS ',
      question
    )
  ) INTO @sql
FROM kv;

SET @sql = CONCAT('SELECT u.uid, u.firstname, u.lastname, ', @sql, ' 
                  from users u 
                  left join kv 
                    on u.uid = kv.uid 
                  group by u.uid, u.firstname, u.lastname');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

デモで SQL Fiddle を参照してください

どちらのバージョンでも同じ結果が生成されます。

| UID | FIRSTNAME | LASTNAME | QUESTION1 | QUESTION2 |
------------------------------------------------------
|   1 |      john |      doe |   answer1 |   answer2 |
|   2 |      jane |      doe |   answer3 |   answer4 |

準備されたステートメントの利点は、値が変更されている場合、実行時に列のリストが生成されることです。

于 2012-11-09T21:18:02.583 に答える
1

これは、ピボットテーブルをシミュレートします。

Select
  uid,
  firstname,
  lastname,
  max(case when question = 'question1' then answer end) as question1,
  max(case when question = 'question2' then answer end) as question2
From
  users inner join answers on users.uid = answers.uid
Grop by uid, firstname, lastname

結合を使用したソリューションもあります。

Select uid, firstname, lastname,
  answers_1.answer as question1,
  answers_2.answer as question2
From
  users left join answers answers_1
  on users.uid = answers_1.uid and answers_1.question = 'question1'
  left join answers answers_2
  on users.uid = answers_2.uid and answers_2.question = 'question2'

もちろん、質問が何であるかを事前に知っておく必要があります。そうでない場合、私が知る限り、MySqlはPIVOTをサポートしていないため、標準のSQLだけを使用して質問に答える方法はありません。

于 2012-11-09T20:11:19.747 に答える
1

あなたはそのようなことを試すことができます:

select u.uid, u.firstname, u.lastname,
  max(case when question="question1" then answer else null) as question1,
  max(case when question="question2" then answer else null) as question2
from user u join answers a on u.uid = a.uid
group by u.uid, u.firstname, u.lastname
于 2012-11-09T20:14:14.527 に答える