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つについて

推薦する

MySQL 8.0 の新機能の分析 - トランザクション データ ディクショナリとアトミック DDL

序文トランザクション データ ディクショナリとアトミック DDL は、MySQL 8.0 で導入され...

MySQLはbinlogを通じてデータを復元する

目次MySQL ログファイルバイナリログBinlogログがオンになっていますログ記録を有効にする方法...

CSS スティッキーフッタークラシックレイアウトの実装

スティッキーフッターレイアウトとは何ですか?一般的な Web ページのレイアウトは、通常、ヘッダー部...

Linuxダイナミックリンクライブラリの使用

通常のプログラムと比較すると、ダイナミック リンク ライブラリにはメイン関数がなく、一連の関数の実装...

DockerコンテナはホストのMySQL操作にアクセスする

背景:インターフェイスを提供する Flask プロジェクトがあり、これは Docker コンテナを使...

Linuxはiftopを使用してネットワークカードのトラフィックをリアルタイムで監視します

Linux は iftop を使用してネットワーク カードのトラフィックをリアルタイムで監視します。...

フロントエンドにアニメーション遷移効果を実装する方法

目次導入従来のトランジションアニメーションCSS トランジションアニメーションjsアニメーション従来...

Ubuntu20.04 VNCのインストールと設定の実装

VNC はリモート デスクトップ プロトコルです。 VNC を使用して Ubuntu 20.04 を...

JavaScript におけるイベント バブリング メカニズムの詳細な分析

バブリングとは何ですか? DOM イベント フローには、イベント キャプチャ ステージ、ターゲット ...

CentOS 7 は Hadoop 2.10 の高可用性 (HA) をビルドします

この記事では、CentOS 7 で高可用性 Hadoop 2.10 クラスターを構築する方法を紹介し...

MySQL Server 8.0.3 のインストールと設定方法のグラフィックチュートリアル

この文書はMySQL Server 8.0.3のインストールと設定方法を参考のために記録したものです...

Linux で top コマンドを使用する際のヒント

まず、top のいくつかのフィールドの意味を紹介します。 VIRT:仮想メモリ使用量1. プロセスが...

Vueは秒殺しのカウントダウンコンポーネントを実装する

この記事では、2番目のキルカウントダウンコンポーネントを実装するためのVueの具体的なコードを参考ま...

マウスオーバーボタンアニメーションを実現する純粋な CSS3 パート 2

前の 2 つの章を終えて、ボタンのフローティング アニメーションについて新たな理解が得られましたか?...

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

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