我有一个查询导致两行或更多行(只有一列),我希望将第一行值捕获到第一个临时变量,将第二行值捕获到第二个临时变量,而不使用select top 1的多次并选择按顺序排名前1位
像这样;
Select row1 value into @tempvariable1, row2 value into @tempvariable2 from blah blah
答案 0 :(得分:1)
您需要以某种方式识别行(我在下面的示例中使用行ID,按值排序 - 您可以按ID或其他顺序排序):
DECLARE @DataSource TABLE
(
[value] VARCHAR(12)
);
INSERT INTO @DataSource
VALUES ('value 1')
,('value 2')
,('value 3');
DECLARE @tempVariable1 VARCHAR(12)
,@tempVariable2 VARCHAR(12);
WITH DataSource ([value], [rowID]) AS
(
SELECT [value]
,ROW_NUMBER() OVER (ORDER BY [value])
FROM @DataSource
)
SELECT @tempVariable1 = IIF([rowID] = 1, [value], @tempVariable1)
,@tempVariable2 = IIF([rowID] = 2, [value], @tempVariable2)
FROM DataSource;
SELECT @tempVariable1
,@tempVariable2;
答案 1 :(得分:0)
您可以使用CTE获取所需的X值,然后从中选择:
declare @data table(id int);
insert into @data(id) values(8), (6), (4), (3);
with vals(id, n) as (
Select top(2) id, ROW_NUMBER() over(order by id)
From @data
)
Select @A = (Select id From vals Where n = 1)
, @B = (Select id From vals Where n = 2)
你也可以使用PIVOT:
Select @A = [1], @B = [2]
From (
Select id, ROW_NUMBER() over(order by id)
From @data
) v(id, n)
PIVOT (
max(id) FOR n in ([1], [2])
) as piv
答案 2 :(得分:0)
您有两个选择
我们说测试用例如下所示构建
create table dbo.Test
(
value varchar(100) not null
)
GO
insert into dbo.Test
values
('A'),('B'),('NO THIS ONE'),('NO THIS ONE'),('NO THIS ONE')
GO
现在让我们假设您按以下方式获取数据
select t.value
from dbo.Test t
where t.value != 'NO THIS ONE'
GO
第一个也是更容易的选择是将数据保存在临时表中
declare @results as Table (value varchar(100))
insert into @results
select t.value
from dbo.Test t
where t.value != 'NO THIS ONE'
你仍然使用TOP 1但不是在整个数据中,只在结果中使用。
使用TOP 1
查找第一个结果,使用第二个TOP 1
,其中值与第一个结果不同。
declare @A varchar(100), @B varchar(100)
set @A = (select top 1 r.value from @results r)
set @B = (select top 1 r.value from @results r where r.value != @A)
select @A, @B
GO
这种方法具有性能优势。
当然,如果两个值相等,那么效果不佳。您可以使用top 1
并按相反顺序排序来修复它。
使用rownumber
有一个更好的替代。
它的工作原理是因为如果你在返回多行时设置了一个变量,那么变量就会与最后一行相交(实际上它会为每一行迭代重置)。
案例陈述确保变量@A
仅在第一行迭代中设置。
declare @A varchar(100), @B varchar(100)
/* This way @B receives the last value and @A the first */
select @B = t.value,
@A = (case when ROW_NUMBER() OVER(order by t.Value) = 1
then t.Value else @A
end)
from dbo.Test t
where t.value != 'NO THIS ONE'
select @A, @B