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

推薦する

Linux Autofs 自動マウント サービスのインストールと展開のチュートリアル

目次1. autofs サービスの紹介2. Autofsのインストールと展開3. Autofs効果の...

さまざまなSQL結合を簡単に学ぶ

SQL JOIN 句は、テーブル間の共通フィールドに基づいて 2 つ以上のテーブルの行を結合するため...

Vue+Springbootでインターフェースシグネチャを実装するためのサンプルコード

1. 実装のアイデアインターフェース署名の目的は、リクエストパラメータが改ざんされていないか、リクエ...

フォームの読み取り専用属性と無効な属性についての簡単な説明

フォーム内の読み取り専用および無効な属性1. 読み取り専用:サーバーは、ユーザーがデータを変更するこ...

iframe を更新する 3 つの方法

コードをコピーコードは次のとおりです。 <iframe src="1.htm&quo...

フラッシュプラグインを使用してPCのカメラを呼び出し、TMLページに埋め込む方法

序文この記事を書いた主な理由は、チームリーダーが、ブラウザを使用してコンピューターのカメラを呼び出し...

ウェブページ印刷細線表+ページ印刷究極の戦略

最近、クライアントのために印刷していたとき、ページのヘッダーを印刷するのではなく、表の内容だけを印刷...

Vue ルーティング遅延読み込みの詳細

目次1. ルートの遅延読み込みとは何ですか? 2. ルートの遅延読み込みの使用1. ルートの遅延読み...

Web プロジェクトでの SQL インジェクションの防止

目次1. SQLインジェクションの概要2. SQLインジェクション攻撃の全体的な考え方SQLインジェ...

Nginx リバース プロキシ学習例チュートリアル

目次1. リバースプロキシの準備1. LinuxシステムにTomcatをインストールする2. Tom...

HTML ヘッドタグの詳細な紹介

HTML のヘッド部分には、ブラウザによる Web ページのレンダリングや SEO などに関連するタ...

MySQLのexecute、executeUpdate、executeQueryの違い

execute、executeUpdate、executeQuery の違い (およびそれらの戻り値...

TOM.COMのホームページリニューアルの経験

<br />何の警告もなく、cnBeta で TOM.COM の Web サイトが再設計...

CSS3 を使って本のページめくり効果を実現するサンプルコード

重要なポイント: 1. CSS3 3Dアニメーションをマスターする2. ページめくり後のページ内容の...

Tomcat のパフォーマンス最適化のための Apr モジュールの構築方法

序文Tomcat は、無数のチューニング オプションを備えた、広く使用されている Java Web ...