在两列范围之间选择值
Posted
技术标签:
【中文标题】在两列范围之间选择值【英文标题】:Select values between two columns range 【发布时间】:2016-11-03 12:29:57 【问题描述】:我有一张这样的桌子:
i1 i2
----------
1 a
1 b
1 c
1 d
2 x
3 y
4 a
4 b
4 c
我想选择 1 c 和 4 a 之间的行。 结果应该是:
1 c
1 d
2 x
3 y
4 a
我该怎么做?
【问题讨论】:
您使用的是哪个 RDBMS? Sql Server 2014 标准 SQL:where (i1, i2) >= (1, 'c') and (i1, i2) <= (4, 'a')
但我不知道 SQL Server 是否支持
@a_horse_with_no_name:很遗憾,没有。
无论你在做什么,你都做错了。
【参考方案1】:
我会这样做:
select t.*
from t
where (i1 > 1 or (i1 = 1 and i2 >= 'c')) and
(i1 < 4 or (i1 = 4 and i2 <= 'a'));
【讨论】:
我认为这是不可能的。【参考方案2】:如果您使用的数据库支持行号功能,那么一种选择是根据您指定的顺序(即先按i1
升序,然后按@987654322 升序,使用行号创建表的 CTE @ 秒)。
然后,使用两个子查询来识别1c
和4a
的行号。这些行号构成了您要选择的范围。
;WITH cte AS (
SELECT ROW_NUMBER() OVER (ORDER BY i1, i2) AS RowNumber, i1, i2
FROM yourTable
)
SELECT *
FROM cte t
WHERE t.RowNumber >= (SELECT RowNumber FROM cte WHERE i1=1 AND i2='c') AND
t.RowNumber <= (SELECT RowNumber FROM cte WHERE i1=4 AND i2='a')
【讨论】:
因为单个where
子句就足够了,这对于查询来说太过分了。
@GordonLinoff 在 Stack Overflow,我们希望确保我们的问题已经彻底解决。因此需要过度杀伤这个查询:-)
?如果您已经在使用一个 CTE,为什么不使用更多的 CTE 而不是子查询
@onedaywhen 假设我们计划只运行实际查询一次或几次,通过创建子查询 CTE 真的会大大提高性能吗?
?我想我的意思是从样式/可读性的角度来看,即当您可以将 CTE 用于子查询并且您已经使用 CTE在查询中,为什么不【参考方案3】:
不是那么漂亮的方法......但是
create procedure GetRangeBetween (@i11 int, @i12 char, @i21 int, @i22 char)
AS
BEGIN
if object_id ('tempdb..#Test') is not null drop table #Test
create table #Test (i1 int, i2 nvarchar(10), [Rank] int)
insert into #Test(i1, i2)
values
(1, 'a'), (1, 'b'), (1, 'c'),
(1, 'd'), (2, 'x'), (3, 'y'),
(4, 'a'), (4, 'b'), (4, 'c')
update #Test
set Rank = src.[srcRank]
from #Test t
join (select *, row_number() over (order by i1) [srcRank] from #Test) src
on t.i1 = src.i1 and t.i2 = src.i2
declare @Rank1 int = (select [Rank] from #Test where i1 = @i11 and i2 = @i12)
declare @Rank2 int = (select [Rank] from #Test where i1 = @i21 and i2 = @i22)
select i1, i2 from #Test
where (i1 between @i11 and @i21) and ([Rank] between @Rank1 and @Rank2)
END
然后你只需用 ... 执行它。
execute GetRangeBetween 1, 'c', 4, 'a'
【讨论】:
[Rank] between 3 and 7
来自哪里?
在嵌套选择内部...有 row_number() 为您提供外部选择的 [Rank] 列
是的,但我们不能确定 (1,'c') 是排名 3。我们需要在某个地方找到排名范围。
修复了它,根本不用担心排名,因为存储过程......将始终有效:)
努力+1 :) 但是额外的列,为每次调用的所有值重新计算,听起来有点矫枉过正。查看上面 Tim Biegeleisen 的答案,以更优雅地实现类似的想法。【参考方案4】:
当然不是最佳解决方案,但这个查询应该可以工作:
select i1, i2
from tbl
where (i1 > 1 and i1 < 4)
or (i1 = 1 and i2 >='c')
or (i1 = 4 and i2 <='a')
请注意,结果中包含 (1, c) 和 (4, a)。如果您不需要包含边框,请更改比较运算符。
【讨论】:
以上是关于在两列范围之间选择值的主要内容,如果未能解决你的问题,请参考以下文章