使用动态查询字符串连接多个表
Using dynamic query string to join multiple tables
在我的数据库中的 4 个不同的 table 中找到了数千个代码。我创建了一个临时 table 来插入所有代码和相应的 table 名称,其中可以找到该代码。作为示例,我展示了一小部分临时 table。
代码 | table_name
DA | StatsCanCensus2011_1
DWAPT5L | StatsCanCensus2011_3
DWAPT5O | StatsCanCensus2011_3
DWDUP | StatsCanCensus2011_3
DWMOVA | StatsCanCensus2011_3
我正在尝试编写一个查询,我可以在其中动态 select 代码并在代码 selected 来自不同的 tables 时加入 tables .我能够轻松地在 2 table 秒内执行此操作,但是当有 3 或 4 个时,它就无法解决了。
下面将给出当需要加入 2 table 时我需要的结果:
declare @code nvarchar(15), @tblname nvarchar(30), @strSQL nvarchar(max), @strWhere nvarchar(max)
DECLARE db_cursor CURSOR FOR
select code, table_name from tmpVarList2
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @code, @tblname
set @strSQL='select'
WHILE @@FETCH_STATUS = 0
BEGIN
print @code + @tblname
set @strSQL=@strSQL + ' ' + @code + ','
FETCH NEXT FROM db_cursor INTO @code, @tblname
END
set @strSQL=left(@strSQL, len(@strSQL)-1)
print @strSQL
CLOSE db_cursor
DEALLOCATE db_cursor
set @strSQL=@strSQL + ' from'
set @strWhere=' where '
DECLARE db_cursor CURSOR FOR
select distinct table_name from tmpVarList2
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @tblname
WHILE @@FETCH_STATUS = 0
BEGIN
print @code + @tblname
set @strSQL=@strSQL + ' ' + @tblname + ','
set @strWhere=@strWhere + @tblname + '.da='
FETCH NEXT FROM db_cursor INTO @tblname
END
set @strSQL=left(@strSQL, len(@strSQL)-1)
set @strWhere=left(@strWhere, len(@strWhere)-1)
set @strSQL=@strSQL + @strWhere
SELECT @strSQL
CLOSE db_cursor
DEALLOCATE db_cursor
结果:
select DA, DWAPT5L, DWAPT5O, DWDUP, DWMOVA
from StatsCanCensus2011_1, StatsCanCensus2011_3
where StatsCanCensus2011_1.da=StatsCanCensus2011_3.da
有 3 table 加入时的结果示例:
select DA, DWAPT5L, FMCLNOCH,FMCPINTO, FMCPSZAV, FMCPTIAV, FMCPTIME, FMHHTOT
from StatsCanCensus2011_1, StatsCanCensus2011_3, StatsCanNHS2011_4
where StatsCanCensus2011_1.da=StatsCanCensus2011_3.da=StatsCanNHS2011_4.da
使用游标 assemble 并执行动态 sql 查询是雄心勃勃的,但这意味着永远无法缓存执行路径。此外,如果这些很大 tables(人口普查数据往往如此),您可能会遇到一些真正的优化挑战。有了标准的 DBA 唠叨,这实际上是一个非常有趣的想法,因为它听起来很糟糕但实际上并没有那么糟糕(因为光标从不接触数据)。
我认为您的方法是正确的,但您试图让每个游标做太多事情。您所需的查询分为三个部分,一个包含列列表的 select 语句,一个包含连接 table 列表的 from 语句,以及一个包含连接这些 [=] 逻辑的 where 语句25=]s(隐式加入它们而不是显式加入)。那么为什么不用三个光标,每个光标都集中在一个特定区域。它让每一个游标的构造变得简单很多,然后你就可以组合最终的结果。
declare @select_Code varchar(max)
declare @Select_column varchar(max)
declare @selectloop int
declare @From_Code varchar(max)
declare @From_Column varchar(max)
declare @FromLoop int
declare @Where_Code Varchar(max)
create table #temp (columnname varchar(128), tablename Varchar(128))
insert into #temp
select 'ColumnA', 'TableA'
union
select 'Columnb', 'TableB'
union
select 'Columnc', 'TableC'
--drop table #temp
set @select_Code = 'Select '
set @selectloop = 0
declare select_cursor cursor for
select columnname from #temp
Open select_cursor
fetch next from select_cursor
into @Select_column
while @@FETCH_STATUS = 0
begin
set @select_Code = @select_Code + (select case when @selectloop > 0 then ', ' else '' end as CommaOrNot) + @Select_column
set @selectloop = @selectloop + 1
fetch next from select_cursor into @Select_column
end
close select_cursor
deallocate select_cursor
set @From_Code = ' From '
set @FromLoop = 0
declare From_cursor cursor for
select tablename from #temp
Open From_cursor
fetch next from From_cursor
into @from_column
while @@FETCH_STATUS = 0
begin
set @From_Code = @From_Code + (select case when @FromLoop > 0 then ', ' else '' end as CommaOrNot) + @from_column
set @FromLoop = @FromLoop + 1
fetch next from From_cursor into @from_column
end
close From_cursor
deallocate From_cursor
select @select_Code + @From_Code
我会让你做 where 子句,因为我不确定你是否正在菊花链式连接它们,或者它们是否都连接回第一个 table,无论哪个都遵循相同的模式,您只需要将 case 语句更新为类似的内容;
case when @whereloop > 0 and @whereloop % 2 = 0 then ' and '
when @whereloop > 0 and @whereloop % 2 = 1 then ' = '
else '' end as EqualsOrNewJoin
对于 select 和 from 语句,我使用循环号来确定是否需要在现有代码和新部分之间的连接之前添加逗号。对于 where 子句,它有点棘手,它需要在 x = y 和 y = z 的位置。因此,我使用 mod 来获取循环编号的其余部分,以确定循环是奇数还是偶数,一旦我们超过了第一个(循环 0)。如果它是奇数(循环 1,这是第二个条目),我知道它们之间应该有一个 = 符号,例如:Loop0 = loop1。如果它甚至我知道我们正在 statring 一个新的 where 条件,所以我需要使用和。无论如何希望这对您有所帮助,如果您有任何问题,请告诉我。
您也可以尝试以下命令:
CREATE Temp Table Adv_Search_Trails(Parameter_Name Text, Parameter_Value Text,Condition Text,Table_Name Text )
INSERT INTO Adv_Search_Trails
SELECT 'trial_therapeutic_area_id','5','AND','trial_ta_filterview'
UNION ALL SELECT 'Primary_Drug','6','AND','trial_drugid_filterview'
UNION ALL SELECT 'collaborator_id','7','AND','trial_status_filterview'
UNION ALL SELECT 'maximum_age','8','OR','trial_patient_filterview'
UNION ALL SELECT 'designkeyword_id','9','OR','trial_key_filterview'
DECLARE @select_Code NVARCHAR(max)
DECLARE @Select_column VARCHAR(max)
DECLARE @selectloop INT
DECLARE @From_Code VARCHAR(max)
DECLARE @From_Column VARCHAR(max)
DECLARE @FromLoop INT
SET @select_Code = ' where '
SET @selectloop = 0
DECLARE select_cursor CURSOR
FOR
SELECT Parameter_Name
FROM Adv_Search_Trails
OPEN select_cursor
FETCH NEXT
FROM select_cursor
INTO @Select_column
WHILE @@FETCH_STATUS = 0
BEGIN
SET @select_Code = @select_Code + (
SELECT CASE
WHEN @selectloop > 0
THEN (
SELECT Condition
FROM Adv_Search_Trails
WHERE Parameter_Name = @Select_column
)
ELSE ''
END AS CommaOrNot
) + ' ' + @Select_column + ' = ' + (
SELECT Parameter_Value
FROM Adv_Search_Trails
WHERE Parameter_Name = @Select_column
) + ' '
SET @selectloop = @selectloop + 1
FETCH NEXT
FROM select_cursor
INTO @Select_column
END
CLOSE select_cursor
DEALLOCATE select_cursor
SET @From_Code = ' from '
SET @FromLoop = 0
DECLARE From_cursor CURSOR
FOR
SELECT Table_Name
FROM Adv_Search_Trails
OPEN From_cursor
FETCH NEXT
FROM From_cursor
INTO @from_column
WHILE @@FETCH_STATUS = 0
BEGIN
SET @From_Code = @From_Code + (
SELECT CASE
WHEN @FromLoop > 0
THEN ' INNER JOIN ' + @from_column+ ' ON ' + (SELECT TOP 1 table_name from Adv_Search_Trails)+'.ID '+' = ' +@from_column +'.ID'
ELSE @from_column
END AS CommaOrNot
)
SET @FromLoop = @FromLoop + 1
FETCH NEXT
FROM From_cursor
INTO @from_column
END
CLOSE From_cursor
DEALLOCATE From_cursor
SELECT 'select ' +@from_column+'.ID '+ @From_Code + @select_Code
在我的数据库中的 4 个不同的 table 中找到了数千个代码。我创建了一个临时 table 来插入所有代码和相应的 table 名称,其中可以找到该代码。作为示例,我展示了一小部分临时 table。
代码 | table_name
DA | StatsCanCensus2011_1
DWAPT5L | StatsCanCensus2011_3
DWAPT5O | StatsCanCensus2011_3
DWDUP | StatsCanCensus2011_3
DWMOVA | StatsCanCensus2011_3
我正在尝试编写一个查询,我可以在其中动态 select 代码并在代码 selected 来自不同的 tables 时加入 tables .我能够轻松地在 2 table 秒内执行此操作,但是当有 3 或 4 个时,它就无法解决了。
下面将给出当需要加入 2 table 时我需要的结果:
declare @code nvarchar(15), @tblname nvarchar(30), @strSQL nvarchar(max), @strWhere nvarchar(max)
DECLARE db_cursor CURSOR FOR
select code, table_name from tmpVarList2
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @code, @tblname
set @strSQL='select'
WHILE @@FETCH_STATUS = 0
BEGIN
print @code + @tblname
set @strSQL=@strSQL + ' ' + @code + ','
FETCH NEXT FROM db_cursor INTO @code, @tblname
END
set @strSQL=left(@strSQL, len(@strSQL)-1)
print @strSQL
CLOSE db_cursor
DEALLOCATE db_cursor
set @strSQL=@strSQL + ' from'
set @strWhere=' where '
DECLARE db_cursor CURSOR FOR
select distinct table_name from tmpVarList2
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @tblname
WHILE @@FETCH_STATUS = 0
BEGIN
print @code + @tblname
set @strSQL=@strSQL + ' ' + @tblname + ','
set @strWhere=@strWhere + @tblname + '.da='
FETCH NEXT FROM db_cursor INTO @tblname
END
set @strSQL=left(@strSQL, len(@strSQL)-1)
set @strWhere=left(@strWhere, len(@strWhere)-1)
set @strSQL=@strSQL + @strWhere
SELECT @strSQL
CLOSE db_cursor
DEALLOCATE db_cursor
结果:
select DA, DWAPT5L, DWAPT5O, DWDUP, DWMOVA
from StatsCanCensus2011_1, StatsCanCensus2011_3
where StatsCanCensus2011_1.da=StatsCanCensus2011_3.da
有 3 table 加入时的结果示例:
select DA, DWAPT5L, FMCLNOCH,FMCPINTO, FMCPSZAV, FMCPTIAV, FMCPTIME, FMHHTOT
from StatsCanCensus2011_1, StatsCanCensus2011_3, StatsCanNHS2011_4
where StatsCanCensus2011_1.da=StatsCanCensus2011_3.da=StatsCanNHS2011_4.da
使用游标 assemble 并执行动态 sql 查询是雄心勃勃的,但这意味着永远无法缓存执行路径。此外,如果这些很大 tables(人口普查数据往往如此),您可能会遇到一些真正的优化挑战。有了标准的 DBA 唠叨,这实际上是一个非常有趣的想法,因为它听起来很糟糕但实际上并没有那么糟糕(因为光标从不接触数据)。
我认为您的方法是正确的,但您试图让每个游标做太多事情。您所需的查询分为三个部分,一个包含列列表的 select 语句,一个包含连接 table 列表的 from 语句,以及一个包含连接这些 [=] 逻辑的 where 语句25=]s(隐式加入它们而不是显式加入)。那么为什么不用三个光标,每个光标都集中在一个特定区域。它让每一个游标的构造变得简单很多,然后你就可以组合最终的结果。
declare @select_Code varchar(max)
declare @Select_column varchar(max)
declare @selectloop int
declare @From_Code varchar(max)
declare @From_Column varchar(max)
declare @FromLoop int
declare @Where_Code Varchar(max)
create table #temp (columnname varchar(128), tablename Varchar(128))
insert into #temp
select 'ColumnA', 'TableA'
union
select 'Columnb', 'TableB'
union
select 'Columnc', 'TableC'
--drop table #temp
set @select_Code = 'Select '
set @selectloop = 0
declare select_cursor cursor for
select columnname from #temp
Open select_cursor
fetch next from select_cursor
into @Select_column
while @@FETCH_STATUS = 0
begin
set @select_Code = @select_Code + (select case when @selectloop > 0 then ', ' else '' end as CommaOrNot) + @Select_column
set @selectloop = @selectloop + 1
fetch next from select_cursor into @Select_column
end
close select_cursor
deallocate select_cursor
set @From_Code = ' From '
set @FromLoop = 0
declare From_cursor cursor for
select tablename from #temp
Open From_cursor
fetch next from From_cursor
into @from_column
while @@FETCH_STATUS = 0
begin
set @From_Code = @From_Code + (select case when @FromLoop > 0 then ', ' else '' end as CommaOrNot) + @from_column
set @FromLoop = @FromLoop + 1
fetch next from From_cursor into @from_column
end
close From_cursor
deallocate From_cursor
select @select_Code + @From_Code
我会让你做 where 子句,因为我不确定你是否正在菊花链式连接它们,或者它们是否都连接回第一个 table,无论哪个都遵循相同的模式,您只需要将 case 语句更新为类似的内容;
case when @whereloop > 0 and @whereloop % 2 = 0 then ' and '
when @whereloop > 0 and @whereloop % 2 = 1 then ' = '
else '' end as EqualsOrNewJoin
对于 select 和 from 语句,我使用循环号来确定是否需要在现有代码和新部分之间的连接之前添加逗号。对于 where 子句,它有点棘手,它需要在 x = y 和 y = z 的位置。因此,我使用 mod 来获取循环编号的其余部分,以确定循环是奇数还是偶数,一旦我们超过了第一个(循环 0)。如果它是奇数(循环 1,这是第二个条目),我知道它们之间应该有一个 = 符号,例如:Loop0 = loop1。如果它甚至我知道我们正在 statring 一个新的 where 条件,所以我需要使用和。无论如何希望这对您有所帮助,如果您有任何问题,请告诉我。
您也可以尝试以下命令:
CREATE Temp Table Adv_Search_Trails(Parameter_Name Text, Parameter_Value Text,Condition Text,Table_Name Text )
INSERT INTO Adv_Search_Trails
SELECT 'trial_therapeutic_area_id','5','AND','trial_ta_filterview'
UNION ALL SELECT 'Primary_Drug','6','AND','trial_drugid_filterview'
UNION ALL SELECT 'collaborator_id','7','AND','trial_status_filterview'
UNION ALL SELECT 'maximum_age','8','OR','trial_patient_filterview'
UNION ALL SELECT 'designkeyword_id','9','OR','trial_key_filterview'
DECLARE @select_Code NVARCHAR(max)
DECLARE @Select_column VARCHAR(max)
DECLARE @selectloop INT
DECLARE @From_Code VARCHAR(max)
DECLARE @From_Column VARCHAR(max)
DECLARE @FromLoop INT
SET @select_Code = ' where '
SET @selectloop = 0
DECLARE select_cursor CURSOR
FOR
SELECT Parameter_Name
FROM Adv_Search_Trails
OPEN select_cursor
FETCH NEXT
FROM select_cursor
INTO @Select_column
WHILE @@FETCH_STATUS = 0
BEGIN
SET @select_Code = @select_Code + (
SELECT CASE
WHEN @selectloop > 0
THEN (
SELECT Condition
FROM Adv_Search_Trails
WHERE Parameter_Name = @Select_column
)
ELSE ''
END AS CommaOrNot
) + ' ' + @Select_column + ' = ' + (
SELECT Parameter_Value
FROM Adv_Search_Trails
WHERE Parameter_Name = @Select_column
) + ' '
SET @selectloop = @selectloop + 1
FETCH NEXT
FROM select_cursor
INTO @Select_column
END
CLOSE select_cursor
DEALLOCATE select_cursor
SET @From_Code = ' from '
SET @FromLoop = 0
DECLARE From_cursor CURSOR
FOR
SELECT Table_Name
FROM Adv_Search_Trails
OPEN From_cursor
FETCH NEXT
FROM From_cursor
INTO @from_column
WHILE @@FETCH_STATUS = 0
BEGIN
SET @From_Code = @From_Code + (
SELECT CASE
WHEN @FromLoop > 0
THEN ' INNER JOIN ' + @from_column+ ' ON ' + (SELECT TOP 1 table_name from Adv_Search_Trails)+'.ID '+' = ' +@from_column +'.ID'
ELSE @from_column
END AS CommaOrNot
)
SET @FromLoop = @FromLoop + 1
FETCH NEXT
FROM From_cursor
INTO @from_column
END
CLOSE From_cursor
DEALLOCATE From_cursor
SELECT 'select ' +@from_column+'.ID '+ @From_Code + @select_Code