SQL查询从表中删除行

时间:2015-06-09 14:18:05

标签: sql-server

我有一张桌子#temp。 #temp中的数据是数据库中的表名。我希望只显示表有数据的表名。如何在不使用动态SQL的情况下执行此操作?

我的样本数据如下:

create TABLE #temp (Table_Name VARCHAR(50))

 insert into #temp values ('#temp1')
                         ,('#temp2') 
                         ,('#temp3')
                         ,('#temp4')

  create TABLE #temp1 (Col1 int) 
  insert into #temp1 values (1)
                           ,(3) 
                           ,(4) 

  create TABLE #temp2 (Col1 int) 
  insert into #temp2 values (7)
                           ,(9) 
                           ,(6)  

  create TABLE #temp3 (Col1 int) 
  create TABLE #temp4 (Col1 int)                          

我手动删除空白表,如何使用大量空白表的查询来执行此操作?

 DELETE FROM #temp 
 WHERE Table_Name = '#temp3' 
 or Table_Name = '#temp4'

这是我想要的结果

从#temp

中选择*

- 它只显示两个非空白的表名

 DROP TABLE #temp 
 DROP TABLE #temp1
 DROP TABLE #temp2
 DROP TABLE #temp3   
 DROP TABLE #temp4

这是我对此问题的旧查询:

DECLARE @TABLE_NAME VARCHAR(50), @COMMAND VARCHAR(500), @COUNT INT, @COUNTT INT

DECLARE @CountResults TABLE (CountReturned INT)

create TABLE #TABLE_NAME (TABLE_NAME VARCHAR(50))

SELECT @COUNTT= COUNT(*) FROM #temp

WHILE @COUNTT > 0  

  BEGIN
    SELECT TOP 1 @TABLE_NAME = Table_Name FROM #temp
    SET @COMMAND = 'SELECT COUNT(*) FROM ' + @TABLE_NAME  
    INSERT @CountResults EXEC (@COMMAND)
    SET @Count = (SELECT * FROM @CountResults)

    BEGIN TRANSACTION
    DELETE @CountResults 
    ROLLBACK TRANSACTION

    IF(@Count > 0)
       BEGIN
           INSERT INTO #TABLE_NAME VALUES (@TABLE_NAME) 
       END

    DELETE FROM #temp WHERE Table_Name = @TABLE_NAME
    SELECT @COUNTT= COUNT(*) FROM #temp
  END 

  SELECT * FROM   #TABLE_NAME

3 个答案:

答案 0 :(得分:0)

我不知道在没有查询该表的情况下确定表是否为空的任何方法,在您的情况下表示动态SQL。你的评论听起来好像你没关系,但正在寻找一种比使用循环更简洁的方法。这是(有限的)可能性:

declare @sql nvarchar(max);
select @sql = 
    -- coalesce() ensures that UNION ALL is inserted before every SELECT but the first.
    coalesce(@sql + N' union all ', N'') + 

    -- Select each table name. Note that SQL Server allows table names that contain 
    -- single quotes. In this case (or in the case of plain old bad/malicious data in 
    -- #temp), we need to make sure those characters are enclosed within the string
    -- literal we're building.
    N'select ''' + replace(table_name, N'''', N'''''') + 

    -- Use EXISTS to make sure there are one or more records in the table.
    N''' where exists (select 1 from ' + quotename(table_name) + N')'
from #temp;

exec sp_executesql @sql;

这将构建并执行如下所示的查询:

select '#temp1' where exists (select 1 from [#temp1]) 
union all 
select '#temp2' where exists (select 1 from [#temp2]) 
union all 
select '#temp3' where exists (select 1 from [#temp3]) 
union all 
select '#temp4' where exists (select 1 from [#temp4])

这种方法有一些您应该注意的限制:

  1. 如果#temp包含任何不是表或视图名称的字符串,查询将失败。通常情况下,我建议使用object_id()或查询INFORMATION_SCHEMA.TABLES来缓解此问题,但是您使用其他临时表的名称加载#temp这一事实会使事情变得复杂。

    < / LI>
  2. 如果#temp包含明确命名表架构的表名,则查询也将失败,例如: dbo.Stuff,因为quotename()会将其呈现为[dbo.Stuff]而不是[dbo].[Stuff]。但是,如果省略quotename(),如果table_name包含空格或其他有问题的字符,则可能会出现错误和/或破坏行为的风险。

  3. 简而言之,如果您只是想要一些供个人使用的东西,并且可以对#temp中的数据做出某些假设,那么上述内容应该有效。但是如果你想要在任何情况下都能正常安全地运行的东西,那么就需要做一些事情,这样即使你可以避免使用某种循环,这样做也不太可能使事情变得复杂。 / p>

答案 1 :(得分:0)

我有一个不使用动态sql的方法。它使用sysindexes表,根据微软的说法,他们可能会随心所欲地改变它。所以这可能不适合生产系统。但它可能是一个很好的起点。如果源表不是临时表,这也更容易一些,因为临时表的实际名称与用于创建它们的名称不匹配。

此脚本在SQL Server 2008 r2上为我工作。

-- drop table #MyTempTable;
Create table #MyTempTable(Table_Name varchar(50));
insert #MyTempTable values ('#MyTempTable2');
insert #MyTempTable values ('#MyTempTable3');
insert #MyTempTable values ('#MyTempTable4');

Create table #MyTempTable2 (Col1 int);
insert #MyTempTable2 values (1);

Create table #MyTempTable4 (Col1 int);
Create table #MyTempTable3 (Col1 int);


SELECT  * 
FROM    #MyTempTable M1
JOIN    tempdb.sys.tables T ON T.name LIKE (M1.Table_Name + '%')
JOIN    [tempdb].[dbo].[sysindexes] S ON S.id = T.object_id
WHERE   S.rowcnt > 0

这不是一个理想的解决方案,但它满足您的要求。如果您在自己的环境中使用它,它可能会让您深入了解实现更大目标的更好方法。祝你好运。

编辑:sysindexes表中的每个索引都有一个条目。或者在我的示例中,对于堆(没有索引)。因此,如果基表有多个索引,则需要稍微修改查询。也许将JOINWHERE条款更改为WHERE EXISTS SELECT * FROM [tempdb].[dbo].[sysindexes] S WHERE S.id = T.object_id AND S.rowcnt > 0使用它进行游戏,您应该能够得到您所要求的位置。

编辑2:用sysobjects替换sys.tables。

SELECT  * 
FROM    #MyTempTable M1
JOIN    [tempdb].[dbo].[sysobjects] O ON O.name LIKE (M1.Table_Name + '%')
JOIN    [tempdb].[dbo].[sysindexes] S ON S.id = O.id
WHERE   S.rowcnt > 0

答案 2 :(得分:-1)

基于DeadZone的查询,以下适用于非临时表:

SELECT  DISTINCT Table_Name 
INTO #TABLE_NAME
FROM    #Temp M1
   JOIN    [dbo].[sysobjects] O ON O.name LIKE (M1.Table_Name + '%')
   JOIN    [dbo].[sysindexes] S ON S.id = O.id
WHERE   S.rowcnt > 0