Reputation: 29
Please help me in select top 1
The data like this
Code Amp Price
-----------------------
00001 10 1000
00002 75-100 1500
00003 50-60 1200
00004 15 1100
Note : datatype for column Amp
is VarChar
I want to select with Amp 75 and I want get the price is 1500
So I use this statement:
SELECT TOP 1 *
FROM Cable
WHERE (Amp <= '75')
ORDER BY Amp DESC
but the result price I get is 1200 is record with code : 00003 (wrong), actually I want the result is code : 00002 and the price is 1500
But if I want to select with Amp 76 the result is true with the syntax :
SELECT TOP 1 *
FROM Cable
WHERE (Amp <= '75')
ORDER BY Amp DESC
What is the true select for my case? Please help me
Upvotes: 2
Views: 6842
Reputation: 6683
If you are using SQL Server 2008 and later, try something like this:
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
Note: This will work only if you have no records with Amp less than 10.
Upvotes: 0
Reputation: 29
Thank's for all answers. I decides to type all data and change it with two field.
00001 10 10 1000 00002 75 100 1500 00003 50 60 1200 00004 15 15 1100
The single value i type same in field Amp2 and then i use the syntax : SELECT * FROM Cable WHERE (65 BETWEEN Amp1 AND Amp2)
Upvotes: 0
Reputation: 4797
The problem is that SQL Server is not going to sort a varchar
column like an int
.
Sorting issue example:
select *
from (
select '125' as nbr
union all
select '24' as nbr
) as a
order by a.nbr asc
1 is less than 2 (the first character in each nbr
), so it will sort thinking that 125 < 24 (not true), even though it looks pretty simple to anyone that 24 should show up first, which is how it would be sorted if the datatype of the column were an int
.
What needs to happen is to split the amp
column into ranges, or max and min. Using the -
as the delimeter, you can use charindex
to split the numbers up and cast
them as int
s instead.
Sample Data Setup:
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)
Answer:
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
After that, a simple between
constraint in the where
clause will do the trick.
Upvotes: 0
Reputation: 81930
Just about any parse/split function will do, and combined with a Cross Apply, it becomes a small matter
-- Easy to do without a parse function
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
Returns
Code Amp Price
00002 75-100 1500
The UDF if interested
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','||')
Upvotes: 2
Reputation: 811
If you have to work with this existing datatype and table structure then below query may work for you.
SELECT TOP 1 *
FROM Cable
WHERE (SUBSTRING(Amp,1,IIF((CHARINDEX('-',Amp)-1)>0,(CHARINDEX('-',Amp)-1),0 ) ) <=75)
ORDER BY Amp DESC
Upvotes: 1