简体   繁体   English

在SQL Server中将所有选择查询与动态表名称合并

[英]Union all select query with a dynamic table name in SQL Server

I have an account table with column ID, 我有一个带有列ID的帐户表,

from all the @ID , and save it as a query to run for later use 从所有@ID ,并将其另存为查询以供以后使用

(I have thousand of accounts) (我有数千个帐户)

ID
------------------------------------
8C76EF27-3080-4DAA-881B-08CD2A1A558F
62FFCB40-AAB4-47A5-953A-08CD2A1A6A43
CFFD7C3C-FEFC-4E97-9970-08CD2A1A3A60
0F5ADAF3-32EF-4D43-BFBD-08CD2A1A5D88
4130153C-24C1-4914-A6F1-08CD2A16DF59

I have found something like this to generate a flex query to retrieve column ID in the sql to be executed like 我发现这样的东西可以生成一个弹性查询来检索要执行的sql中的列ID

with getAllAccount as(
select B.ID,B.DisplayName from (
select ID,DisplayName from u3_system.[dbo].[Account] with (nolock)
where ID = '8c76ef27-3080-4daa-881b-08cd2a1a555f' or ParentID = '8c76ef27-3080-4daa-881b-08cd2a1a555f') A
join u3_system.[dbo].[Account] B with (nolock)
on A.ID = B.ParentID
union 
select ID,DisplayName from u3_system.[dbo].[Account] with (nolock)
where ID = '8c76ef27-3080-4daa-881b-08cd2a1a555f'
)

--create pre script
Select 'if exists (select * from sys.tables where name = ''Maillog_' + replace(getAllAccount.ID,'-','') + ') begin Select CampaignID,mailoutID,deliveryDate from  u3_data.data.Maillog_' + replace(getAllAccount.ID,'-','') + ' with(nolock) end union '
from getAllAccount

I want to select all the account if its exists then union together, and there will be thousands of account, some of them exists, some not, 我想选择所有存在的帐户,然后合并在一起,将有成千上万个帐户,其中一些存在,一些不存在,

Now the union in this case doesnt work. 现在工会在这种情况下不起作用。 Is there another way to do it? 还有另一种方法吗? thanks very much 非常感谢

Not sure what do you mean by "query for later use". 不确定“查询供以后使用”是什么意思。 You can generate select queries for all tables with a simple query like below - 您可以使用以下简单查询为所有表生成选择查询-

Select CONCAT('select * from  u5_data.data.Mailtable_', ID)  from Account

It will generate the output as below, which you can save it in file for later use. 它将生成如下输出,您可以将其保存在文件中以备后用。

select * from  u5_data.data.Mailtable_8C76EF27-3080-4DAA-881B-08CD2A1A558F
select * from  u5_data.data.Mailtable_62FFCB40-AAB4-47A5-953A-08CD2A1A6A43
select * from  u5_data.data.Mailtable_CFFD7C3C-FEFC-4E97-9970-08CD2A1A3A60
select * from  u5_data.data.Mailtable_0F5ADAF3-32EF-4D43-BFBD-08CD2A1A5D88
select * from  u5_data.data.Mailtable_4130153C-24C1-4914-A6F1-08CD2A16DF59

It's funny; 这很有趣; I just tweeted today about the worst database design I've ever encountered in my 20+ years as a SQL developer, and this question sounds eerily similar. 我今天在Twitter上发布了有关我20多年来作为SQL开发人员所遇到的最糟糕的数据库设计的推文 ,这个问题听起来很相似。 It sounds like you have a bunch of tables that are identical except for the name, and the name represents an entity that you want to retrieve data for. 听起来好像您有一堆表,除了名称相同,而且名称代表您要为其检索数据的实体。 You're now trying to do it as a batch, so for every entity stored in accounts, you want to pull back a (I assume) single data-set for those accounts. 您现在正尝试批量执行此操作,因此对于帐户中存储的每个实体,您都希望为这些帐户拉回(我假设为)单个数据集。

