使用动态查询字符串连接多个表

时间:2015-11-04 15:17:41

标签: sql join dynamic-sql

在我的数据库中的4个不同表中找到了数千个代码。我创建了一个临时表来插入可以找到该代码的所有代码和相应的表名。作为一个例子,我展示了一小块临时表。

代码 |的表名

DA | StatsCanCensus2011_1

DWAPT5L | StatsCanCensus2011_3

DWAPT5O | StatsCanCensus2011_3

DWDUP | StatsCanCensus2011_3

DWMOVA | StatsCanCensus2011_3

我正在尝试编写一个查询,我可以动态选择代码并在选择的代码来自不同的表时连接表。我可以很容易地为2个表做这个,但是当有3个或4个时它没有用。

以下将给出需要加入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

2 个答案:

答案 0 :(得分:1)

使用游标来组装和执行动态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子句,因为我不确定你是否菊花链接它们,或者它们是否都加入到第一个表中,无论它是哪个它遵循相同的模式,你和#39; ll只需将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语句,我使用循环编号来确定是否需要在现有代码和新部分之间的concat之前添加逗号。对于where子句来说,它有点棘手,它需要在x = y和y = z的位置。因此,我使用mod来获取循环数的剩余部分,以确定循环是奇数还是偶数一旦超过第一个循环(循环0)。如果它是奇数(循环1是第二个条目)我知道它们之间应该有一个=符号,例如:Loop0 = loop1。如果它甚至我知道我们是一个新的where条件所以我需要使用和。无论如何希望这会有所帮助,如果您有任何问题,请告诉我。

答案 1 :(得分:0)

您也可以尝试以下命令:

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