1

我有一个存储某些表名称的表 - tableNames。我想在其中一些表上运行 DELETE 语句(从它们所代表的表中删除所有行,而不是从tableNames中删除它们)。我以为我能做到

DELETE FROM (SELECT tableName FROM tablesNames WHERE ...) AS deleteTables

但我不断收到不正确的语法错误。我还考虑过在 WHILE 循环中遍历表并使用变量进行存储,但我希望有更简单的方法。具体来说,这是针对 Microsoft SQL

4

6 回答 6

5

您不能那样做,因为内部SELECT只是您要从中删除的另一个集合。

基本上,您正在创建一个表名表并告诉数据库将其删除。如果没有动态 sql 和EXEC

你需要自动化这个过程吗?

我过去所做的是这样的

SELECT
    'DELETE ' + tableName
FROM
    tablenames
WHERE
   [conditions]

您的输出将如下所示:

DELETE myTableName1
DELETE myTableName2
DELETE myTableName3

然后只需将此查询的结果复制到窗口外并运行它们。

如果您需要在 SQL 中自动执行此操作,您可以连接结果中的所有输出字符串并将它们作为参数发送给EXEC调用。

于 2013-05-02T17:28:39.807 回答
3

尝试使用光标:

DECLARE @tableName varchar(255)

DECLARE cur cursor for select tableName from tableNames where (...)

OPEN CUR
FETCH NEXT FROM cur into @tableName

WHILE @@FETCH_STATUS = 0
BEGIN
exec('DELETE ' + @tableName)
FETCH NEXT FROM cur into @tableName 
END

CLOSE cur
DEALLOCATE cur
于 2013-05-03T06:25:33.453 回答
3

在这方面,您可以将 SQL 视为类似 C/C++ 的编译语言。SQL 语句由“编译器”评估,并完成某些检查。其中一项检查是查询中直接引用的表和列是否存在(和权限)。在您构建查询时,您的代码中必须存在准确的表名,以便编译器可以对其进行验证。

好消息是 SQL 也是一种动态语言。这意味着您可以编写一个过程以将查询构建为字符串,并告诉数据库使用该EXEC命令执行该字符串。此时,所有相同的“编译器”规则都适用,但由于您能够将表名直接插入 SQL 字符串,因此查询将通过。

问题是这也有安全隐患。最好还检查您的表是否与 类似的资源information_schema.Tables,以避免潜在的注入攻击。不幸的是,如果您要删除整个表,您的整个模型可能已经被怀疑,因此您不能保证有人不会注入您真正想要保留的表名。但取决于这些是如何填充的,你也可能会很好。

于 2013-05-02T17:31:27.873 回答
1

假设不存在潜在的约束错误,一个有趣的可能性是一个未记录的过程sp_MSforeachtable,它将允许您对查询返回名称的所有表应用给定的操作:

EXEC sp_MSforeachtable @command1 = 'delete from ?'
, @whereand = 'and o.name IN (SELECT tableName FROM tablesNames WHERE ...)'

还有http://weblogs.asp.net/nunogomes/archive/2008/08/19/sql-server-undocumented-stored-procedure-sp-msforeachtable.aspx以获取更多信息。

于 2013-05-02T18:46:49.843 回答
0

delete 语句一次只能使用一个表名。

此处记录了完整的语法,但它是 TL;DR... 简而言之,您必须使用循环。

于 2013-05-02T17:26:53.370 回答
0

我正在使用与@Pavel 类似的游标和我的索引列表,以便重新组织它们。像这样的操作是游标的极少数好理由之一。

于 2013-05-13T07:36:44.567 回答