3

次の表があります。

UID | ID  | Type
1   | 1   | product
1   | 2   | product
1   | 3   | service
1   | 4   | product
1   | 5   | product
2   | 6   | service
1   | 7   | order
2   | 8   | invoice
2   | 9   | product

私は最終的にしたい:

UID | product | service | invoice | order
1   |  4      |  1      |  0      |  1
2   |  1      |  1      |  1      |  0

SQL クエリはどのようになりますか? または、少なくとも、最も十分なものですか?

4

5 に答える 5

7

これら 4 つのタイプのみが本当に必要な場合は、次のように値をハードコーディングできます。

select UID,
    count(case when type='product' then 1 else null end) as product,
    count(case when type='service' then 1 else null end) as service,
    count(case when type='invoice' then 1 else null end) as invoice,
    count(case when type='order' then 1 else null end) as order
from MyTable
group by UID
order by UID    
于 2009-09-26T20:42:12.553 に答える
7

やりたいことは、SQL 構文では直接サポートされていないピボット操作です。ただし、それほど複雑ではなく、概念的には次の 2 つの手順が含まれます。

  1. 元のデータ セットの行ごとに 1 つの行で、データを多くの列に "爆破" します。これは通常、CASE WHEN ... ELSE ... END で行われるか、場合によっては関数 (Oracle の decode() など) で行われます。以下の例では CASE WHEN を使用します。これは、ほとんどの RDBMS で同様に機能するためです。
  2. GROUP BY と集計関数 (SUM、MIN、MAX など) を使用して、多数の行を必要な出力行セットにまとめます。

例として、次のデータセットを使用しています。

mysql> select * from foo;
+------+------+---------+
| uid  | id   | type    |
+------+------+---------+
|    1 |    1 | product | 
|    1 |    2 | product | 
|    1 |    3 | service | 
|    1 |    4 | product | 
|    1 |    5 | product | 
|    2 |    6 | service | 
|    1 |    7 | order   | 
|    2 |    8 | invoice | 
|    2 |    9 | product | 
+------+------+---------+

ステップ 1 は、データ セットを「爆破」することです。

select uid
     , case when type = 'product' then 1 else 0 end as is_product
     , case when type = 'service' then 1 else 0 end as is_service
     , case when type = 'invoice' then 1 else 0 end as is_invoice
     , case when type = 'order' then 1 else 0 end as is_order
  from foo;

与える:

+------+------------+------------+------------+----------+
| uid  | is_product | is_service | is_invoice | is_order |
+------+------------+------------+------------+----------+
|    1 |          1 |          0 |          0 |        0 | 
|    1 |          1 |          0 |          0 |        0 | 
|    1 |          0 |          1 |          0 |        0 | 
|    1 |          1 |          0 |          0 |        0 | 
|    1 |          1 |          0 |          0 |        0 | 
|    2 |          0 |          1 |          0 |        0 | 
|    1 |          0 |          0 |          0 |        1 | 
|    2 |          0 |          0 |          1 |        0 | 
|    2 |          1 |          0 |          0 |        0 | 
+------+------------+------------+------------+----------+

次に、日付ごとに出力を 1 行にまとめ、インライン ビュー (別名「サブクエリ」) として初期クエリを使用して、各 is_* 列を合計します。

select uid
     , sum(is_product) as count_product
     , sum(is_service) as count_service
     , sum(is_invoice) as count_invoice
     , sum(is_order)   as count_order
  from (
         select uid
              , case when type = 'product' then 1 else 0 end as is_product
              , case when type = 'service' then 1 else 0 end as is_service
              , case when type = 'invoice' then 1 else 0 end as is_invoice
              , case when type = 'order' then 1 else 0 end as is_order
           from foo
       ) x
 group by uid;

(ここではわかりやすくするために別々に示していますが、これら 2 つのクエリを 1 つにまとめることができることにも注意してください。少なくとも MySQL では、これにより実行プランが単純になり、多くの場合、実行が高速になります。いつものように、テスト現実的なデータ セットでの SQL パフォーマンス、私の言葉を鵜呑みにしないでください!)

これにより、次のことがわかります。

+------+---------------+---------------+---------------+-------------+
| uid  | count_product | count_service | count_invoice | count_order |
+------+---------------+---------------+---------------+-------------+
|    1 |             4 |             1 |             0 |           1 | 
|    2 |             1 |             1 |             1 |           0 | 
+------+---------------+---------------+---------------+-------------+

これは望ましい結果です。

于 2009-09-26T20:47:13.470 に答える
2

MySQL でCASE ステートメントを使用して、行データを列に変換する (またはその逆) 必要があります。

  SELECT t.uid,
         SUM(CASE WHEN t.type = 'product' THEN COUNT(*) END) as PRODUCT,
         SUM(CASE WHEN t.type = 'service' THEN COUNT(*) END) as SERVICE,
         SUM(CASE WHEN t.type = 'invoice' THEN COUNT(*) END) as INVOICE,
         SUM(CASE WHEN t.type = 'order' THEN COUNT(*) END) as ORDER
    FROM TABLE t
GROUP BY t.uid, t.type
于 2009-09-26T20:44:09.913 に答える
1

「ピボット テーブル」と呼ばれるものを探していますが、これは MySQL がネイティブに実行できるものではありません。

この場合、アプリケーションでデータを変換し、GROUP BY や DISTINCT を組み合わせて使用​​して、探しているデータを収集するのがおそらく最善の方法です。このクエリは機能する可能性がありますが、テストしていません。

SELECT Type, COUNT(ID), UID
  FROM tablename
 GROUP BY UID, Type
于 2009-09-26T20:38:01.673 に答える
-3

mytable からカウント (製品、サービス、請求書、注文) を選択します

于 2009-09-26T20:34:22.553 に答える