我有一个包含列ID的帐户表,
来自所有@ID
,并将其保存为查询以供以后使用
(我有数千个账户)
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
我发现这样的东西生成一个flex查询来检索要执行的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
我想选择所有帐户,如果它存在然后联合在一起,并且将有数千个帐户,其中一些存在,一些不存在,
现在这种情况下的联盟不起作用。还有另一种方法吗?非常感谢
不确定“查询以供以后使用”是什么意思。您可以使用下面的简单查询为所有表生成选择查询 -
Select CONCAT('select * from u5_data.data.Mailtable_', ID) from Account
它将生成如下输出,您可以将其保存在文件中供以后使用。
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
这很有趣; I just tweeted today关于我作为SQL开发人员20多年来遇到的最糟糕的数据库设计,这个问题听起来非常相似。听起来你有一堆除了名称之外相同的表,并且名称代表你想要为其检索数据的实体。您现在尝试将其作为批处理执行,因此对于存储在帐户中的每个实体,您希望为这些帐户提取(我假设的)单个数据集。
这可以通过几种不同的方式完成,所有这些都是hackish。如果您对此数据库的设计有任何影响,请尝试找出重构它的方法。我为此示例选择了CURSOR路由,但也可以使用视图或单个动态SQL语句来完成。但是,这两个选项只有在表的数量很小的情况下才会起作用(过去我已经完成了90个表或更少的表)。因为我不知道,这是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]
简而言之,您遍历accounts表中的每个值并编写动态SQL语句。您可以按ID执行它,并将该SQL语句的输出插入临时表,然后从该临时表中选择结果。
你不能在SQL中参数化对象标识符(即你不能使用SqlParameter
),你必须使用“动态SQL” - 这意味着你必须小心避免SQL注入。
假设您必须完全在T-SQL中执行此操作,那么我强烈建议使用SQL Server 2017,因为它引入了非常有用的STRING_AGG
函数(相当于MySQL的GROUP_CONCAT
函数)。
像这样:
DECLARE @sql varchar(max)
SELECT
@sql = STRING_AGG( CONCAT( 'SELECT * FROM ', [ID] ), CHAR(13) + CHAR(10) )
FROM
Accounts
EXECUTE sp_executesql @sql
使用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
找到了答案
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