This can be done in a couple of different ways, all of them hackish. 这可以通过几种不同的方式来完成,所有这些方式都令人生厌。 If you have any influence over the design of this database, try to figure out a way to refactor it. 如果对该数据库的设计有影响,请尝试找出一种重构它的方法。 I chose the CURSOR route for this sample, but it might also be done using a view or a single dynamic SQL statement. 我为此示例选择了CURSOR路由,但也可以使用视图或单个动态SQL语句来完成。 Those two options, however, will only work if the number of tables are small (I've done it with 90 tables or less in the past). 但是,这两个选项仅在表的数量较小时才起作用(我过去使用90个或更少的表来完成)。 Since I don't know that, here's the CURSOR. 由于我不知道,所以这里是CURSOR。

 USE tempdb;

/*set up demo up here*/
CREATE TABLE Account (ID uniqueidentifier)

INSERT INTO Account (ID)
VALUES ('8C76EF27-3080-4DAA-881B-08CD2A1A558F'),
('62FFCB40-AAB4-47A5-953A-08CD2A1A6A43'),
('CFFD7C3C-FEFC-4E97-9970-08CD2A1A3A60'),
('0F5ADAF3-32EF-4D43-BFBD-08CD2A1A5D88'),
('4130153C-24C1-4914-A6F1-08CD2A16DF59')

--these are not temp tables; be sure to clean up.  naming has hyphens
CREATE TABLE [MT_4130153C-24C1-4914-A6F1-08CD2A16DF59] (val varchar(20))
CREATE TABLE [MT_CFFD7C3C-FEFC-4E97-9970-08CD2A1A3A60] (val varchar(20))
CREATE TABLE [MT_8C76EF27-3080-4DAA-881B-08CD2A1A558F] (val varchar(20))
CREATE TABLE [MT_0F5ADAF3-32EF-4D43-BFBD-08CD2A1A5D88] (val varchar(20))
CREATE TABLE [MT_62FFCB40-AAB4-47A5-953A-08CD2A1A6A43] (val varchar(20))

INSERT INTO [MT_4130153C-24C1-4914-A6F1-08CD2A16DF59] VALUES ('This')
INSERT INTO [MT_CFFD7C3C-FEFC-4E97-9970-08CD2A1A3A60] VALUES ('is')
INSERT INTO [MT_8C76EF27-3080-4DAA-881B-08CD2A1A558F] VALUES ('a')
INSERT INTO [MT_0F5ADAF3-32EF-4D43-BFBD-08CD2A1A5D88] VALUES ('bad')
INSERT INTO [MT_62FFCB40-AAB4-47A5-953A-08CD2A1A6A43] VALUES ('design')


/*magic starts here*/
CREATE TABLE #output (val varchar(20), id uniqueidentifier)

DECLARE @sql nvarchar(200), @Id varchar(50)

DECLARE c CURSOR FOR
SELECT CONVERT(VARCHAR(50), ID) FROM account 

OPEN C

FETCH NEXT FROM C INTO @ID
WHILE @@FETCH_STATUS = 0
BEGIN 

SET @SQL = 'SELECT val, ''' + @ID + ''' FROM [MT_' + @ID + ']'      

INSERT INTO #output (val, id)
exec sp_executesql @SQL


FETCH NEXT FROM C INTO @ID
END

CLOSE C
DEALLOCATE C


/*output comes next*/
SELECT *
FROM #output
ORDER BY ID

DROP TABLE #output


/*clean up demo*/
DROP TABLE Account

DROP TABLE [MT_4130153C-24C1-4914-A6F1-08CD2A16DF59]
DROP TABLE [MT_CFFD7C3C-FEFC-4E97-9970-08CD2A1A3A60]
DROP TABLE [MT_8C76EF27-3080-4DAA-881B-08CD2A1A558F]
DROP TABLE [MT_0F5ADAF3-32EF-4D43-BFBD-08CD2A1A5D88]
DROP TABLE [MT_62FFCB40-AAB4-47A5-953A-08CD2A1A6A43]

Long story short, you iterate through each value in the accounts table and write a dynamic SQL statement. 简而言之,您遍历accounts表中的每个值并编写动态SQL语句。 You execute it per ID, and insert the output of that SQL statement into a temporary table, and then select the results from that temp table. 您按ID执行它,并将该SQL语句的输出插入临时表中,然后从该临时表中选择结果。

Below Script using Cursor 下面的脚本使用光标

create table tbl(ID varchar(max))
insert into tbl values('8C76EF27-3080-4DAA-881B-08CD2A1A558F')
insert into tbl values('62FFCB40-AAB4-47A5-953A-08CD2A1A6A43')
insert into tbl values('CFFD7C3C-FEFC-4E97-9970-08CD2A1A3A60')
insert into tbl values('0F5ADAF3-32EF-4D43-BFBD-08CD2A1A5D88')
insert into tbl values('4130153C-24C1-4914-A6F1-08CD2A16DF59')


DECLARE @sql varchar(max)
SELECT  CONCAT('SELECT * FROM ',[ID], CHAR(13) + CHAR(10)  ) as execRecord
into #tmp
from tbl
select * from #tmp

    DECLARE ID_Cursor CURSOR FOR
        SELECT execRecord from #tmp
    DECLARE @tmpID varchar(max)
    OPEN ID_Cursor   
        FETCH NEXT FROM ID_Cursor INTO @tmpID
        WHILE @@FETCH_STATUS = 0   
        BEGIN   
            SET @sql = @tmpID
            EXECUTE SP_EXECUTESQL @sql
            SET @sql = ''
            FETCH NEXT FROM ID_Cursor INTO @tmpID  
        END   

    CLOSE ID_Cursor   
    DEALLOCATE ID_Cursor

DROP TABLE #tmp
DROP TABLE tbl

You cannot parameterise object identifiers in SQL (ie you cannot use SqlParameter for this), you must use "Dynamic SQL" - which means you have to be careful to avoid SQL Injection. 您不能在SQL中参数化对象标识符(即,不能为此使用SqlParameter ),必须使用“动态SQL”-这意味着您必须小心避免SQL注入。

Assuming you have to do this entirely in T-SQL, then I strongly recommend using SQL Server 2017 because it introduces the very useful STRING_AGG function (equivalent to MySQL's GROUP_CONCAT function). 假设您必须完全在T-SQL中执行此操作,那么我强烈建议您使用SQL Server 2017,因为它引入了非常有用的 STRING_AGG函数(相当于MySQL的GROUP_CONCAT函数)。

Like so: 像这样:

DECLARE @sql varchar(max)

SELECT
    @sql = STRING_AGG( CONCAT( 'SELECT * FROM ', [ID] ), CHAR(13) + CHAR(10) )
FROM
    Accounts

EXECUTE sp_executesql @sql

Found the answer 找到了答案

Select * from 
(   Select case when exists (select * from sys.tables where name = 'Maillog_' + replace(getAllAccount.ID,'-',''))
        Then 'Select CampaignID,mailoutID,deliveryDate from  u3_data.data.Maillog_' + replace(getAllAccount.ID,'-','') + ' with(nolock) union ' End execQuery
    from getAllAccount
) A
where execQuery is not null

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM