为什么递归字符串连接中的子查询总是返回NULL?

时间:2012-09-28 21:46:28

标签: sql-server string sql-server-2005

假设我有两个表:

  • TABLE1:有一个我需要处理的ID列表。
  • 表2:具有ID和值的键值对。

我需要从TABLE2中检索TABLE1中所有ID的值,作为单个字符串。为了实现这一点,我做了下一个查询:

DECLARE @id INT, @value VARCHAR(10);

SELECT @id=0, @value='';

SELECT
    @value = @value + (SELECT TOP 1 value FROM TABLE2 WHERE id=@id) + '-',
    @id = @id+1
FROM TABLE1

但是当我运行此查询时,子查询总是返回null(因此,最后返回@value=NULL)。我的问题是:为什么子查询SELECT TOP 1 value FROM TABLE2 WHERE id=@id总是返回NULL,即使在TABLE2中找到了ID?

3 个答案:

答案 0 :(得分:4)

这是一种非常奇怪的尝试实现树行者的方法,在SELECT中增加@id并期望它应用于子查询。它不起作用,因为SQL Server在查询设置阶段将子查询表达式的@id值锁定为常量。

请参阅此示例,其中返回的@value明确指示@id锁定为1.对于您的问题,它被锁定为0,因此每个子查询将返回NULL,表面上是因为@id = 0没有匹配

create table table1 (
  id int);
create table table2 (
  id int, value varchar(10));
insert table1 values (1),(2),(3),(4);
insert table2 values
(1,1),
(2,2),
(3,3),
(4,4);

DECLARE @id INT, @value VARCHAR(10);

SELECT @id=1, @value='';

SELECT
    @value = @value + (SELECT TOP 1 value FROM TABLE2 WHERE id=@id) + '-',
    @id = @id+1
FROM TABLE1;

select @value, @id

-- result
1-1-1-1       5

如果你只想要2的值,那么你只需要将子查询与table.id相关联,而不是变量@id,如下所示:

create table table1 (id int);
create table table2 (id int, value varchar(10));
insert table1 values (1),(2),(3),(4);
insert table2 values
(1,1),
(3,9),
(4,4);

DECLARE @value VARCHAR(10);

SELECT @value='';

SELECT
    @value = @value + isnull((SELECT TOP 1 value 
                              FROM TABLE2 
                              WHERE id=table1.id) + '-','')
FROM TABLE1;

select @value

-- Result
1-9-4

答案 1 :(得分:1)

另一个解决方案(如果table2中的值为NOT NULL,则此方法仅在table2的值之间附加' - '分隔符):

declare @id int, @value varchar(max);
select @id = 0, @value='';

select 
    @value = @value + isnull(value,'') + case when value is null then '' else '-' end
from 
    table2 t2
where 
    t2.id in (select id from table1)

答案 2 :(得分:1)

这是因为你在0开始你的@id除非你的表中的id为0,否则你可能需要这样做:SELECT @ id = 1

或者,您可以将其浓缩为此而不使用id:

SELECT @value = @value + value +  '-'
FROM TABLE2 t2
INNER JOIN TABLE1 t1 ON t1.id = t2.id