MySQL-여러 해에 걸쳐 서로 다른 달에 걸쳐 최대 합계


9

이 질문에 의해 영감을받은 이 하나 [마감] 사실상이 동일 하나 이지만 다른 RDBMS의 사용 (PostgreSQL의 대 MySQL을).

종양 목록이 있다고 가정합니다 (이 데이터는 실제 데이터로 시뮬레이션 됨).

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, 넥타이가 있음을 알 수 전혀 이해 관계가 포함되어야한다 - 그래서 - 무작위로 하나를 선택하고, 답변으로 그를 제공하기를이 문제가 훨씬 더 도전합니다.

정답은 다음과 같습니다.

  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 관련 질문이라는 것을 알고 있지만 시계열 데이터베이스를 사용하면 훨씬 간단 해 질 수 있습니다.
Sash

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

그리고 여기 바이올린 에서 볼 수 있듯이 올바른 결과를 얻 습니다 !


훨씬 간단하게 할 수 있다고 생각하지 않습니다. 염두에 두는 대안은 연도 및 날짜의 최대 수와 동일한 수를 얻기위한 조인 대신 하위 선택입니다. 가능하지만 거의 간단하지 않습니다. 또 다른 옵션은 변수를 사용하여 partition ()을 기준으로 rank ()를 모방 한 것입니다. 쿼리를 변경해야 할 때까지 새로운 작업을 찾길 바랍니다. ;-)
Lennart

바라건대 우리는 이런 일이 일어나기 전에 MySQL 8에있을 것입니다 :-). 그것은 마침내 MySQL을 21 세기로 가져옵니다! INTERSECT 및 기타 몇 가지 그립을 수행 할 수는 없지만 CTE의 적절한 REGEXP는 좋아 보입니다. 그러나 오라클이 실제로 이번 릴리스에 많은 관심을 보인 것처럼 보입니다.
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.