好吧,以下情況如何。鑑於此樣本數據:
CREATE TABLE t
(`ID` int, `Value` decimal(5,2), `Start_Date` date, `End_Date` date)
;
INSERT INTO t
(`ID`, `Value`, `Start_Date`, `End_Date`)
VALUES
(1, 0.1, '2015-10-01', '2015-10-10'),
(2, 0.3, '2015-10-05', '2015-10-12'),
(2, 0.4, '2015-10-12', NULL),
(1, 0.5, '2015-10-10', '2015-10-20'),
(1, 0.5, '2015-10-20', NULL)
;
你現在可以做的是沒有數據來創建表的副本:
CREATE TABLE tmp_t LIKE t;
然後插入你的表的清理版本:
INSERT INTO tmp_t
SELECT MIN(ID), MIN(Value), MIN(Start_Date)
, IF(MIN(IFNULL(End_Date, '1970-01-01')) = '1970-01-01', NULL, MIN(IFNULL(End_Date, '1970-01-01')))
FROM (
SELECT
t.*
, @gn := IF(@prev_value != `Value` OR @prev_id != ID, @gn + 1 , @gn) AS group_number
, @prev_value := `Value`
, @prev_id := ID
FROM
t
, (SELECT @prev_value := NULL, @prev_id := NULL, @gn := 0) var_init_subquery
ORDER BY Start_Date
) sq
GROUP BY group_number;
請注意,它也可以做
CREATE TABLE tmp_t AS
SELECT ...
但我選擇了上面的版本,原因CREATE TABLE ... LIKE ...
也像原始表一樣創建主鍵,索引和外鍵約束等等。 CREATE TABLE ... AS
不這樣做。
反正都是你所要做的則是這樣的:
RENAME TABLE t TO t_backup, tmp_t TO t;
這將在任何時間完成,也將是一個原子操作,因此,即使在安全的生產環境中使用。
結果集是:
mysql > SELECT * FROM t;
+------+-------+------------+------------+
| ID | Value | Start_Date | End_Date |
+------+-------+------------+------------+
| 1 | 0.10 | 2015-10-01 | 2015-10-10 |
| 2 | 0.30 | 2015-10-05 | 2015-10-12 |
| 1 | 0.50 | 2015-10-10 | 2015-10-20 |
| 2 | 0.40 | 2015-10-12 | NULL |
| 1 | 0.50 | 2015-10-20 | NULL |
+------+-------+------------+------------+
下面是它如何工作的。我們在這裏所做的只是掃描整個桌子,並且...
順便說一句,這裏是我在開始時曾經使用過的簡化版本,假設您只專注於一個ID
。保持它的完整性,以防萬一你想玩它。不妨忽略它。
SELECT MIN(ID), MIN(Value), MIN(Start_Date)
, IF(MIN(IFNULL(End_Date, '1970-01-01')) = '1970-01-01', NULL, MIN(IFNULL(End_Date, '1970-01-01')))
FROM (
SELECT
t.*
, @gn := IF(@prev != `Value`, @gn + 1 , @gn) AS group_number
, @prev := `Value`
FROM
t
, (SELECT @prev := NULL, @gn := 0) var_init_subquery
WHERE
ID = 1
ORDER BY Start_Date
) sq
GROUP BY group_number;
返回解釋。 SELECT
子句逐個處理它中的每一行。因此,IF()
條件中的變量實際上保持其初始化值或前一行的值,因爲在處理IF()
函數之後分配了當前行的值。因此,我們所做的只是增加@gn
變量,除非Value
(可怕的列名稱)的值相同,並且ID
是相同的(並且開始日期是「下一個」(我的英語很糟糕))。還請注意,這就是爲什麼ORDER BY
非常重要。關係數據庫中沒有順序,除非您指定它,所以不要「優化」它。
什麼確定是否行「有義」或不? – fancyPants
@fancyPants對於在「End_Date」中具有「NULL」的行具有相同的值,但具有不同的「Start_Date」......它沒有意義,因爲它不是真正的更新 - 狀態(值)保持不變 – Bramat
因此,在End_Date設置爲NULL的整個表中,它會永遠只是一行嗎?你也應該添加更多的樣本數據。如果行中有兩行具有相同值但行中沒有一個將End_Date設置爲NULL,而是另一行更新? – fancyPants