在SQL Server中选择Top 1

时间:2017-04-03 04:15:22

标签: sql-server

请帮我选择前1名

像这样的数据

Code    Amp      Price
-----------------------
00001   10       1000
00002   75-100   1500
00003   50-60    1200
00004   15       1100

注意:列Amp的数据类型为VarChar

我想选择Amp 75,我希望得到的价格是1500

所以我使用这句话:

SELECT TOP 1 * 
FROM Cable 
WHERE (Amp <= '75') 
ORDER BY Amp DESC

但我得到的结果价格是1200是代码:00003(错误)的记录,其实我想要的结果是代码:00002,价格是1500

但是如果我想用Amp 76选择,结果是正确的语法:

SELECT TOP 1 * 
FROM Cable 
WHERE (Amp <= '75') 
ORDER BY Amp DESC

我案件的真正选择是什么?请帮帮我

5 个答案:

答案 0 :(得分:2)

几乎任何解析/拆分功能都可以,并且与Cross Apply相结合,它就变成了一个小问题

- 没有解析功能很容易

Declare @Cable table (Code varchar(25),Amp varchar(50),Price int)
Insert Into @Cable values
('00001','10',    1000),
('00002','75-100',1500),
('00003','50-60', 1200),
('00004','15',    1100)

Select Top 1 A.*
 From  @Cable A
 Cross Apply [dbo].[udf-Str-Parse](A.Amp,'-') B
 Where RetVal<=76              --<< Notice we are testing for 76
 Order By Price Desc

返回

Code    Amp     Price
00002   75-100  1500

感兴趣的UDF

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@Delimiter varchar(25))
Returns Table 
As
Return (  
    with   cte1(N)   As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
           cte2(N)   As (Select Top (IsNull(DataLength(@String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a,cte1 b,cte1 c,cte1 d) A ),
           cte3(N)   As (Select 1 Union All Select t.N+DataLength(@Delimiter) From cte2 t Where Substring(@String,t.N,DataLength(@Delimiter)) = @Delimiter),
           cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(@Delimiter,@String,s.N),0)-S.N,8000) From cte3 S)

    Select RetSeq = Row_Number() over (Order By A.N)
          ,RetVal = LTrim(RTrim(Substring(@String, A.N, A.L)))
    From   cte4 A
);
--Orginal Source http://www.sqlservercentral.com/articles/Tally+Table/72993/
--Much faster than str-Parse, but limited to 8K
--Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse-8K]('John||Cappelletti||was||here','||')

答案 1 :(得分:1)

如果您必须使用此现有数据类型和表结构,则下面的查询可能适合您。

SELECT TOP 1 *
FROM Cable
WHERE (SUBSTRING(Amp,1,IIF((CHARINDEX('-',Amp)-1)>0,(CHARINDEX('-',Amp)-1),0 ) ) <=75)
ORDER BY Amp DESC

答案 2 :(得分:0)

如果您使用的是SQL Server 2008及更高版本,请尝试以下操作:

SELECT TOP 1 * 
FROM Cable 
WHERE isnumeric(left(Amp, 2)) = 1 and cast(left(Amp, 2) as int) <= 75
and Price = 1500 
ORDER BY Amp DESC

注意:仅当您没有Amp小于10的记录时,此功能才有效。

答案 3 :(得分:0)

问题是SQL Server不会像varchar那样对int列进行排序。

排序问题示例:

select *
from (
    select '125' as nbr
    union all
    select '24' as nbr
    ) as a
order by a.nbr asc

1小于2(每个nbr中的第一个字符),因此它会认为125&lt; { 24(不是真的),尽管对于24应该首先出现的任何人看起来都很简单,如果列的数据类型是int,它将如何排序。

需要做的是将amp列拆分为范围,或最大值和最小值。使用-作为分隔符,您可以使用charindex将数字分开,将cast分割为int代替。

示例数据设置:

declare @cable table
    (
        code char(5) not null
        , amp varchar(10) not null
        , price int not null
    )

insert into @cable
values 
        ('00001','10'       ,10000),
        ('00002','75-100'   ,15000),
        ('00003','50-60'    ,12000),
        ('00004','15'       ,11000)

<强>答案:

declare @amp_nbr int = 75

select top 1 *
from (  
    select c.code
    , cast(iif(charindex('-', c.amp, 0) > 0, left(c.amp, charindex('-', c.amp, 0) - 1), c.amp) as int) as amp_min
    , cast(iif(charindex('-', c.amp, 0) > 0, right(c.amp, len(c.amp) - charindex('-', c.amp, 0)), c.amp) as int) as amp_max
    , c.price
    from @cable as c
    ) as a
where 1=1
and @amp_nbr between a.amp_min and a.amp_max
order by a.amp_min desc

之后,between子句中的一个简单where约束就可以了。

答案 4 :(得分:0)

感谢所有答案。我决定键入所有数据并用两个字段更改它。

代码Amp1 Amp2价格

00001 10 10 1000 00002 75 100 1500 00003 50 60 1200 00004 15 15 1100

单个值i在字段Amp2中输入相同然后我使用语法: SELECT * FROM电缆WHERE(Amp1和Amp2之间的65)