我正在跟踪表中行的更改历史记录,该表在另一个表的更新时填充了触发器。它跟踪主表的修订历史记录。
通常,我的用户出于习惯,即使他们没有更改记录中的任何内容,也会点击SAVE按钮,系统仍然会将该行的副本记录为历史记录表中的修订版,尽管事实如此没有任何改变。
让我说我有这样的列表(尽管我有大约40多个cols):
主要数据:
id, name, phone, task, dob, timestamp, note, drivername, student, doctor, userid
在更新主数据时,插入历史记录:
revisionid, revisiontime, id, name, phone, task, dob, timestamp, note, drivername, student, doctor, userid
如果我想手动列出列,那么在本网站和其他网站上找到重复记录的解决方案都可以正常运行。
问题是有很多列,我经常添加列,不想每次都重写这个查询。
当用户保存时,通常只会更改时间戳。我想要做的只是保留值已更改的修订(忽略始终更改的修订版和修订版)。
在查询中,我不想列出除了我想忽略的列之外的任何其他列名。有可能吗?
伪代码:
DELETE [rows, except one] FROM historytable WHERE [all columns match values] EXCEPT [these few columns which can still be different and be deleted]
以下是一些参考问题:
Deleting duplicate rows from a table
How to check for duplicates in mysql table over multiple columns
答案 0 :(得分:0)
不,如果不指定列,就无法从表中删除重复项。
我知道使用SQL语句修剪重复表而不指定显式列列表的唯一方法是执行以下操作。创建仅包含不同记录的新副本:
create table T_UNIQUES as select distinct * from T;
您必须创建一个新表,重命名旧表,然后将新表重命名到位。当DELETE操作太慢时,有时会在数据仓库上执行此操作。但是,这并不会忽略任何时间戳列,因此可能不够。
我知道用自动和可扩展的东西编写修剪历史表的唯一方法是从数据字典中提取列(INFORMATION_SCHEMA)。这只会使其自动化,但不能避免指定相关列。
我的方法是修复触发器。它听起来破碎/不足;我会改写它来做一个" UPSERT"而不是盲目的INSERT。
答案 1 :(得分:0)
我的思考过程如下......
列出所有列名(带有排除列表)
SELECT COLUMN_NAME
来自INFORMATION_SCHEMA
。COLUMNS
在哪里TABLE_SCHEMA
=' db'
和TABLE_NAME
='表'
和COLUMN_NAME
不在(' columnToIgnore')
将名称作为行存储在临时表中
CREATE TEMPORARY TABLE IF NOT NOT EXISTS columnNames AS( step1 );
从临时表' columnNames'中获取所有记录并存储在变量中。
将GROUP_CONCAT(COLUMN_NAME)选入@cols FROM columnNames;
准备最终语句,列出所有冗余行。 (我用SELECT来检查)
SET @sql = CONCAT(' SELECT CONCAT_WS("",',@ cols,')AS allColumns FROM targetTable GROUP BY allcolumns');
总结一下,
CREATE TEMPORARY TABLE IF NOT EXISTS columnNames AS (SELECT `COLUMN_NAME`
FROM `INFORMATION_SCHEMA`.`COLUMNS`
WHERE `TABLE_SCHEMA`='dbName'
AND `TABLE_NAME`='tableName'
AND `COLUMN_NAME` NOT IN ('columnNameToIgnore'));
SELECT GROUP_CONCAT(COLUMN_NAME) into @cols FROM columnNames;
SET @sql = CONCAT('SELECT CONCAT_WS(" ",',@cols,') AS allColumns FROM targetTable GROUP BY allcolumns');
PREPARE stmt FROM @sql;
EXECUTE stmt;
谁说我们不能用电锯切面包;)