简体   繁体   中英

SQL select data and grouping data by date range

I have table with data like this

price date type
1000 2021-03-13 A
1000 2021-03-14 A
1000 2021-03-15 A
1300 2021-03-16 A
1000 2021-03-17 A
1300 2021-03-18 A
1000 2021-03-19 A
1500 2021-03-20 A
1500 2021-03-21 A
1500 2021-03-22 A
2000 2021-03-13 B
2000 2021-03-14 B
2000 2021-03-15 B
2000 2021-03-16 B
2000 2021-03-17 B

I want to query data like this

price startDate endDate type
1000 2021-03-13 2021-03-15 A
1300 2021-03-16 2021-03-16 A
1000 2021-03-17 2021-03-17 A
1300 2021-03-18 2021-03-18 A
1000 2021-03-19 2021-03-19 A
1500 2021-03-20 2021-03-22 A
2000 2021-03-13 2021-03-17 B

my current sql below but it is not correct at all

SELECT MIN(date) as startDate, MAX(date) as endDate, price, type                                      
                            FROM prices 
                            GROUP BY type, price
                            ORDER BY type, MIN(date)

This is a gaps and islands problem, and one simple way to handle it uses the difference in row numbers method. Assuming you are using MySQL 8+, the following should work:

WITH cte AS (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY type ORDER BY date) rn1,
              ROW_NUMBER() OVER (PARTITION BY type, price ORDER BY date) rn2
    FROM prices
)

SELECT price, MIN(date) AS startDate, MAX(date) AS endDate, type
FROM cte
GROUP BY price, type, rn1 - rn2
ORDER BY type, startDate;

下面演示链接的屏幕截图

Demo

If not using CTE, you can work the following query:

SELECT w1.price, w1.date, w2.date, w1.type FROM
(
  SELECT * FROM mytable t1
  WHERE NOT EXISTS (
    SELECT 1 FROM mytable t2
    WHERE 
      t1.price = t2.price AND
      t1.type = t2.type AND
      DATEDIFF(t2.date, t1.date) = -1
  )
) w1
INNER JOIN
(
  SELECT * FROM mytable t1
  WHERE NOT EXISTS (
    SELECT 1 FROM mytable t2
    WHERE 
      t1.price = t2.price AND
      t1.type = t2.type AND
      DATEDIFF(t2.date, t1.date) = +1
  )
) w2
ON
w1.price = w2.price AND
w1.type = w2.type AND
w1.date <= w2.date AND
NOT EXISTS (
  SELECT * FROM mytable t1
  WHERE NOT EXISTS (
    SELECT 1 FROM mytable t2
    WHERE 
      t1.price = t2.price AND
      t1.type = t2.type AND
      DATEDIFF(t2.date, t1.date) = +1
  )
  AND
  w1.price = t1.price AND
  w1.type = t1.type AND
  w1.date <= t1.date AND t1.date < w2.date
)
  1. Getting the smaller and larger dates of each period.
  2. Joining these tables.
  3. Getting rows between smaller and larger dates.

DB Fiddle

SELECT MIN(date) as startDate, MAX(date) as endDate, price, type    
FROM prices
GROUP BY type, price
ORDER BY MIN(date) ASC

This query might work in arranging data in ascending order of date

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM