我有一个表存储某些表的名称 - tableNames 。我想在其中一些表上运行DELETE语句(删除它们所代表的表中的所有行,而不是从 tableNames 中删除它们)。我以为我可以做到
DELETE FROM (SELECT tableName FROM tablesNames WHERE ...) AS deleteTables
但是我一直收到错误的语法错误。我还想过迭代WHILE循环中的表并使用变量存储,但我希望有更简单的方法。具体来说,这适用于Microsoft SQL
答案 0 :(得分:5)
你不能那样做,因为内部SELECT
只是你要删除的另一个集合。
基本上你要创建一个表名表并告诉DB删除它。如果没有动态sql和EXEC
您是否需要自动执行此过程?
我过去所做的就是这样的事情
SELECT
'DELETE ' + tableName
FROM
tablenames
WHERE
[conditions]
您的输出将如下所示:
DELETE myTableName1
DELETE myTableName2
DELETE myTableName3
然后只需将此查询的结果复制出窗口并运行它们。
如果您需要在SQL中自动执行此操作,您可以连接结果中的所有输出字符串,并将它们作为参数发送到EXEC
调用。
答案 1 :(得分:3)
在这方面,您可以将SQL视为一种编译语言,如C / C ++。 SQL语句由“编译器”评估,并完成某些检查。其中一项检查是针对查询中直接引用的表和列的存在(和权限)。在构建查询时,代码中存在精确的表名必须,以便编译器可以对其进行验证。
好消息是SQL也是一种动态语言。这意味着您可以编写一个过程来将查询构建为字符串,并告诉数据库使用EXEC
命令执行该字符串。此时,所有相同的“编译器”规则都适用,但由于您能够将表名直接插入到SQL字符串中,因此查询将通过。
问题在于这也具有安全隐患。最好还是针对像information_schema.Tables
这样的资源检查你的表,以避免潜在的注入攻击。不幸的是,如果您要删除整个表格,您的整个模型可能已经被怀疑,这样您就无法保证某人不会注入您真正想要保留的表格名称。但是根据这些人口的填充方式,你也可能没问题。
答案 2 :(得分:2)
尝试使用cursor:
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
答案 3 :(得分:1)
假设不存在潜在的约束错误,一个有趣的可能性是未记录的过程sp_MSforeachtable
,它允许您对查询返回名称的所有表应用给定的操作:
EXEC sp_MSforeachtable @command1 = 'delete from ?'
, @whereand = 'and o.name IN (SELECT tableName FROM tablesNames WHERE ...)'
答案 4 :(得分:0)
delete语句一次只能使用一个表名。
完整语法为documented here,但它是TL; DR ...简而言之,您必须使用循环。
答案 5 :(得分:0)
我正在使用与@Pavel类似的游标以及我的索引列表以重新组织它们。像这样的操作是游标的极少原因之一。