Mysql 从SQL数据库表中删除未使用的父记录

Mysql 从SQL数据库表中删除未使用的父记录,mysql,sql,sql-server,oracle,tsql,Mysql,Sql,Sql Server,Oracle,Tsql,在SQL Server 2012中执行的测试表明,如果删除表中的一条记录会导致外键冲突,则命令DELETE FROM dbo.TableName将停止并返回错误。不删除任何记录 假设未使用的记录是那些可以在不违反外键关系的情况下删除的记录 假设所有记录都可以通过不可为空的整数ID列唯一标识 假设可以安全地忽略可能导致副作用的功能,例如触发器或级联删除 关于表,应该假设它的记录和关系。(例如:在这些参数范围内,解决方案应该是通用的。) 是否存在以以下形式删除未使用的父记录的解决方案: SQL,

在SQL Server 2012中执行的测试表明,如果删除表中的一条记录会导致外键冲突,则命令
DELETE FROM dbo.TableName
将停止并返回错误。不删除任何记录

  • 假设未使用的记录是那些可以在不违反外键关系的情况下删除的记录

  • 假设所有记录都可以通过不可为空的整数ID列唯一标识

  • 假设可以安全地忽略可能导致副作用的功能,例如触发器或级联删除

  • 关于表,应该假设它的记录和关系。(例如:在这些参数范围内,解决方案应该是通用的。)

是否存在以以下形式删除未使用的父记录的解决方案:

  • SQL,它将忽略导致错误的记录的错误,并在没有错误的记录上成功执行
  • SQL,它将仅对一组以某种方式检测到的未使用的父记录执行删除?(对于已知FK关系的特定表容易完成。一般来说不太容易完成。)
  • 服务器端代码将执行与上述解决方案等效的操作
  • 注意事项:

    • SQL解决方案比需要C#、Python、Java、Ruby等的解决方案更可取
    • 与特定于RDBMS的解决方案相比,跨RDBMS解决方案更可取

    请说明您的解决方案所应用并已在其上进行测试的RDBMS。

    在这种情况下,我通常会禁用fk约束,如果这不起作用,我通常会删除约束,清理数据,然后重新创建fk

    这里有一个关于如何做的快速链接

    在Oracle中,您可以使用
    将错误记录到
    选项:

    示例数据设置:

    create table parent (pid integer not null primary key);
    create table child 
    (
      cid integer not null primary key,
      pid integer not null references parent(pid)
    );
    
    insert into parent values (1);
    insert into parent values (2);
    insert into parent values (3);
    
    insert into child values (1,1);
    insert into child values (2,1);
    insert into child values (3,2);
    
    创建将记录所有不可删除行的表:

    begin
      DBMS_ERRLOG.CREATE_ERROR_LOG('PARENT', 'ERR_LOG_PARENT');
    end;
    /
    
    现在运行删除:

    delete from parent
    log errors into err_log_parent ('delete test')
    reject limit unlimited;
    
    SQLFiddle示例:

    DBMS\u错误日志手册:

    LOG ERRORS
    选项手册:

    没有任何神奇的药丸可以满足您在所有平台上的需求,但您可以编写一个适合任何DBMS的药丸。是的,我们在SQL server生产数据库上完成了这项工作。这不是一个单步的过程,但是您可以使用动态SQL或类似的工具轻松地自动化第二步

    关于:

    您必须知道当前记录的每个父表

    是的,但是你可以编写代码来解释这一点。使用信息_模式视图(SQL Server、MySQL)或DB的等效项为相关表生成delete语句。然后运行生成的语句


    一个好的起点是信息\u SCHEMA.TABLES、信息\u SCHEMA.REFERENTIAL\u约束和信息\u SCHEMA.CONSTRAINT\u COLUMN\u用法。

    如果行引用了PK,那么删除将失败,但它将继续

    SET NOCOUNT ON;
    
    DECLARE @PK varchar(10);
    
    PRINT '-------- Delete PK --------';
    
    DECLARE delete_cursor CURSOR FOR 
    SELECT PK 
    FROM PKstring
    ORDER BY PK;
    
    OPEN delete_cursor
    
    FETCH NEXT FROM delete_cursor 
    INTO @PK
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        DELETE PKstring where PK = @PK 
    
        FETCH NEXT FROM delete_cursor 
        INTO @PK
    END 
    CLOSE delete_cursor;
    DEALLOCATE delete_cursor;
    

    我不同意这样的评论:
    SQL,它只会对一组以某种方式检测到的孤立记录执行删除?(对于已知FK关系的特定表,很容易做到。一般来说,不太容易做到。)
    我认为,根据定义,只有当记录具有某种外键关系时,它才可能是孤立的,而外键表中的记录被删除了(在这种情况下,基于外部联接选择这些记录总是很容易的)。通常这样做是什么意思?在Oracle中,您可以使用选项
    log errors to
    DELETE
    语句。跨dbms解决方案类似于
    DELETE from foo where id in(select…)
    其中子选择将返回“孤立”行。Mike Brant:我看到的大多数解决方案都非常特定于记录/表定义。您必须知道当前记录的每个父表。“通用解决方案”将能够检测记录或表的外键关系,并且只删除不会导致外键冲突的记录。这与手动指定记录可能与之相关的每个表并执行联接相反。我可以问一下原因吗?您创建FK是为了限制值。为什么需要清除FK表中的值而不是r引用?如果下一次插入是您清除的值,而现在插入失败,该怎么办?布拉姆:这个想法实际上是清除一个不再引用有效外键的记录表。我们正在删除子实体,而不是父实体。这些是孤立的记录,不再属于数据库。如果在生产中使用,我们会尝试至于为什么会发生这种情况,情况可能会有所不同——从测试数据到不成熟的应用程序,到数据库模式更改,再到允许0..n关系而不是1..n关系的数据库模式(在模式中可能有效,但在应用程序中不有效)。回答得很好。我不熟悉游标,所以没有想过使用它们。我可以看出,与我发布的示例相比,这个示例更受欢迎。那么,这怎么不是一个答案呢?这是一个答案,就像其他几个发布到这个问题上的答案一样。