MySQL/MariaDB でピボット テーブルを実装する方法のサンプル コード

MySQL/MariaDB でピボット テーブルを実装する方法のサンプル コード

前回の記事では、Oracle でピボット テーブルを実装するいくつかの方法を紹介しました。今日は、同じ機能を MySQL/MariaDB で実装する方法を見てみましょう。

この記事で使用されているサンプルデータは、ここからダウンロードできます。

CASE式とグループ化集計の使用

ピボット テーブルの本質は、行と列のさまざまな組み合わせに従ってデータをグループ化し、結果を要約することです。したがって、データベースのグループ化 (GROUP BY) と集計関数 (COUNT、SUM、AVG など) の機能に非常に似ています。

まず、次の GROUP BY 句を使用して売上データを集計します。

select coalesce(product, '【全商品】') "商品",
    coalesce(channel, '【全チャンネル】') "チャンネル",
    any_value(coalesce(extract(year_month from saledate), '【全月】')) "月",
    合計(金額)「売上高」
販売データから
製品、チャネル別にグループ化し、(saledate から year_month を抽出して) ロールアップします。

上記のステートメントは、製品、チャネル、月ごとに集計します。with rollup オプションを使用して、さまざまなレベルで小計、合計、総計を生成します。coalesce 関数を使用して、集計行の NULL 値を対応する情報として表示します。any_value 関数は、グループ内の任意のデータを返すために使用されます。削除すると、構文エラーが返されます (MySQL のバグ)。クエリは次の結果を返します。

製品 | チャネル | 月 | 販売量 |
---------|----------|----------|-------|
オレンジ |JD |201901 | 41289|
オレンジ |JD |201902 |43913|
オレンジ |JD |201903 | 49803|
オレンジ |JD.com |201904 | 49256|
オレンジ |JD.com |201905 | 64889|
オレンジ |JD |201906 |62649|
オレンジ |JD.com |【全月】| 311799|
オレンジ |ストア |201901 | 41306|
オレンジ |ストア |201902 | 37906|
オレンジ |ストア |201903 | 48866|
オレンジ |ストア |201904 | 48673|
オレンジ |ストア |201905 | 58998|
オレンジ |ストア |201906 | 58931|
オレンジ |ストア |【全月】| 294680|
オレンジ | 淘宝網 | 201901 | 43488|
オレンジ | 淘宝網 | 201902 | 37598|
オレンジ | 淘宝網 | 201903 | 48621|
オレンジ | 淘宝網 | 201904 | 49919|
オレンジ | タオバオ | 201905 | 58530|
オレンジ | 淘宝網 | 201906 | 64626|
オレンジ | タオバオ | 【全月】| 302782|
オレンジ |【全チャンネル】|【全月】| 909261|
...
バナナ |【全チャンネル】|【全月】| 925369|
【全商品】|【全チャンネル】|【全月】|2771682|

実際には、売上の集計結果はすでに取得していますが、月ごとに異なる列にデータを表示する必要があります。つまり、行を列に変換する必要があります。この機能は、CASE 式を使用して実現できます。

select coalesce(product, '【全商品】') "商品", coalesce(channel, '【全チャンネル】') "チャンネル", 
    sum(case extract(year_month from saledate) when 201901 then amount else 0 end) "1月",
    sum(case extract(year_month from saledate) when 201902 then amount else 0 end) "2月",
    sum(case extract(year_month from saledate) when 201903 then amount else 0 end) "三月",
    sum(case extract(year_month from saledate) when 201904 then amount else 0 end) "4月",
    sum(case extract(year_month from saledate) when 201905 then amount else 0 end) "5月",
    sum(case extract(year_month from saledate) when 201906 then amount else 0 end) "六月",
    合計(金額)「合計」
販売データから
製品、ロールアップによるチャネル別にグループ化します。

最初の SUM 関数の CASE 式では、2019 年 1 月の売上のみを集計し、他の月の売上は 0 に設定します。後続の SUM 関数も同様で、各月の売上集計と全月の合計が取得されます。このクエリによって返されるピボットテーブルは次のとおりです。

