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

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