是否可以在不使用连接的情况下从另一个公用表表达式引用列?

时间:2013-09-18 13:13:23

标签: sql common-table-expression

我有一个遗留系统,其中使用“多级查询”将数据加载到树结构中(稍后显示为树视图)。也就是说,每个级别都有自己的查询。较低级别取决于上级检索的数据。基本上,较低级别查询的参数是(某些)上级查询返回的值。我能够检索查询,但我想使用“with”语句构建一个“常规”查询。问题是:如何在不使用连接修改查询的情况下引用较低级别的CTE?

以下是我想要的简化示例:

with Level1Q as (select * from table1),
Level2Q as (select * from table2 where id=Level1Q.id)
select * from Level2Q

我可以单独访问每个查询,因为它们存储在XML文件中,该文件因用户而异:select * from table1& select * from table2 where id=:param1。我已经有了“填充”参数的例程但我不想通过插入连接来更改现有的查询文本,因为这意味着解析SQL语法的相对复杂的过程。

这就是我所知道的,并尽量避免:

with Level1Q as (select * from table1),
Level2Q as (select t2.* from table2 t2, Level1Q l1 where t2.id=l1.id)
select * from Level2Q

1 个答案:

答案 0 :(得分:1)

她对我如何处理这个问题的模糊概述。它做了很多假设,缺少关键组件,没有以任何方式进行调试,并且完全依赖于那些你无法控制对于难以确定的值“好”的查询好的。

假设:一组看起来像这样的查询:

Level1Q:  select * from users where name=:param_user
Level2Q:  select * from projects where id=:param_id
Level3Q:  select * from details where id=:param_id
Level4Q:  <etc>

因此,对于“3级”查询,您需要生成以下内容:

;WITH
   Level1Q as (select * from users where name=:param_user)
  ,Level2Q as (select * from projects where id=:param_id)
  ,Level3Q as (select * from details where id=:param_id)
 select * from Level3Q

这或类似的东西应该产生该查询:

DECLARE
  @Command   nvarchar(max)
 ,@Query     nvarchar(max)
 ,@Loop      int
 ,@MaxDepth  int
 ,@CRLF      char(2) = char(13) + char(10)  --  Makes the dynamic code more legible

SET @Command = 'WITH'


--  Set @MaxDepth to the level you want to query at
SET @MaxDepth = 3
SET @Loop = 0

WHILE @Loop < @MaxDepth
 BEGIN
    SET @Loop = @Looop + 1

    --  Get the query for this level
    SET @Query = <next query>

    SET @Command = replace(@Command + @CRLF
                           + case @Loop when 1 then '  ' else ' ,' end
                           + 'Level<<@Loop>>Q as (' + @Query + ')'
     ,':param_user', <appropriate value)  --  Only used when @Loop = 1
     ,':param_id', 'Level<<@Loop>>Q.id')  --  This assumes the link to the prior query is always by a column named "id"
     ,'<<@Loop>>', @Loop)  --  Done last, as the prior replace added another <<@Loop>>

 END

--  Add the final pull
SET @Command = @Command + @CRLF + replace(' select * from Level<<@Loop>>Q', '<<@Loop>>', @Loop - 1)

--  The most important command, because debugging this mess will be a pain
PRINT @Command

--EXECUTE sp_executeSQL @Command