Sql server 为什么递归字符串连接中的子查询总是返回NULL?
假设我有两张桌子: 表1:有一个我需要处理的ID列表。 表2:具有ID和值的键值对。 我需要从表2中检索表1中所有ID的值,作为单个字符串。为了实现这一点,我进行了下一个查询:Sql server 为什么递归字符串连接中的子查询总是返回NULL?,sql-server,string,sql-server-2005,Sql Server,String,Sql Server 2005,假设我有两张桌子: 表1:有一个我需要处理的ID列表。 表2:具有ID和值的键值对。 我需要从表2中检索表1中所有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
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。我的问题是:为什么子查询从表2中选择TOP 1值,其中id=@id总是返回NULL,即使在表2中找到id也是如此?这是一种非常奇怪的尝试实现treewalker的方法,在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中的值,则不需要变量@id,只需将子查询与table.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
这是一种非常奇怪的尝试实现treewalker的方法,在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中的值,则不需要变量@id,只需将子查询与table.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
另一种解决方案是,如果表2中的值不为空,则此解决方案仅在表2中的值之间附加“-”分隔符:
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中的值不为空,则此解决方案仅在表2中的值之间附加“-”分隔符:
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)
这是因为您的@id从0开始。除非表中的id为0,否则可能需要执行以下操作:选择@id=1 或者,您可以将其压缩为此,而不使用id:
SELECT @value = @value + value + '-'
FROM TABLE2 t2
INNER JOIN TABLE1 t1 ON t1.id = t2.id
这是因为您的@id从0开始。除非表中的id为0,否则可能需要执行以下操作:选择@id=1 或者,您可以将其压缩为此,而不使用id:
SELECT @value = @value + value + '-'
FROM TABLE2 t2
INNER JOIN TABLE1 t1 ON t1.id = t2.id
是的,但我很好奇为什么子查询总是返回NULL。因为它做的第一件事是从表2中选择TOP 1值,其中id=0的计算结果为NULL,NULL+'value'=NULL。我想我必须放弃这种方式,而是使用while循环。为了将来的参考,我可以用CTE代替这种方法吗?我认为你不需要while循环或CTE。还有两个答案可以满足您的需求。除非你需要对值或类似的东西进行分组,你没有提到。@Giscard Biamby,这只是一个简短的例子来说明我的问题,但我实际做的比这个复杂得多。我不能使用其他示例,因为我需要每个循环的最后一个ID,而不是当前ID。是的,但我想知道为什么子查询总是返回NULL。因为它做的第一件事是从表2中选择前1个值,其中ID=0的计算结果为NULL,NULL+'value'=NULL。我想我必须放弃这种方式,使用while循环代替。为了将来的参考,我可以用CTE代替这种方法吗?我认为你不需要while循环或CTE。还有两个答案可以满足您的需求。除非你需要对值或类似的东西进行分组,你没有提到。@Giscard Biamby,这只是一个简短的例子来说明我的问题,但我实际做的比这个复杂得多。我不能使用其他示例,因为我需要每个循环的最后一个ID,而不是当前ID。