製品 | チャネル | 1月 | 2月 | 3月 | 4月 | 5月 | 6月 | 合計 |
----------|----------|------|------|------|------|------|------|------|
オレンジ |JD.com | 41289| 43913| 49803| 49256| 64889| 62649| 311799|
オレンジ |ストア| 41306| 37906| 48866| 48673| 58998| 58931| 294680|
オレンジ | タオバオ | 43488| 37598| 48621| 49919| 58530| 64626| 302782|
オレンジ |【全チャンネル】|126083|119417|147290|147848|182417|186206| 909261|
アップル |JD.com | 38269| 40593| 56552| 56662| 64493| 62045| 318614|
Apple |ストア| 43845| 40539| 44909| 55646| 56771| 64933| 306643|
アップル | タオバオ | 42969| 43289| 48769| 58052| 58872| 59844| 311795|
Apple |【全チャンネル】|125083|124421|150230|170360|180136|186822| 937052|
バナナ |JD.com | 36879| 36981| 51748| 54801| 64936| 60688| 306033|
バナナ |ストア| 41210| 39420| 50884| 52085| 60249| 67597| 311445|
バナナ | 淘宝 | 42468| 41955| 52780| 54971| 56504| 59213| 307891|
バナナ |【全チャンネル】|120557|118356|155412|161857|181689|187498| 925369|
【全商品】|【全チャンネル】|371723|362194|452932|480065|544242|560526|2771682|

MySQL の IF(expr1, expr2, expr3) 関数を使用して、上記の CASE 式を置き換えることもできます。

行が列に変換され、列が行に変換される場合もあります。MySQL には、この状況を処理する特別な関数はありません。UNION 演算子を使用して、複数の結果セットを結合できます。例えば:

dを(
 製品、チャネルを選択、
     sum(case extract(year_month from saledate) when 201901 then amount else 0 end) s01,
     sum(case extract(year_month from saledate) when 201902 then amount else 0 end) s02,
     sum(case extract(year_month from saledate) when 201903 then amount else 0 end) s03,
     sum(case extract(year_month from saledate) when 201904 then amount else 0 end) s04,
     sum(case extract(year_month from saledate) when 201905 then amount else 0 end) s05,
     sum(case extract(year_month from saledate) when 201906 then amount else 0 end) s06
 販売データから
 製品、チャネル別にグループ化
)
製品、チャネル、201901 販売日、s01 金額を d から選択
すべて結合
製品、チャネル、201902 販売日、s02 を d から選択
すべて結合
製品、チャネル、201903 販売日、s03 を d から選択
すべて結合
製品、チャネル、201904 販売日、s04 を d から選択
すべて結合
製品、チャネル、201905 販売日、s05 を d から選択
すべて結合
d から製品、チャネル、201906 販売日、s06 を選択します。

共通テーブル式 (with 句) は、各月を列として複数の月の販売データを構築します。各クエリは 1 か月のデータを返し、すべての結果は union all 演算子を使用して結合されます。

プリコンパイルされた動的SQL文の使用

CASE 式と集計関数を使用してピボット テーブルを実装する方法には、一定の制限があります。7 月から 12 月までの売上をカウントする必要がある場合は、クエリ ステートメントを変更して、この処理部分を追加する必要があります。この目的のために、動的 SQL を使用して行と列の変換のステートメントを自動的に生成できます。

グループ連結を選択(
 個別の連結(
  ' sum(case extract(year_month from saledate) when ', dt,
  ' then amount else 0 end) as "', dt, '"')
 ) を @sql に
から (
 select extract(year_month from saledate) as dt
 販売データから
 発売日順に並べる
)d;

