MySQL - farklı yıllardaki maksimum toplamlar


9

Bu soru esinlenerek bu bir [kapalı] ve neredeyse bu aynıdır biri fakat farklı RDBMS en kullanarak (PostgreSQL vs MySQL).

Bir tümör listesine sahip olduğumu varsayalım (bu veriler gerçek verilerden simüle edilmiştir):

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');

Belirli bir ayda hangi tümörün en yaygın olduğunu bulmak istiyorsunuz - şimdiye kadar çok iyi!

Şimdi, 2017'nin 1 ayı için bir kravat olduğunu fark edeceksiniz - bu yüzden rastgele birini seçmek ve cevap olarak vermek mantıklı değil - bu yüzden bağlar dahil edilmelidir - bu sorunu çok daha zorlaştırıyor.

Doğru cevap:

  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

Başka bir bonus da ay adının bir tamsayı yerine metin olarak görünmesini sağlamaktır.

Bir çözümüm var ama oldukça karmaşık - çözümümün optimal olup olmadığını bilmek istiyorum. MySQL kemanı burada !


Bunun SQL'e özel bir soru olduğunu anlıyorum, ancak bu bir zaman serisi veritabanı kullanarak çok daha basit hale getirilebilir.
Kanat

2
@Sash, MySQL / MariaDB'nin daha yeni sürümleri de dahil olmak üzere çoğu SQL DBMS ile çok daha basit yapılabilir. MySQL 5.6, SQL92'den sonra icat edilen pek çok işlevselliği uygulamaz.
Lennart

Yanıtlar:


4

Bunu çözme girişimim şu şekildedir. Bu sorgunun nasıl geliştirilebileceği konusunda herhangi bir tavsiye için teşekkür ederiz:

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

Ve burada kemanda görülebileceği gibi doğru sonucu veriyor !


Daha basit yapmanın mümkün olduğunu düşünmüyorum. Akla gelen bir alternatif, yıl ve tarih için maksimum sayıya eşit sayım elde etmek için birleştirme yerine bir alt seçimdir. Mümkün, ancak çok daha basit. Başka bir seçenek de değişkenleri sıralamak () tarafından bölümlere göre ...) taklit etmek ve sorgunun değiştirilmesi gerektiğinde yeni bir iş bulduğunuzu umarız ;-)
Lennart

Umarım böyle bir şey olmadan önce MySQL 8'de olacağız :-). Bu nihayet 21. yüzyılda MySQL getiriyor! Analytics, CTE'ler, uygun REGEXP'ler - iyi görünüyor - INTERSECT'leri ve birkaç başka tutuş yapamazsınız, ancak Oracle'ın bu sürüme gerçekten çok şey kattığı görülüyor.
Vérace

0

MySQL-8.0 ve CTE'leri kullanarak ilk tmpolarak yıl / ay /'a göre toplam sayım gruplaması olarak yaratırız , aynı değere özdeş değerler atar nature_of_illness, böylece yinelenen maks: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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.