MySQL慢慢改变尺寸SCD2 + ON DUPLICATE KEY UPDATE

时间:2012-09-05 11:43:05

标签: mysql database scd

我希望让MySQL处理慢慢改变尺寸 该表设置为使用“生效日期”作为控件 - 因此表结构类似于此处http://en.wikipedia.org/wiki/Slowly_changing_dimension类型II底部示例。

是否可以使用此功能更新/插入或最好分离功能,例如insert = check for existing then insert,update = update original column,insert new column

由于

2 个答案:

答案 0 :(得分:1)

不,这是不可能的。如果该行已经存在,则该语句将更新该行,因此您最终只会有一条记录和松散的历史信息。您需要先更新旧记录(将end_date设置为当前日期),然后插入新记录(end_date为NULL)。

答案 1 :(得分:0)

我有这种方法的实现,没有任何选择(但有插入/更新)。 MySQL:5.7 这是表结构:

CREATE TABLE UserStatusLog (
  `user_id` int(11) NOT NULL,
  `status_type` tinyint(8) NOT NULL, // we are logging multiple statuses in one table
  `status_value` int(11) NOT NULL, // actual value of the status
  `is_last` tinyint(1) DEFAULT '1', // marking flag
  `start_ts` timestamp NOT NULL DEFAULT '1970-01-01 00:00:01', // when this status_value became actual
  `finish_ts` timestamp NOT NULL DEFAULT '2030-01-01 00:00:00', // end of actuality for this status
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, // just for logging
  `updated` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, // just for logging
  PRIMARY KEY (`user_id`,`status_type`,`finish_ts`),
  UNIQUE KEY `uniq` (`user_id`,`status_type`,`is_last`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

我们正在尝试将新值插入日志:

INSERT IGNORE INTO UserStatusLog
(user_id, status_type, status_value, is_last, start_ts, finish_ts)
VALUES ($user_id, $type, $value, NULL, '2017-12-08 15:45:34', '2030-01-01 00:00:00')
ON DUPLICATE KEY UPDATE is_last = IF(start_ts < '2017-12-08 15:45:34' && status_value != VALUES(status_value), 
2 /* THIS IS A "SPECIAL VALUE" for is_last */
, is_last);

然后,我们通过mysql_affected_rows();

比较查询结果
  • 0 有一条记录,其start_ts大于新记录,oe
  • 1 这是日志中的第一个用户记录,需要执行更新,为此记录标记is_last:

    更新UserStatusLog SET is_last = 1 WHERE user_id = $ user_id AND status_type = $ type AND finish_ts =&#39; 2030-01-01 00:00:00&#39;限制1;

  • 2 有一条记录,比新的start_ts更长,我们已经用is_last = 2(特殊值)更新了它:

    更新test.mock_20171208_47d9ac21808ee65d605ca32205888648 SET is_last = NULL,finish_ts =&#39; 2017-12-08 15:45:45&#39; WHERE user_id = $ user_id AND status_type = $ type AND is_last = 2 LIMIT 1; //插入新的,真正的最后记录 INSERT INTO test.mock_20171208_47d9ac21808ee65d605ca32205888648 (user_id,status_type,status_value,is_last,start_ts,finish_ts) VALUES ($ user_id,$ type,$ value,$ is_last = 1,&#39; 2017-12-08 15:45:45&#39;,&#39; 2030-01-01 00:00:00&#39; );