Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何从表中删除重复行而不在查询中命名列?_Mysql_Sql_Database - Fatal编程技术网

Mysql 如何从表中删除重复行而不在查询中命名列?

Mysql 如何从表中删除重复行而不在查询中命名列?,mysql,sql,database,Mysql,Sql,Database,我正在跟踪一个表中的行的更改历史,该表在更新另一个表时使用触发器填充。它跟踪主表的修订历史记录 通常,我的用户出于习惯,会点击保存按钮,即使他们没有更改记录中的任何内容,系统仍会将该行的副本记录为历史记录表中的修订,尽管事实上没有任何更改 假设我有这样列的表(尽管我的表有40多个列): 主要数据: id, name, phone, task, dob, timestamp, note, drivername, student, doctor, userid 更新主数据时,在历史记录中插入: r

我正在跟踪一个表中的行的更改历史,该表在更新另一个表时使用触发器填充。它跟踪主表的修订历史记录

通常,我的用户出于习惯,会点击保存按钮,即使他们没有更改记录中的任何内容,系统仍会将该行的副本记录为历史记录表中的修订,尽管事实上没有任何更改

假设我有这样列的表(尽管我的表有40多个列):

主要数据:

id, name, phone, task, dob, timestamp, note, drivername, student, doctor, userid
更新主数据时,在历史记录中插入:

revisionid, revisiontime, id, name, phone, task, dob, timestamp, note, drivername, student, doctor, userid
如果我想手动列出这些列,那么在这个站点和其他站点上查找重复记录的解决方案都会很好地工作

问题是有很多列,我经常添加列,不想每次都重写这个查询

当用户保存时,通常只会更改时间戳。我想做的是只保留值已更改的修订(忽略始终更改的修订ID和修订时间)

在查询中,除了要忽略的列之外,我不想列出任何其他列名。可能吗

伪代码:

DELETE [rows, except one] FROM historytable WHERE [all columns match values] EXCEPT [these few columns which can still be different and be deleted]
以下是一些参考问题:


否,如果不指定列,则无法从表中删除重复项

据我所知,在不指定显式列列表的情况下,使用SQL语句修剪DUP表的唯一方法是执行以下操作。创建仅包含不同记录的新副本:

create table T_UNIQUES as select distinct * from T;
您必须创建一个新表,重命名旧表,然后将新表重命名到位。当删除操作太慢时,有时会在数据仓库上执行此操作。但是,这不会忽略任何时间戳列,因此可能不够

我所知道的用一些自动的和可扩展的东西来编写修剪历史表的唯一方法是从数据字典(INFORMATION_SCHEMA)中提取列。这只会自动执行,但不会避免指定有问题的列


我的方法是修复触发器。这听起来不完整/不充分;我会重写它,以执行“向上插入”,而不是盲目插入。

我的思考过程如下

  • 列出所有列名(带有排除列表)

    选择
    COLUMN\u NAME
    信息\u架构
    其中
    TABLE_SCHEMA
    ='db' 和
    TABLE\u NAME
    ='TABLE' 和
    COLUMN\u NAME
    不在('columnToIgnore')中

  • 将名称作为行存储在临时表中

    如果不存在列名,则创建临时表(步骤1)

  • 从临时表“columnNames”中获取所有记录并存储在变量中

    从columnNames中选择GROUP_CONCAT(COLUMN_NAME)进入@cols

  • 准备最终语句,列出所有多余的行。(我使用SELECT进行检查)

    将@sql=CONCAT('SELECT CONCAT_WS(“,”,@cols,”)设置为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;
    

    谁说我们不能用电锯切面包;)

    通常在提交到数据库之前执行此操作。比较现有的和请求的,如果没有相关的更改,忽略它。像那样修剪历史记录表并不容易。是的,解决方法如下:不幸的是,我继承了这个问题..这不是一个非常传统的解决方案,但是您可以查询
    信息\u schema
    以获取列的名称,然后使用这些信息以友好的方式构建DELETE语句。这些列中有多少列实际需要更改?你能按它们中的任何一个分组,然后使用select语句找到一个不同的子集,然后将其放入delete语句中的not in子句中吗?@abl这是个好主意!我现在就调查一下,没想到。如果你能看看我的方法和/或有什么意见,我将不胜感激。谢谢