我的数据库中有 4 个不同的表,可找到数千个代码。我创建了一个临时表来插入所有代码以及可以找到该代码的相应表名称。作为示例,我展示了临时表的一小部分。
代码 | 表名
DA |加拿大人口普查统计局2011_1
DWAPT5L |加拿大人口普查统计局2011_3
DWAPT5O |加拿大人口普查统计局2011_3
DWDUP |加拿大人口普查统计局2011_3
DWMOVA |加拿大人口普查统计局2011_3
我正在尝试编写一个查询,当所选代码来自不同的表时,我可以动态选择代码并连接表。我可以轻松地为 2 张 table 做到这一点,但是当有 3 或 4 张 table 时,它就不起作用了。
下面将给出当需要连接 2 个表时我需要的结果:
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 个表时的结果示例:
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
最佳答案
使用游标来组装和执行动态 SQL 查询是雄心勃勃的,但这意味着执行路径永远无法被缓存。另外,如果这些表很大(人口普查数据往往如此),那么您可能会在优化方面遇到一些真正的挑战。排除了标准 DBA 的烦扰,这实际上是一个非常有趣的想法,因为它听起来很糟糕,但实际上并没有那么糟糕(因为光标从不接触数据)。
我认为你的方法是正确的,但你试图让每个光标做太多事情。您所需的查询由三个部分组成:一个包含列列表的 select 语句、一个包含连接表列表的 from 语句以及一个包含连接这些表的逻辑的 where 语句(隐式连接它们而不是显式地这样做) 。那么为什么不使用三个光标,每个光标专注于一个特定区域。它使每个游标的构建变得更加简单,然后您可以组合最终结果。
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 子句,因为我不确定你是否以菊花链方式连接它们,或者它们是否全部连接回第一个表,无论它是什么它遵循相同的模式,你只需要将案例陈述更新为类似的内容;
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 子句来说有点棘手,它需要是 where x = y 且 y = z。因此,我使用 mod 来获取循环编号的剩余部分,以确定一旦我们经过第一个循环(循环 0)后该循环是奇数还是偶数。如果它很奇怪(循环 1 这是第二个条目),我知道它们之间应该有一个 = 符号,例如:Loop0 = Loop1。如果是的话,我知道我们正在声明一个新的 where 条件,所以我需要使用 and 。无论如何,希望这对您有所帮助,如果您有任何疑问,请告诉我。
关于sql - 使用动态查询字符串连接多个表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33525428/