@sql を設定する
 = concat('select coalesce(product, ''【全商品】'') "商品", coalesce(channel, ''【全チャネル】'') "チャネル",', @sql,
      '、合計(金額)「合計」
      販売データから
      製品、ロールアップによるチャネル別にグループ化します。');
@sql を選択します。
@sql から stmt を準備します。
ステートメントを実行します。
準備ステートメントの割り当てを解除します。

まず、sales_data テーブルをクエリしてすべての月を調べ、合計関数を構築し、構築したステートメントを変数 @sql に格納します。group_concat 関数を使用すると、複数行の文字列を 1 つの文字列に結合できます。

group_concat 関数によって返される最大長 (バイト単位) は、システム変数 group_concat_max_len によって設定され、デフォルト値は 1024 です。

次に、set コマンドを使用して、クエリ ステートメントの残りの部分を既存のコンテンツとマージします。生成されたクエリ ステートメントは次のようになります。

select coalesce(product, '【全商品】') "商品", coalesce(channel, '【全チャンネル】') "チャンネル", 
    sum(case extract(year_month from saledate) when 201901 then amount else 0 end) as "201901", 
    sum(case extract(year_month from saledate) when 201902 then amount else 0 end) as "201902", 
    sum(case extract(year_month from saledate) when 201903 then amount else 0 end) as "201903", 
    sum(case extract(year_month from saledate) when 201904 then amount else 0 end) as "201904", 
    sum(case extract(year_month from saledate) when 201905 then amount else 0 end) as "201905", 
    sum(case extract(year_month from saledate) when 201906 then amount else 0 end) as "201906", 
    合計(金額)「合計」
販売データから
製品、ロールアップによるチャネル別にグループ化します。

最後に、プリコンパイルされたコマンドを通じてステートメントが実行され、結果が返されます。他の月の売上データが追加されても、クエリ ステートメントを手動で変更する必要はありません。

CONNECTストレージエンジンの使用

MariaDB 10.0 以降を使用する場合は、CONNECT ストレージ エンジンの PIVOT テーブル タイプを使用してピボット テーブルを実装できます。

まず、CONNECT ストレージ エンジンをインストールする必要があります。 Windows システムでは、次のコマンドを実行して動的インストールを実行できます。

SONAME 'ha_connect' をインストールします。

構成ファイル my.ini に次の内容を追加することもできますが、サービスを再起動する必要があります。

[mysqld]
プラグインのロード追加 = ha_connect

Linux システムの場合、インストール プロセスについては公式ドキュメントを参照してください。

次にピボット テーブルを定義します。

pivot_salesテーブルを作成する(
 製品varchar(20)がnullではない、
 チャネルvarchar(20)がnullではない、
 `201901` 小数点(10,2) nullでないフラグ=1、
 `201902` 小数点(10,2) nullでないフラグ=1、
 `201903` 小数点(10,2) nullでないフラグ=1、
 `201904` 小数点(10,2) nullでないフラグ=1、
 `201905` 小数点(10,2) nullでないフラグ=1、
 `201906` 小数点(10,2) nullでないフラグ=1
)
エンジン=接続 テーブルタイプ=ピボット
option_list='PivotCol=saledate、FncCol=amount、host=127.0.0.1、user=root、password=p123456、port=3306'
SrcDef='select product,channel,date_format(saledate, ''%Y%m'') saledate,sum(amount) amount from sales_data group by product,channel,date_format(saledate, ''%Y%m'')';

このうち、engine はストレージエンジンを connect として定義します。table_type はテーブルタイプを pivot として定義します。option_list は各種オプションを定義するために使用され、Pivo​​tCol は複数のフィールドに変換するデータが配置されている列を示します。FncCol は集計するフィールドを指定します。その他はソーステーブルサーバーに接続するための情報です。SrcDef はソーステーブルのクエリステートメントを指定するために使用され、Tabname はテーブル名を指定するためにも使用できます。上記のフィールドはピボットテーブルの構造であり、flag=1 は集計後のフィールドを示します。

作成が成功すると、 pivot_sales テーブルのデータに対して直接クエリを実行できます。

pivot_sales から * を選択します。

製品 | チャンネル | 201901 | 201902 | 201903 | 201904 | 201905 | 201906 |
--------|----------|---------|--------|--------|--------|
オレンジ|JD|41289.00|43913.00|49803.00|49256.00|64889.00|62649.00|
オレンジ|ストア|41306.00|37906.00|48866.00|48673.00|58998.00|58931.00|
オレンジ|タオバオ|43488.00|37598.00|48621.00|49919.00|58530.00|64626.00|
アップル|JD.com|38269.00|40593.00|56552.00|56662.00|64493.00|62045.00|
Apple|ストア|43845.00|40539.00|44909.00|55646.00|56771.00|64933.00|
アップル|タオバオ|42969.00|43289.00|48769.00|58052.00|58872.00|59844.00|
バナナ|JD|36879.00|36981.00|51748.00|54801.00|64936.00|60688.00|
バナナ|ストア|41210.00|39420.00|50884.00|52085.00|60249.00|67597.00|
バナナ|タオバオ|42468.00|41955.00|52780.00|54971.00|56504.00|59213.00|

現在、PIVOT テーブルは限られた機能をサポートしており、いくつかの基本的な操作のみを実行できます。例えば:

-- エラーなし select * from pivot_sales
ここで、チャンネルは 'JD.com' です。

-- 構文エラー pivot_sales からチャネルを選択
ここで、チャンネルは 'JD.com' です。

MySQL/MariaDB でピボット テーブルのサンプル コードを実装する方法に関するこの記事はこれで終わりです。MySQL/MariaDB ピボット テーブルに関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • MySQL ピボットテーブルについての簡単な説明

<<:  JavaScriptプロトタイプチェーンの詳細な説明

>>:  レム適応の一般的なパッケージ3つについて

推薦する

Vue diffアルゴリズムの完全な分析

目次序文Vue 更新ビューパッチ同じVノードパッチVノード更新子供序文Vue は仮想 DOM を使用...

HTML チュートリアル: よく使われる HTML タグのコレクション (4)

導入された HTML タグは、必ずしも XHTML 仕様に完全に準拠しているわけではありません。実際...

ネイティブ JS 音楽プレーヤー

この記事の例では、音楽プレーヤーを実装するためのJSの具体的なコードを参考までに共有しています。具体...

JavaScript ドラッグタイム ドラッグケースの詳細な説明

目次DragEvent インターフェースデータ転送インターフェースの概要DataTransfer の...

VMware esxi6.5 のインストールと使用の詳細な手順

目次導入建築ESXIの利点vSphere とは何ですか? 2. 仮想マシンの利点3. 仮想マシンを使...

Spring Cloud での Docker デプロイメントに jib を使用する詳細な手順

ジブの紹介Jib は Google が開発した、Java アプリケーションの Docker および ...

HTML テキストフォーマットの簡単な例 (詳細な説明)

1. テキストの書式設定: この例では、HTML ファイル内のテキストを書式設定する方法を示します...

Alibaba Cloud ECSインスタンスのユーザールートパスワードとリモート接続方法を設定する方法

Alibaba Cloud サーバーを購入した後、新しいインスタンスが正常に動作できるようにするには...

HTML は、Web ページの作成者が学習して習得しなければならないものです。

HTML を学ぶメリットは何ですか? 1: ウェブサイトやブログのウェブ構造を簡単に変更できます。...

ハイパーリンクの幅と高さを直接設定できない問題の解決策

幅と高さを直接使用することはできません。 display:block; または display:in...

Apache POIの基本的な使い方の詳しい説明

目次基本的な紹介入門テスト (Excel ファイルからのデータの読み取り)ステップ1: Maven座...

MySQLの不合理なMaxIdleConnsにより接続が短くなる

1 背景最近、Shimo Document のオンライン ビジネスでパフォーマンスの問題が発生しまし...

Vue における v-model を使用したクロスコンポーネントバインディングの基本的な実装方法

みなさんこんにちは。今日はv-modelを使って親子コンポーネントのバインディング効果を実現する方法...

テキストエリアのテキスト入力領域に改行を実装する方法

textarea 入力領域でテキストを折り返す場合は、<br/> と入力すると <...