How do u use between operator for range? - sql

This is my table Data
Id Begin End
1 0 1
2 1 3
3 3 4
This is my Query:
DECLARE #abc Float=1.5;
SELECT * FROM dbo.Slab AS s WHERE #abc BETWEEN s.Begin AND s.End
This give me 2 rows. I want to find a row for which #abc parameter is greater than Begin but less or equal to End.For example if #abc=1 i want to select 1 , if #abc=1.5 I want to select 2 , if #abc=3 i want to select 2 , if #abc=0.1 i want to select 1 and so on.

DECLARE #abc Float=1.5;
SELECT * FROM dbo.slab AS s WHERE #abc > s.[begin] and #abc<=s.[end]

Related

Difference between two columns into separate rows for each value between the two

I'm having trouble explaining my problem but I have this table
ID START END
1 10 12
2 30 31
3 11 13
and want something like this:
ID NUMBER
1 10
1 11
1 12
2 30
2 31
3 11
3 12
3 13
I need the all unique whole numbers between the two columns transform into separate rows.
Here's how I want the transformation to look like
I haven't tried anything because I don't even know how to call such procedure so any help is appreciated
If you don't have a numbers table (highly recommended), you can use an ad-hoc tally table in concert with a CROSS APPLY
Example
Select A.ID
,B.Number
From YourTable A
Cross Apply ( Select Top ([End]-[Start]+1)
Number=[START]-1+Row_Number() Over (Order By (Select NULL))
From master..spt_values n1, master..spt_values n2
) B
Returns
ID Number
1 10
1 11
1 12
2 30
2 31
3 11
3 12
3 13
In SQL Server, you can use a recursive CTE:
with cte as (
select id, [start] as number, [end] as end_number
from t
union all
select id, number + 1
from cte
where number < end_number
)
select id, number
from cte;
Note: If the span can exceed 100, you need option (maxrecursion) for the query.
Recursive CTEs are usually a bit slower than a numbers table. However, I find them much faster than I would expect.
--create table NewTable
--(
--ID int,
--NUMBER int
--)
DECLARE #ID nvarchar(50)
declare #START int
declare #END int
DECLARE Cursor_Name CURSOR
FOR
select ID, [START], [End] from tblSequences
OPEN Cursor_Name
FETCH NEXT FROM Cursor_Name INTO #ID,#START,#END
WHILE ##FETCH_STATUS = 0
begin
WHILE #START<=#END
begin
insert into NewTable (ID, NUMBER) Values (#ID, #START)
set #START = #START+1
end
FETCH NEXT FROM Cursor_Name INTO #ID,#START,#END
end
CLOSE Cursor_Name
DEALLOCATE Cursor_Name
select * from NewTable

How to use variable and changing user defined functions in query

I have defined some user defined function in sql server . for example :
select dbo.SumItems(1 , 2) will return 3
and
select dbo.MaxItems(5 , 3) will return 5
and some other functions may be more complicated.
also I keep variables and their formula expressions in a table:
IdVar Title Formula
----- ----- ---------------------
1 Sum dbo.SumItems(#a , #b)
2 Max dbo.maxItems(#a , #b)
I have my parameters in another table :
a b
-- --
1 2
5 3
now i want to join this two tables and get the following result :
Parameter a Parameter b Variable Title Result
----------- ----------- -------------- ------
1 2 Sum 3
1 2 Max 2
5 3 Sum 8
5 3 Max 5
also I have asked my problem from another view here.
Posted something very similar to this yesterday. As you know, you can only perform such function with dynamic sql.
Now, I don't have your functions, so you will have to supply those.
I've done something very similar in the past to calculate a series of ratios in one pass for numerous income/balance sheets
Below is one approach. (However, I'm not digging the 2 parameters ... seems a little limited, but I'm sure you can expand as necessary)
Declare #Formula table (ID int,Title varchar(25),Formula varchar(max))
Insert Into #Formula values
(1,'Sum' ,'#a+#b')
,(2,'Multiply','#a*#b')
Declare #Parameter table (a varchar(50),b varchar(50))
Insert Into #Parameter values
(1,2),
(5,3)
Declare #SQL varchar(max)=''
;with cte as (
Select A.ID
,A.Title
,ParameterA = A
,ParameterB = B
,Expression = Replace(Replace(Formula,'#a',a),'#b',b)
From #Formula A
Cross Join #Parameter B
)
Select #SQL = #SQL+concat(',(',ID,',',ParameterA,',',ParameterB,',''',Title,''',(',Expression,'))') From cte
Select #SQL = 'Select * From ('+Stuff(#SQL,1,1,'values')+') N(ID,ParameterA,ParameterB,Title,Value)'
Exec(#SQL)
-- Optional To Trap Results in a Table Variable
--Declare #Results table (ID int,ParameterA varchar(50),ParameterB varchar(50),Title varchar(50),Value float)
--Insert Into #Results Exec(#SQL)
--Select * from #Results
Returns
ID ParameterA ParameterB Title Value
1 1 2 Sum 3
2 1 2 Multiply 2
1 5 3 Sum 8
2 5 3 Multiply 15

Sorting results of SQL query just like IN parameter list

I'm doing a query which looks something like
SELECT id,name FROM table WHERE id IN (2,1,4,3)
I'd like to get
id name
2 B
1 A
4 D
3 C
but I'm getting
1 A
2 B
3 C
4 D
Is there any way to sort the query results in the same way as the list I'm including after IN?
Believe me, I have a practical reason that I would need it for ;)
SELECT id,name FROM table WHERE id IN (2,1,4,3)
ORDER BY CASE id
WHEN 2 THEN 1
WHEN 1 THEN 2
WHEN 4 THEN 3
WHEN 3 THEN 4
ELSE 5
END
This might solve your problem.
Solution 2, insert your list into a temp table and get them a running sequence
id, seq(+1 every new row added)
-----------------
2 1
1 2
4 3
3 4
then join 2 table together and order by this seq.
Okay, I did it myself. It's a bit mad but it works ;)
DECLARE #IDs varchar(max)
DECLARE #nr int
DECLARE #znak varchar(1)
DECLARE #index int
DECLARE #ID varchar(max)
SET #IDs='7002,7001,7004,7003'
SET #nr=1
SET #index=1
IF OBJECT_ID('tempdb..#temp') IS NOT NULL DROP TABLE #temp
CREATE TABLE #temp (nr int, id int)
--fill temp table with Ids
WHILE #index<=LEN(#Ids)
BEGIN
set #znak=''
set #ID=''
WHILE #znak<>',' AND #index<=LEN(#Ids)
BEGIN
SET #znak= SUBSTRING(#IDs,#index,1)
IF #znak<>',' SET #ID=#ID+#znak
SET #index=#index+1
END
INSERT INTO #temp(nr,id) VALUES (#nr,CAST(#ID as int))
SET #nr=#nr+1
END
-- select proper data in wanted order
SELECT MyTable.* FROM MyTable
INNER JOIN #temp ON MyTable.id=#temp.id
ORDER BY #temp.nr

Fill in missing rows in a table SQL

I have a report that needs the top 18 id codes for each case. Some cases only have all 18 rows and some only have a few. Here is an example of the output:
Case idcode value
2 3 122
2 6 52
2 15 121
3 1 111
3 3 555
3 6 322
What I need the output to have is 18 rows per record (idcodes 1-18) and to put "none" for the value if it is added. What is the best way to add in the missing rows if I do not know which ones are missing ahead of time?
Here is my query:
SELECT
rcl.CaseCaseId as Case, cce.StringValue as Value, cce.CorpIdCodeId as idcode
FROM
CaseIdCodeEntry AS cce
INNER JOIN
CorpIdCodes AS cid ON cce.CorpIdCodeId = cid.CorpIdCodeId
INNER JOIN
PhdRpt.ReportCaseList_542 AS rcl ON cce.CaseCaseId = rcl.CaseCaseId
WHERE
(cce.CorpIdCodeId < 19)
I would use a recursive CTE to auto-generate a numbered list of 1-18, and then LEFT JOIN off of that. Then use a CASE statement to adjust the Value field.
;WITH cte AS
( SELECT DISTINCT CaseCaseId AS CaseID, 1 AS idcode
FROM PhdRpt.ReportCaseList_542 UNION ALL
SELECT CaseID, idcode+1 FROM cte WHERE idcode < 18 )
SELECT cte.CaseID AS [Case],
CASE WHEN cce.CorpIdCodeId IS NULL THEN 'None' ELSE cce.StringValue END AS Value,
cte.idcode AS idcode
FROM cte
LEFT JOIN CaseIdCodeEntry cid ON cid.CorpCodeId = cte.idcode
LEFT JOIN CorpIdCodes cid ON cce.CorpIdCodeId = cid.CorpIdCodeId
LEFT JOIN PhdRpt.ReportCaseList_542 rcl ON cce.CaseCaseId = rcl.CaseCaseId
Try this seems works fine
create table #temp(iCase int, idcode int,value int)
Insert into #temp values(2,3,122)
Insert into #temp values(2,6,52)
Insert into #temp values(2,15,121)
Insert into #temp values(3,1,11)
Insert into #temp values(3,3,555)
Insert into #temp values(3,6,322)
create table #Val(Id int)
declare #count int =1
while (#count<=18)
begin
insert into #Val values(#count)
set #count=#count+1
end
DECLARE #CaseId INT
DECLARE #DataCursor CURSOR
SET #DataCursor = CURSOR FOR
SELECT distinct iCase
From #temp
OPEN #DataCursor
FETCH NEXT
FROM #DataCursor INTO #CaseId
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #temp
SELECT #CaseId,Id,null
FROM #Val
WHERE Id NOT IN (
SELECT idcode
FROM #temp
WHERE iCase=#CaseId )
FETCH NEXT
FROM #DataCursor INTO #CaseId
END
CLOSE #DataCursor
DEALLOCATE #DataCursor
Select * from #temp
TL;DR SQL Fiddle
Like Jon of All Trades I also favour the use of a sequence (or number) table.
CREATE TABLE Seq ( seq_num int)
You can use this to populate the missing rows from your original data; assuming you have a table T holding your data
CREATE TABLE T ( case_num int
,code_id int
,value char(4))
You can use the following query to get your fully populated results
WITH All_Codes AS (
SELECT DISTINCT case_num, seq_num AS code_id
FROM T, Seq
)
SELECT All_Codes.case_num
,All_Codes.code_id
,CASE WHEN value IS NULL THEN 'none' ELSE value END AS value
FROM All_Codes LEFT JOIN T
ON All_Codes.case_num = T.case_num AND All_Codes.code_id = T.code_id
The result is
case_num code_id value
2 1 none
2 2 none
2 3 122
2 4 none
2 5 none
2 6 52
2 7 none
2 8 none
2 9 none
2 10 none
2 11 none
2 12 none
2 13 none
2 14 none
2 15 121
2 16 none
2 17 none
2 18 none
3 1 111
3 2 none
3 3 555
3 4 none
3 5 none
3 6 322
3 7 none
3 8 none
3 9 none
3 10 none
3 11 none
3 12 none
3 13 none
3 14 none
3 15 none
3 16 none
3 17 none
3 18 none
Humpty and Matt's solutions should work, but as a purist I'd recommend using a Numbers table rather than a cursor or CTE. It's simpler (IMHO) and for large quantities it should be significantly faster:
SELECT
X.CaseId, N.Number, X.Value
FROM
Numbers AS N
LEFT JOIN
(
SELECT
CICE.CaseCaseId AS CaseId, CICE.StringValue AS Value, CICE.CorpIdCodeId AS IdCode
FROM
CaseIdCodeEntry AS CICE
INNER JOIN CorpIdCodes AS CIC ON CICE.CorpIdCodeId = CIC.CorpIdCodeId
INNER JOIN PhdRpt.ReportCaseList_542 AS RCL ON CICE.CaseCaseId = RCL.CaseCaseId
) AS X ON N.Number = X.IdCode
WHERE
N.Number BETWEEN 1 AND 18
Incidentally, are you sure you need to join CaseIdCodeEntry to CorpIdCodes and ReportCaseList_542? If they're there to filter the data, that's fine, but as they're not contributing to the output I have to wonder.
This is the solution that I used. I used some of #Jon of All Trades and #huMpty duMpty code.
SELECT cice.CaseCaseId, cice.CorpIdCodeId, cice.DateValue, cice.DoubleValue, cice.StringValue, cic.Label
into #TT
FROM CaseIdCodeEntry AS cice INNER JOIN
CorpIdCodes AS cic ON cice.CorpIdCodeId = cic.CorpIdCodeId INNER JOIN
PhdRpt.ReportCaseList_542 AS rcl ON cice.CaseCaseId = rcl.CaseCaseId
WHERE (cice.CorpIdCodeId <= 18)
ORDER BY cice.CaseCaseId, cice.CorpIdCodeId
create table #Val(Id int)
declare #count int =1
while (#count<=18)
begin
insert into #Val values(#count)
set #count=#count+1
end
DECLARE #CaseId INT
DECLARE #DataCursor CURSOR
SET #DataCursor = CURSOR FOR
SELECT distinct CaseCaseId
From #TT
OPEN #DataCursor
FETCH NEXT
FROM #DataCursor INTO #CaseId
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #TT
SELECT #CaseId,Id,null, null, null, 'none'
FROM #Val
WHERE Id NOT IN (
SELECT CorpIdCodeId
FROM #TT
WHERE CaseCaseId=#CaseId )
FETCH NEXT
FROM #DataCursor INTO #CaseId
END
CLOSE #DataCursor
DEALLOCATE #DataCursor
Select * from #TT
order by CaseCaseId, CorpIdCodeId
drop table #TT, #Val

get specific rows of table given a rule SQL Server 2008

I have a table like:
ID NAME VAL
----------------------
1 a1*a1 90052
2 a1*a2 236
3 a1*a3 56
4 a1*a4 6072
5 a1*a5 1004
6 a2*a2 4576
7 a2*a3 724
8 a2*a4 230
9 a2*a5 679
10 a3*a3 5
11 a3*a4 644
12 a3*a5 23423
13 a4*a4 42354
14 a4*a5 10199
15 a5*a5 10279
Given a number given S = 5, I want to query
the rows wth id: 1,6,10,13,15
they are a1*a1,a2*a2,a3*a3,a4*a4 and a5*a5
I would like something like:
INSERT #NEW_TABLE (ID,NAME,Value) (
SELECT ordinal, NAME, VAL FROM myTable where id = 1,6,10,13,15)
to get
ID NAME VAL
----------------------
1 a1*a1 90052
2 a2*a2 4576
3 a3*a3 5
4 a4*a4 42354
5 a5*a5 10279
Is there a way to do this for any given S, Maybe wth dynamic sql?
I was getting the formula and I got this:
S=5
ID formula
1 1
6 1+S
10 1+S+ (S-1)
13 1+S+ (S-1) + (S-2)
15 1+S+ (S-1) + (S-2) + (S-3)
Is there a way to do this inside a case or a while loop?
This worked in testing.
You can just inner join on #Tab to limit your results. You probably also want to add some traps for values below 3, which I haven't done.
The basic process is
Declare your #s value
Insert the first two rows since they will always be the same
In a loop, insert one row at a time with an incrementing difference
Loop exits once it has run #s-2 times
Try:
DECLARE #Tab Table (id INT)
DECLARE #S int = 5,
#ct int
DECLARE #cur int = (1 + #S)
INSERT INTO #Tab SELECT 1
INSERT INTO #Tab SELECT (1 + #S)
SET #ct = 1
WHILE #ct <= #S - 2
BEGIN
SET #cur = #cur + (#S - #ct)
INSERT INTO #Tab SELECT #cur
SET #ct = #ct + 1
END
SELECT * FROM #Tab
ORDER BY id
To use this in your query, you can do either:
SELECT ordinal, NAME, VAL
FROM myTable
WHERE id IN (SELECT id FROM #Tab)
-- OR
SELECT ordinal, NAME, VAL
FROM myTable t
INNER JOIN #tab t2
ON t2.id = t.id