【问题标题】:How to delete every row that can be deleted?如何删除可以删除的每一行?
【发布时间】:2015-07-11 01:41:41
【问题描述】:

SQL Server 中有没有一种方法可以删除每一行可删除的行(没有阻止删除的外键),而不必知道每个外键引用?

我知道我可以用WHERE ID NOT IN (..)LEFT OUTER JOIN 来检查每个约束,但是有没有类似的东西

DELETE * FROM MyTable WITH CONTINUE_ON_ERROR

这会简单地尝试删除每条记录,如果发生错误忽略它并继续下一条记录而不回滚事务?

【问题讨论】:

  • 不,没有这样的功能。如果你想删除,你的工作确保这些行没有从某处被引用
  • 似乎是一个奇怪的请求。您怎么知道您没有删除今天未使用但将来可能需要它的 FK?
  • 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。
  • "有没有办法...?" 是的。有内置的或简单的方法吗?不,您需要为此编写自己的代码..

标签: sql-server tsql transactions delete-row sql-delete


【解决方案1】:

您可以通过 cursor 使用 try catch 块来执行此操作:

DECLARE @id int

DECLARE curs CURSOR FAST_FORWARD
FOR
    SELECT  ID
    FROM    MyTable

OPEN curs
FETCH NEXT FROM curs INTO @id
WHILE @@FETCH_STATUS = 0
    BEGIN


        BEGIN TRY
            DELETE  FROM MyTable
            WHERE   id = @id
        END TRY
        BEGIN CATCH
        END CATCH


        FETCH NEXT FROM curs INTO @id
    END


CLOSE curs
DEALLOCATE curs

【讨论】:

  • 这也是我想到的,但知道它对于任何大小的桌子都会很慢。
【解决方案2】:

我编写了一些 SQL,它会为您编写所有连接,然后返回连接不匹配的地方。把它指向你的桌子。然后,如果您想删除,请从您的表中删除 pk_col IN(我的动态创建的查询)

DECLARE @TableName          VARCHAR(100) = 'yourTable',
        @LeftJoins          VARCHAR(MAX),
        @WherePredicates    VARCHAR(MAX);

WITH CTE_FK_PK
AS
(
    SELECT
        FK_Table = FK.TABLE_NAME,
        FK_Column = CU.COLUMN_NAME,
        PK_Table = PK.TABLE_NAME,
        PK_Column = PT.COLUMN_NAME
    FROM
        INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
    INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK
        ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
    INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK
        ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
    INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU
        ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
    INNER JOIN (
                SELECT
                    i1.TABLE_NAME,
                    i2.COLUMN_NAME
                FROM
                    INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
                INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2
                    ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
                WHERE
                    i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
               ) PT
        ON PT.TABLE_NAME = PK.TABLE_NAME
    WHERE PK.TABLE_NAME = @TableName
)


SELECT  @LeftJoins = COALESCE(@LeftJoins + CHAR(10),'') + 'LEFT JOIN ' + FK_Table + ' ON ' + FK_Table + '.' + FK_Column + ' = ' + PK_Table + '.' + PK_Column,
        @WherePredicates = COALESCE(@WherePredicates + CHAR(10) + 'AND ','') + FK_Table + '.' + FK_Column + ' IS NULL '
FROM CTE_FK_PK

SELECT 
'SELECT pk_col
FROM ' + @TableName + '
' + @LeftJoins + '
WHERE ' + @WherePredicates

【讨论】:

    【解决方案3】:

    如果您确实需要这样做,请检查每个约束。

    您可以使用游标遍历每个条目并将其包装在 try catch 但是这太可怕了,会给您和任何必须支持您的应用程序/数据库的人带来痛苦和痛苦。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-28
      • 2019-02-05
      • 1970-01-01
      相关资源
      最近更新 更多