MySQL-複数年にわたる同数の異なる月の合計の最大


9

この質問は、触発されたこの1 [クローズ]、事実上これと同じである1が異なるRDBMSの(MySQLの対PostgreSQLの)を使用します。

腫瘍のリストがあるとします(このデータは実際のデータからシミュレートされます)。

CREATE table illness (nature_of_illness VARCHAR(25), created_at DATETIME);

INSERT INTO illness VALUES ('Cervix', '2018-01-03 15:45:40');
INSERT INTO illness VALUES ('Cervix', '2018-01-03 15:45:40');
INSERT INTO illness VALUES ('Cervix', '2018-01-03 15:45:40');
INSERT INTO illness VALUES ('Cervix', '2018-01-03 15:45:40');
INSERT INTO illness VALUES ('Cervix', '2018-01-03 15:45:40');
INSERT INTO illness VALUES ('Lung',   '2018-01-03 17:50:32');
INSERT INTO illness VALUES ('Lung',   '2018-02-03 17:50:32');
INSERT INTO illness VALUES ('Lung',   '2018-02-03 17:50:32');
INSERT INTO illness VALUES ('Lung',   '2018-02-03 17:50:32');
INSERT INTO illness VALUES ('Cervix', '2018-02-03 17:50:32');
-- 2017, with 1 Cervix and Lung each for the month of Jan - tie!
INSERT INTO illness VALUES ('Cervix', '2017-01-03 15:45:40');
INSERT INTO illness VALUES ('Lung',   '2017-01-03 17:50:32');
INSERT INTO illness VALUES ('Lung',   '2017-02-03 17:50:32');
INSERT INTO illness VALUES ('Lung',   '2017-02-03 17:50:32');
INSERT INTO illness VALUES ('Lung',   '2017-02-03 17:50:32');
INSERT INTO illness VALUES ('Cervix', '2017-02-03 17:50:32');

あなたは、特定の腫瘍が特定の月に最も一般的であったことを知りたいです-これまでのところとても良いです!

ここで、2017年の1か月目にネクタイがあることに気づくでしょう- ランダムに1つを選んでそれを答えとして与えるのはまったく意味がありません

正解は次のとおりです。

  Year    Month  Tumour count      Type
  2017        1             1    Cervix  -- note tie
  2017        1             1      Lung  --   "   "
  2017        2             3      Lung
  2018        1             5    Cervix
  2018        2             3      Lung

さらに、月名を整数ではなくテキストとして表示することもできます。

私は解決策を持っていますが、それは非常に複雑です-私の解決策が最適であるかどうか知りたいのですが。MySQLフィドルがここにあります


これはSQL固有の問題であることは理解していますが、時系列データベースを使用すると、これをはるかに簡単にすることができます。
サッシュ

2
@Sash、それは、MySQL / MariaDBの新しいバージョンを含むほとんどのSQL DBMSではるかに簡単に実行できます。MySQL 5.6は、SQL92の後に発明された多くの機能を実装していません。
Lennart

回答:


4

これを解決するための私の試みは以下の通りです。このクエリを改善する方法についてのアドバイスをいただければ幸いです。

SELECT 
  t3.c_year AS "Year",
  t3.c_month AS "Month", 
  t3.il_mc AS  "Tumour count", 
  t4.ill_nat AS "Type" FROM
(
  SELECT c_year, c_month, il_mc FROM
  (
    SELECT  
    c_year, 
    c_month,
    MAX(month_count) AS il_mc
  FROM
    (
      SELECT nature_of_illness as illness,
        EXTRACT(YEAR  FROM created_at) AS c_year,
        EXTRACT(MONTH FROM created_at) AS c_month,
        COUNT(EXTRACT(MONTH FROM created_at)) AS month_count
      FROM illness
      GROUP BY illness, c_year, c_month
      ORDER BY c_year, c_month
    ) AS t1
  GROUP BY c_year, c_month
  ) AS t2
) AS t3
JOIN
(
SELECT 
  EXTRACT(YEAR FROM created_at) AS t_year, 
  EXTRACT(MONTH FROM created_at) AS t_month,  
  nature_of_illness AS ill_nat, 
  COUNT(nature_of_illness) AS ill_cnt
FROM illness
GROUP BY t_year, t_month, nature_of_illness
ORDER BY t_year, t_month, nature_of_illness
) AS t4
ON t3.c_year = t4.t_year
AND t3.c_month = t4.t_month
AND t3.il_mc = t4.ill_cnt

そして、ここのフィドル分かるように、それは正しい結果を与えます


もっと簡単にできるとは思いません。頭に浮かぶ1つの選択肢は、年と日付の最大数に等しい数を取得するための結合ではなく、副選択です。可能ですが、ほとんど簡単ではありません。別のオプションは、変数を使用して、partition by ...でrank()を模倣し、クエリを変更する必要があるときまでに新しいジョブを見つけたことを願っています;-)
Lennart

うまくいけば、そのようなことが起こる前にMySQL 8にいることになるでしょう:-) これは、最終的には 21世紀にMySQLをもたらします!分析、CTE、適切なREGEXP-良さそう-INTERSECTや他のいくつかの不満を行うことはできませんが、Oracleはこのリリースに多くを注いでいるようです。
Vérace

0

MySQL-8.0とCTEを使用しtmpて、年/月/ nature_of_illnessでグループ化した集計カウントとして最初に作成し、RANK()同じ値を同じ値に割り当てc、重複する最大値を考慮します。

 SELECT y as 'Year',mon as 'Month',c as 'Tumor Count', nature_of_illness as 'Type'
 FROM (
   WITH tmp AS ( 
    SELECT YEAR(created_at) as y, MONTH(created_at) as mon, COUNT(*) as c, nature_of_illness
    FROM illness
    GROUP BY y, mon, nature_of_illness
   )
   SELECT y, mon, c, nature_of_illness,
   RANK() OVER (PARTITION BY y, mon ORDER BY c DESC) as `rank`
   FROM tmp
 ) AS tmp2 
WHERE `rank` = 1
ORDER BY y, mon
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.