使用一个联接查询多个表

时间:2018-09-04 13:05:51

标签: sql sql-server

我需要查询多个包含列名称'idClient'的特定条件的表。

到目前为止,我已经使用以下查询获取了需要查询的表:

SELECT c.name  AS 'ColumnName',
       t.name AS 'TableName'
FROM        sys.columns c (nolock)
JOIN        sys.tables  t   (nolock) ON c.object_id = t.object_id
WHERE       c.name LIKE '%idClient%'
ORDER BY    TableName,
            ColumnName;

这给了我以下结果(实际上大约返回了100张表):

+------------+-----------------+
| ColumnName |    TableName    |
+------------+-----------------+
| idClient   | tbClient        |
| idClient   | tbClientContact |
| idClient   | tbInvoice       |
+------------+-----------------+

为了让我在每个表中都能找到所有的客户记录,我目前正在为每个表名运行3个单独的查询。例如:

SELECT * FROM tbClientContact (nolock)
    JOIN tbClient (nolock)
        ON tbClientContact.idClient = tbClient.idClient
WHERE tbClient.vcSurname = 'Smith'

代替对每个表运行上述查询3次,有没有更简单的方法对作为TableName返回的所有结果运行相同的查询?

目标:在上述示例中,我的任务是从客户姓氏为“ Smith”的数据库中删除所有客户记录。我正在运行上面的SELECT查询,以查找所有姓为“ Smith”的客户机的idClient是否将孤儿记录留在表中有“ idClient”链接的表中。我正在加入tbClient,因为除了tbClient之外,其他任何表中都不存在vcSurname列。

4 个答案:

答案 0 :(得分:3)

您可以尝试

SELECT idClient FROM tbClient WHERE vcSurname = 'Smith'
UNION ALL
SELECT idClient FROM tbClientContact WHERE vcSurname = 'Smith'
UNION ALL
SELECT idClient FROM tbInvoice  WHERE vcSurname = 'Smith'

如果您需要更多的列输出,则所有三个查询必须具有相同数量的输出列并且所有类型都相同

修改 正如其他人所建议的那样,知道您在做什么将很有帮助,因为您尝试的方法绝不是做某事的最佳方法。但是,下面的游标解决方案应构建一个动态查询以执行您想要的

DECLARE @table AS NVARCHAR(128)
DECLARE @sql AS NVARCHAR(4000)

DECLARE c CURSOR FOR
    -- hey all the tables with the columns LIKE '%idClient%'
    SELECT t.name AS 'TableName'
    FROM        sys.columns c (nolock)
    JOIN        sys.tables  t   (nolock) ON c.object_id = t.object_id
    WHERE       c.name LIKE '%idClient%'
    ORDER BY    TableName


-- loop through the results of the query line by line
OPEN c
FETCH NEXT FROM c INTO @table

WHILE @@FETCH_STATUS = 0
BEGIN

    -- build the query dynamically
    SET @sql =CONCAT(@sql,'SELECT idClient FROM ' + @table +  ' WHERE vcSurname = ''Smith'' UNION ALL ')
    FETCH NEXT FROM c INTO @table
END

-- remove last "UNION ALL" text
SET @sql = STUFF(@sql,LEN(@sql)-9,11,'')
EXEC sp_executesql @stmt = @sql

CLOSE c
DEALLOCATE c

编辑编辑 刚刚看到了您的修改。您的表是否具有外键/主键对,外键是否具有ON DELETE CASCADE?如果是这样,应该只是

DELETE from tbClient WHERE vcSurname = 'Smith'

答案 1 :(得分:2)

对于自动查询:

提问后修改:

SELECT 'SELECT '+c.name+' FROM '+t.name+' T WITH(nolock)
    JOIN tbClient (NOLOCK)
        ON T.idClient = tbClient.idClient
WHERE vcSurname = ''Smith''
        UNION ALL
        '
FROM        sys.columns c (nolock)
JOIN        sys.tables  t   (nolock) ON c.object_id = t.object_id
WHERE       c.name LIKE '%idClient%'

以文本格式(ctrl + T)打印结果。 复制完整的结果,然后删除最后一个UNION ALL

答案 2 :(得分:1)

1通过查询systable(sysforeignkeyssyscolumns(如果您没有FK)来确定涉及的表。

2手动编写一个用于完成所有操作的全面存储过程

create proc dbo.Client_Del
  @client_id int
as
begin try
  if not exists(select 1 from dbo.Client c where c.id = @client_id)
    raiserror("Client %d not found", 16, 1, @client_id)

  begin tran

  delete ct
  from dbo.ClientContacts ct
  where ct.client_id = @client_id

  delete idt
  from dbo.InvoiceDetail idt
  inner join dbo.Invoice i
     on i.invoice_id = idt.invoice_id
  where i.client_id = @client_id

  delete i
  from dbo.Invoice i
  where i.client_id = @client_id

  delete c
  from dbo.Client c
  where c.client_id = @client_id

  commit tran
end try
begin catch
  if @@trancount > 0
     rollback tran
  throw
end catch
GO

3使用参数调用存储的proc

declare @id int

set @id = (select c.client_id from dbo.Client c where c.LastName = 'Smith')

exec dbo.Client_Del
  @client_id = @id

答案 3 :(得分:0)

  

我不确定您需要什么。这篇文章是@Luv的增强代码。使用它,您只需运行它即可。

declare @select nvarchar(max) = N''
set @select = 
N'
declare @sql nvarchar(max) = N''''
SELECT @sql += '' UNION ALL SELECT ''+c.name+'' FROM ''+t.name+'' T WITH(nolock)
    JOIN tbClient (NOLOCK)
        ON T.idClient = tbClient.idClient
WHERE vcSurname = ''''Smith''''''
FROM        sys.columns c (nolock)
JOIN        sys.tables  t   (nolock) ON c.object_id = t.object_id
WHERE       c.name LIKE ''%yourColumnName%'' 
set @sql = STUFF(@sql, 1, 10, '''')
print @sql
exec sp_executesql @sql
'
exec sp_executesql @select