MySQLでクロス集計

SQLでクロス集計する際、該当がない項目も水平軸にしないと

漏れがでてしまうと考えたことはないでしょうか?

該当がある項目を2つ、縦に並べるのは標準で備わっているので

何の造作もないことでしょう。

例えば、

SELECT  縦カラム,横カラム名,COUNT(*) 件数

       FROM  スキーマ名.テーブル名 

      GROUP BY 縦カラム,横カラム名;

で完成です。

しかし、横カラムのデータを水平方向に並べた、所謂クロス集計

をしたいと思った途端、横カラムの異なるデータの個数が動的(

言い換えれば不定)なので、SQLを書くことができない。

ありうる全ての種類が受容限度以下なら、該当データが無いこと

を承知でSQLを書くこともできるでしょう。

実は、何個のカラムを用意すればいいのかは、SQLで直ぐわかって

しまうことです。

例えば,  SELECT DISTINCT 横カラム名 FROM ....;

で済んでしまいます。

そこで、この結果を人間が見てSQLを書き下す代わりに、

SQL自分自身でSQLで作成する事はできないのかと言うことを

見ましょう。

そうすると、

SELECT 縦カラム,

       式1 AS 横カラム1,

       式2 AS 横カラム2,

         ...

       式n AS 横カラムn

          FROM  ... GROUP BY 縦カラム;

のようなSQL(言わばメタ的SQL)をSQL自身で、

生成できそうな気がしませんか?

SQLで生成しななくてもいい部分は、固定文字列にして

おけば完成のハズですね。

ではここで具体例を示します。

 

SQLを生成するSQL見本 

 

DROP TEMPORARY TABLE IF EXISTS temp.wrk ;
CREATE TEMPORARY TABLE temp.wrk
  SELECT DISTINCT TbL.横カラム名
    FROM スキーマ名.テーブル名 TbL
    LEFT JOIN ~~~~~~
    WHERE ~~~~~~ AND

                   ~~~~~~ AND

                              . . . . . .  . . . 

                               ~~~~~~ ;
DROP TEMPORARY TABLE IF EXISTS temp.tmp ;
CREATE TEMPORARY TABLE temp.tmp (cmd VARCHAR(128)) ;
INSERT INTO temp.tmp VALUES
      ("SELECT 式 AS 縦カラム) ;
INSERT INTO temp.tmp
     (SELECT CONCAT(" SUM(", 縦カラム, ") AS  ", 縦カラム, ", ") FROM temp.wrk);
INSERT INTO temp.tmp VALUES
     (" SUM(合計) 合計 "),
     (" FROM ("),
    (" SELECT TbL.横カラム名,TbL.縦カラム名,") ;
INSERT INTO temp.tmp
    (SELECT CONCAT(" SUM(IF(AcT.横カラム名='", 横カラム, "' , 1 ,0))  AS ", 横カラム, ",")             FROM temp.wrk);
INSERT INTO temp.tmp VALUES
      (" SUM(1) 合計"),
     (" FROM スキーマ名.テーブル名 Tbl"),
     (" LEFT JOIN ~~~~~~"),
     (" WHERE ~~~~~~ AND"),
     (" ~~~~~~ AND"),

     . . . . . ..  . . . . .
    (" ~~~~~~"),
    (" GROUP BY 1,2,"),
    (" ) tmp"),
    (" GROUP BY 1 WITH ROLLUP;"),;
SELECT * FROM temp.tmp
;