如何从对列中的每个常见值序列进行分组的 mysql 表中创建期间日期范围

Raf*_*lks 1 mysql select date-range sequence

我的目标是在列中返回具有相同值的开始和结束日期。这是我的桌子。已标记 (*) 以让您了解我希望如何为 A 和 B 列的每个相似序列值获取“EndDate”

ID | DayDate   |  A  |  B
-----------------------------------------------
1  | 2010/07/1 | 200 |  300
2  | 2010/07/2 | 200 |  300 *
3  | 2010/07/3 | 150 |  250
4  | 2010/07/4 | 150 |  250 *
8  | 2010/07/5 | 150 |  350 *
9  | 2010/07/6 | 200 |  300
10 | 2010/07/7 | 200 |  300 *
11 | 2010/07/8 | 100 |  200
12 | 2010/07/9 | 100 |  200 *
Run Code Online (Sandbox Code Playgroud)

我想从上表中得到以下结果表

| DayDate   |EndDate   |  A  |  B
-----------------------------------------------
| 2010/07/1 |2010/07/2 | 200 |  300
| 2010/07/3 |2010/07/4 | 150 |  250
| 2010/07/5 |2010/07/5 | 150 |  350
| 2010/07/6 |2010/07/7 | 200 |  300
| 2010/07/8 |2010/07/9 | 100 |  200
Run Code Online (Sandbox Code Playgroud)

更新:

谢谢迈克,您的方法似乎在您将以下行视为错误的角度来看有效。

8  | 2010/07/5 | 150 |  350 * 
Run Code Online (Sandbox Code Playgroud)

然而,这并不是一个错误。我面临的这类数据的挑战就像记录市场价格随日期变化的场景。mycase 中的真正问题是如果 A 和 B 在所有这些行中都匹配,则选择具有开始日期和结束日期的所有行。还可以选择与先前选择的行相邻的行,依此类推,表中不会遗漏任何数据。

我可以解释一个真实世界的场景。如我的问题中所述,带有 A 室和 B 室的酒店将每天的房价输入到表中。现在,酒店需要获得一份报告,以使用开始和结束日期以更短的方式显示价格日历,而不是列出所有输入的日期。比如2010/07/01到2010/07/02,A的价格是200,B的价格是300。这个价格从3号到4号,5号才有不同的价格,只有B房的那一天价格更改为 350。所以这被视为单日差异,这就是为什么开始和结束日期相同。

我希望这可以解释问题的情况。另请注意,这家酒店可能会在特定时间段内关闭,可以说这是我第一个问题的另一个问题。问题是如果没有在特定日期输入价格会怎样,例如在星期天酒店不出售这两个房间,所以他们没有输入价格,这意味着表中将不存在该行。

Mik*_*ike 6

创建相关表可以让您更自由地查询和提取相关信息。以下是一些您可能会觉得有用的链接:

您可以从这些教程开始:
http://dev.mysql.com/tech-resources/articles/intro-to-normalization.html
http://net.tutsplus.com/tutorials/databases/sql-for-beginners/

这里还有一些关于 stackoverflow 的问题可能有用:
用简单的英语规范化
数据库规范化到底是做什么的?

无论如何,找到一个可能的解决方案。以下示例使用您的酒店房间类比。

首先,创建一个表来保存有关酒店房间的信息。该表仅包含房间 ID 及其名称,但您可以在此处存储其他信息,例如房间类型(单人房、双人房、双床房)、其景观(海景、海景、城市景观、泳池景观)以及很快:

CREATE TABLE `room` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `name_UNIQUE` (`name` ASC) )
ENGINE = InnoDB;
Run Code Online (Sandbox Code Playgroud)

现在创建一个表格来保存不断变化的房价。该表room通过room_id列链接到该表。外键约束防止将记录插入到rate表中,这些记录指的是不存在的房间:

CREATE TABLE `rate` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
  `room_id` INT UNSIGNED NOT NULL,
  `date` DATE NOT NULL,
  `rate` DECIMAL(6,2) UNSIGNED NOT NULL,
  PRIMARY KEY (`id`),
  INDEX `fk_room_rate` (`room_id` ASC),
  CONSTRAINT `fk_room_rate`
    FOREIGN KEY (`room_id` )
    REFERENCES `room` (`id` )
    ON DELETE CASCADE
    ON UPDATE CASCADE)
ENGINE = InnoDB;
Run Code Online (Sandbox Code Playgroud)

创建两个房间,并添加一些关于每个房间的每日房价信息:

INSERT INTO `room` (`id`, `name`) VALUES (1, 'A'), (2, 'B');

INSERT INTO `rate` (`id`, `room_id`, `date`, `rate`) VALUES
( 1, 1, '2010-07-01', 200),
( 2, 1, '2010-07-02', 200),
( 3, 1, '2010-07-03', 150),
( 4, 1, '2010-07-04', 150),
( 5, 1, '2010-07-05', 150),
( 6, 1, '2010-07-06', 200),
( 7, 1, '2010-07-07', 200),
( 8, 1, '2010-07-08', 100),
( 9, 1, '2010-07-09', 100),
(10, 2, '2010-07-01', 300),
(11, 2, '2010-07-02', 300),
(12, 2, '2010-07-03', 250),
(13, 2, '2010-07-04', 250),
(14, 2, '2010-07-05', 350),
(15, 2, '2010-07-06', 300),
(16, 2, '2010-07-07', 300),
(17, 2, '2010-07-08', 200),
(18, 2, '2010-07-09', 200);
Run Code Online (Sandbox Code Playgroud)

存储该信息后,带有 的简单SELECT查询JOIN将显示所有每日房价:

SELECT
    room.name,
    rate.date,
    rate.rate
FROM room
JOIN rate
ON rate.room_id = room.id;

+------+------------+--------+
| A    | 2010-07-01 | 200.00 |
| A    | 2010-07-02 | 200.00 |
| A    | 2010-07-03 | 150.00 |
| A    | 2010-07-04 | 150.00 |
| A    | 2010-07-05 | 150.00 |
| A    | 2010-07-06 | 200.00 |
| A    | 2010-07-07 | 200.00 |
| A    | 2010-07-08 | 100.00 |
| A    | 2010-07-09 | 100.00 |
| B    | 2010-07-01 | 300.00 |
| B    | 2010-07-02 | 300.00 |
| B    | 2010-07-03 | 250.00 |
| B    | 2010-07-04 | 250.00 |
| B    | 2010-07-05 | 350.00 |
| B    | 2010-07-06 | 300.00 |
| B    | 2010-07-07 | 300.00 |
| B    | 2010-07-08 | 200.00 |
| B    | 2010-07-09 | 200.00 |
+------+------------+--------+
Run Code Online (Sandbox Code Playgroud)

要查找每个房价的开始和结束日期,您需要一个更复杂的查询:

SELECT 
    id,
    room_id,
    MIN(date) AS start_date,
    MAX(date) AS end_date,
    COUNT(*) AS days,
    rate
FROM (
    SELECT
        id,
        room_id,
        date,
        rate, 
        (
            SELECT COUNT(*)
            FROM rate AS b
            WHERE b.rate <> a.rate
            AND b.date <= a.date
            AND b.room_id = a.room_id
        ) AS grouping
    FROM rate AS a
    ORDER BY a.room_id, a.date
) c
GROUP BY rate, grouping
ORDER BY room_id, MIN(date);

+----+---------+------------+------------+------+--------+
| id | room_id | start_date | end_date   | days | rate   |
+----+---------+------------+------------+------+--------+
|  1 |       1 | 2010-07-01 | 2010-07-02 |    2 | 200.00 |
|  3 |       1 | 2010-07-03 | 2010-07-05 |    3 | 150.00 |
|  6 |       1 | 2010-07-06 | 2010-07-07 |    2 | 200.00 |
|  8 |       1 | 2010-07-08 | 2010-07-09 |    2 | 100.00 |
| 10 |       2 | 2010-07-01 | 2010-07-02 |    2 | 300.00 |
| 12 |       2 | 2010-07-03 | 2010-07-04 |    2 | 250.00 |
| 14 |       2 | 2010-07-05 | 2010-07-05 |    1 | 350.00 |
| 15 |       2 | 2010-07-06 | 2010-07-07 |    2 | 300.00 |
| 17 |       2 | 2010-07-08 | 2010-07-09 |    2 | 200.00 |
+----+---------+------------+------------+------+--------+
Run Code Online (Sandbox Code Playgroud)

您可以在此处找到对上述查询中使用的技术的很好解释:http :
//www.sqlteam.com/article/detecting-runs-or-streaks-in-your-data