How to add and subtract value from previous rows based on condition - sql

I have a table with values
Slno Type Amount
1 P 40
2 C 20
3 P 45
4 P 20
5 C 10
I want to get values for RESULT column.
Type Amount RESULT
P 40 40
C 20 20
P 45 65
P 20 85
C 10 75
If Type is C then value gets subtracted from previous value,
else if Type is P then value gets added to previous values.
This is what i've tried:
;WITH FINALMIDRESULT
AS (SELECT Type,
Value1,
Row_number()
OVER(
ORDER BY Slno ASC) rownum
FROM #midRes)
SELECT C1.Type,
C1.Value1,
CASE
WHEN C1.Type = 'C' THEN (SELECT Sum(Amount)
FROM FINALMIDRESULT c2
WHERE c2.rownum <= C1.rownum)
ELSE (SELECT Sum(Amount) - Sum(Amount)
FROM FINALMIDRESULT c2
WHERE c2.rownum <= C1.rownum)
END AS RESULT
FROM FINALMIDRESULT C1
This is the Result that i have got
Type Amount RESULT
P 40 0
C 20 60
P 45 0
P 20 0
C 10 135

You need to implement a seft INNER JOIN to sum all values with Slno less than the current value, like below:
;WITH OriginalData AS
( SELECT *
FROM
( VALUES
(1, 'P', 40),
(2, 'C', 20),
(3, 'P', 45),
(4, 'P', 20),
(5, 'C', 10)
) AS Temp(Slno, Type, Amount)
)
SELECT [Current].Type, [Current].Amount,
ISNULL(SUM(
CASE WHEN [Previous].Type = 'P'
THEN +[Previous].Amount
ELSE -[Previous].Amount
END),0) +
CASE WHEN [Current].Type = 'P'
THEN +[Current].Amount
ELSE -[Current].Amount
END Result
FROM OriginalData [Current]
LEFT JOIN OriginalData [Previous]
ON [Previous].Slno < [Current].Slno
GROUP BY [Current].Slno, [Current].Type, [Current].Amount
ORDER BY [Current].Slno
I think the biggest change you can make is to shift your mindset. When you think "previous values" you chose a procedural path which can be solved my any major programming language, but rapidly evolve to a cursor approach in SQL -- what isn't appropriate in this case.
When comes to SQL, you need to think in "sets", so you can drive your efforts to identify those data sets and combine them.

SELECT SlNo, Type, Amount,
Sum((Case when Type='C' then -1 else 1 END)*Amount) Over(Order by SlNo) Result
FROM TableName

Related

How to calculate the degree of agreement by row comparisons in SQL Server?

For a minimal, reproducible example (reprex) let's assume I have a database object (dbo) in a Microsoft SQL Server and I want to query things in T-SQL.
My dbo looks like this:
Animal-ID Marker-ID Allele1 Allele2
--------------------------------------------
1 OAR1 A G
1 OAR2 C C
1 OAR3 T G
2 OAR1 A C
2 OAR2 C C
2 OAR3 A C
What I would like to do is calculate an allele match percentage per Marker-ID across all Animal-IDs.
Given the dbo example from above the desired result looks like this:
Animal-ID-pair Marker-ID Match-percentage
--------------------------------------------
1-2 OAR1 50
1-2 OAR2 100
1-2 OAR3 0
So far, I tried the following approaches:
First I thought selecting individual rows is sufficient.
SELECT *
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY Animal-ID ASC) AS rownumber,
Animal-ID, Marker-ID,
Allele1, Allele2
FROM
dbo) AS foo
WHERE
rownumber BETWEEN 1 AND 3;
and then compare that to the range between 4 and 6.
The problem here is that, in my real and way lager data set, not all animal-ID pairs have the same number of rows, i.e. not the same number of markers.
That is why I thought grouping might be helpful:
SELECT
Animal-ID, Marker-ID,
Allele1, Allele2
FROM
dbo
WHERE
Animal-ID IN (SELECT Animal-ID FROM dbo
GROUP BY Animal-ID
HAVING COUNT(*) > 1);
but that does not allow me to do comparisons and/or calculations across groups.
Thus I would like to ask how to calculate the degree of agreement in the comparison of row pairs.
Sample data
create table genomes
(
AnimalId int,
MarkerId nvarchar(10),
Allele1 nvarchar(1),
Allele2 nvarchar(2)
)
insert into genomes (AnimalId, MarkerId, Allele1, Allele2) values
(1, 'OAR1', 'A', 'G'),
(1, 'OAR2', 'C', 'C'),
(1, 'OAR3', 'T', 'G'),
(2, 'OAR1', 'A', 'C'),
(2, 'OAR2', 'C', 'C'),
(2, 'OAR3', 'A', 'C'),
(3, 'OAR1', 'A', 'G'), --new sample Animal with less data (no OAR3)
(3, 'OAR2', 'C', 'G');
Solution
Select all unique animals cte_AllAnimals.
Select all unique markers cte_AllMarkers.
Combine every animal with every animal behind it a2.AnimalId > a1.AnimalId. This will give you all unique animal combinations.
Combine every pair with every marker cross join cte_AllMarkers.
This gives me:
with cte_AllMarkers as
(
select g.MarkerId
from genomes g
group by g.MarkerId
),
cte_AllAnimals as
(
select g.AnimalId
from genomes g
group by g.AnimalId
)
select convert(nvarchar(10), a1.AnimalId) + '-' +
convert(nvarchar(10), a2.AnimalId) as AnimalIdPair,
m.MarkerId,
case g1.Allele1 when g2.Allele1 then 50 else 0 end +
case g1.Allele2 when g2.Allele2 then 50 else 0 end as MatchPercentage
from cte_AllAnimals a1
join cte_AllAnimals a2
on a2.AnimalId > a1.AnimalId
cross join cte_AllMarkers m
left join genomes g1
on g1.AnimalId = a1.AnimalId
and g1.MarkerId = m.MarkerId
left join genomes g2
on g2.AnimalId = a2.AnimalId
and g2.MarkerId = m.MarkerId
order by a1.AnimalId,
a2.AnimalId,
m.MarkerId;
Result
AnimalIdPair MarkerId MatchPercentage
------------ -------- ---------------
1-2 OAR1 50
1-2 OAR2 100
1-2 OAR3 0
1-3 OAR1 100
1-3 OAR2 50
1-3 OAR3 0
2-3 OAR1 50
2-3 OAR2 50
2-3 OAR3 0
Fiddle to see it in action.
By Using SUBQUERY & STUFF
DECLARE #T TABLE(Animal_ID INT, Marker_ID CHAR(10) , Allele1 CHAR, Allele2 CHAR)
INSERT INTO #T VALUES
(1,'OAR1','A','G'),
(1,'OAR2','C','C'),
(1,'OAR3','T','G'),
(2,'OAR1','A','C'),
(2,'OAR2','C','C'),
(2,'OAR3','A','C')
SELECT * FROM #T
SELECT S.*,(ISNULL(S1.C,0)+ISNULL(S2.C,0))*100/LEN(Allele_Pair) AS Percentage
FROM (
SELECT STUFF((SELECT CONCAT('-' , Animal_ID ) FROM #T t1
WHERE t1.Marker_ID = t2.Marker_ID FOR XML PATH ('')), 1, 1, '') AS Animal_ID_Pair
,Marker_ID,
STUFF((SELECT CONCAT(Allele1,Allele2) FROM #T t1
WHERE t1.Marker_ID = t2.Marker_ID FOR XML PATH ('')), 1, 0, '') AS Allele_Pair
FROM #T t2
GROUP BY Marker_ID) S
LEFT JOIN (SELECT Marker_ID,Allele2,COUNT(Allele2) AS C FROm #T GROUP BY Allele2,Marker_ID HAVING COUNT(Allele2)>1) S1 ON S1.Marker_ID=S.Marker_ID
LEFT JOIN (SELECT Marker_ID,Allele1,COUNT(Allele1) AS C FROm #T GROUP BY Allele1,Marker_ID HAVING COUNT(Allele1)>1) S2 ON S2.Marker_ID=S.Marker_ID
Output:
Animal_ID_Pair Marker_ID Allele_Pair Percentage
1-2 OAR1 AGAC 50
1-2 OAR2 CCCC 100
1-2 OAR3 TGAC 0
A self-join does what you want -- with some arithmetic:
select t1.animal_id, t2.animal_id,
( case when t1.allele1 = t2.allele1 then 1.0 else 0 end +
case when t1.allele2 = t2.allele2 then 1.0 else 0 end +
) / 2.0 as match_percentage
from t t1 join
t t2
on t1.marker_id = t2.marker_id and
t1.animal_id < t2.animal_id;
Although it is easy enough to add new alleles into this. You can also express this as by unpivoting the alleles and aggregating:
with ta as (
select t.*,, v.*
from t cross apply
(values (1, allele1), (2, allele2)) v(allele, val)
)
select ta1.animal_id, ta2.animal_id, mta1.marker,
avg(case when ta1.val = ta2.val then 1.0 else 0 end) as match_percentage
from ta ta1 join
ta ta2
on ta1.marker_id = ta2.marker_id and
ta1.animal_id < ta2.animal_id
group by ta1.animal_id, ta2.animal_id;

How to get the result in below format in SQL Server?

I have a table called recipes with following data.
page_no title
-----------------
1 pancake
2 pizza
3 pasta
5 cookie
page_no 0 is always blank, and missing page_no are blank, I want output as below, for the blank page NULL values in the result.
left_title right_title
------------------------
NULL pancake
Pizza pasta
NULL cookie
I have tried this SQL statement, but it's not returning the desired output:
SELECT
CASE WHEN id % 2 = 0
THEN title
END AS left_title,
CASE WHEN id %2 != 0
THEN title
END AS right_title
FROM
recipes
You are quite close. You just need aggregation:
select max(case when id % 2 = 0 then title end) as left_title,
max(case when id % 2 = 1 then title end) as right_title
from recipes
group by id / 2
order by min(id);
SQL Server does integer division, so id / 2 is always an integer.
Using CTE.. this should be give you a good CTE overview
DECLARE #table TABLE (
pageno int,
title varchar(30)
)
INSERT INTO #table
VALUES (1, 'pancake')
, (2, 'pizza')
, (3, 'pasta')
, (5, 'cookie')
;
WITH cte_pages
AS ( -- generate page numbers
SELECT
0 n,
MAX(pageno) maxpgno
FROM #table
UNION ALL
SELECT
n + 1 n,
maxpgno
FROM cte_pages
WHERE n <= maxpgno),
cte_left
AS ( --- even
SELECT
n,
ROW_NUMBER() OVER (ORDER BY n) rn
FROM cte_pages
WHERE n % 2 = 0),
cte_right
AS ( --- odd
SELECT
n,
ROW_NUMBER() OVER (ORDER BY n) rn
FROM cte_pages
WHERE n % 2 <> 0)
SELECT
tl.title left_title,
tr.title right_title --- final output
FROM cte_left l
INNER JOIN cte_right r
ON l.rn = r.rn
LEFT OUTER JOIN #table tl
ON tl.pageno = l.n
LEFT OUTER JOIN #table tr
ON tr.pageno = r.n

SQL Server loop through a table for every 5 rows

I need to write a stored procedure or table function to return a new data table as a new data source.
I wish to loop through the original table for every 5 rows base on the invoice ID column (it's possible not start from 1), the first 5 rows add to the left of the new table and the second 5 rows add to the right of the new table, the third 5 rows to the left and so on.
For example, Here is the original table:
Here is the expect table:
Thanks in advance!
declare #rowCount int = 5;
with cte as (
select *,( (IN_InvoiceID-1) / #rowCount ) % 2 group1
,( (IN_InvoiceID-1) / #rowCount ) group2
,IN_InvoiceID % #rowCount group3
from T
)
select * from cte
select T1.INID,T1.IN_InvoiceID,T1.IN_InvoiceAmount,T2.INID,T2.IN_InvoiceID,T2.IN_InvoiceAmount
from CTE T1
left join CTE T2 on T2.group1 = 1 and T1.group2 = T2.group2-1 and T1.group3 = T2.group3
where T1.group1 = 0
Test DDL
CREATE TABLE T
([INID] varchar(38), [IN_InvoiceID] int, [IN_InvoiceAmount] int)
;
INSERT INTO T
([INID], [IN_InvoiceID], [IN_InvoiceAmount])
VALUES
('DB3E17E6-35C5-41:121-93B1-F809BF6B2972', 1, 2999),
('3212F048-8213-4FCC-AB64-121485B77D4E43', 2, 3737),
('E3526373-A204-40F5-801C-7F8302A4E5E2', 3, 3175),
('76CC9C19-BF79-4E8A-8034-A33805AD3390', 4, 391),
('EC7A2FBC-B62D-4865-88DE-A8097975F125', 5, 1206),
('52AD3046-21331-4F0A-BD1D-67F232C54244', 6, 402),
('CA48F132-A9F5-4516-9E58-CDEE6644AAD1', 7, 1996),
('02E10C31-CAB2-4220-B66A-CEE5E67A9378', 8, 3906),
('98F1EEFF-B07A-4B65-87F4-E165264284DD', 9, 2575),
('91EBDD8B-B73C-470C-8900-DD66078483DB', 10, 2965),
('6E2490E5-C4DE-4833-877F-1590F7BDC1B8', 11, 1603),
('00985921-AC3C-4E3E-BAE1-7F58302F831A', 12, 1302)
;
Result:
Could you please check article Display Data in Multiple Columns using SQL showing with example case how a database developer can show the list of data rows in a columnar mode using Row_Number() function and mode arithmetic expression
You need to add additional columns from the same row that is different in the sample
Seems as if you want to split the table into 2 tables with alternating 5 rows. An easy way to do this would be:
Take data into a temp table having an extra column (lets say
grouping_id)
Update the grouping id so that each 5 rows have the same id. You can
use in_invoiceId % 5 (the nod function). After this step the first 5
rows will have grouping_id 0, next 5 will have 1, next will have 2
(assuming your invoice id is incremented +1 for all rows).
You can just do a normal select with where clause for odd and even grouping_id
Ideally, you can manage with the 2 tables Master and detail table.
But due to my curiosity, I am able to solve and give the answer as
Declare #table table(id int identity, invoice_id int)
; WITH Numbers AS
(
SELECT n = 1
UNION ALL
SELECT n + 1
FROM Numbers
WHERE n+1 <= 50
)
insert into #table SELECT n
FROM Numbers
Select (a.id )%5 ,* from #table a join #table b on a.id+5 = b.id and a.id != b.id
;WITH Numbers AS
(
SELECT n = 1, o = 5
UNION ALL
SELECT n + 10, o = o+10
FROM Numbers
WHERE n+1 <= 50
)
select a.id ParentId,a.invoice_id ParentInvoiceId, --b.n, b.o,
c.invoice_id childInvoiceID from #table a
join Numbers b on a.id between b.n and b.o
left join #table c on a.id + 5 = c.id
Here is my solution
First i create grps based on whether the in_invoiceid is divisible by 5 or not.(Ignore the remainders)
After that i create a category to indicate between alternative groups(ie by checking if the remainder is 0 or otherise)
Then its a matter of dense_ranking the records on the basis of the category field ordered by in_invoiceid
Lastly a join with category=1 rows with same dense_rank as those records in category=0
create table Invoicetable(IN_ID varchar(100), IN_InvoiceID int)
INSERT INTO Invoicetable (IN_ID, IN_InvoiceID)
VALUES
('2345-BCDE-6645-1DDF', 1),
('2345-BCDE-6645-3DDF', 2),
('2345-BCDE-6645-4DDF', 3),
('2345-BCDE-6645-5DDF', 4),
('2345-BCDE-6645-6DDF', 5),
('2345-BCDE-6645-7DDF', 6),
('2345-BCDE-6645-aDDF', 7),
('2345-BCDE-6645-sDDF', 8),
('2345-BCDE-6645-dDDF', 9),
('2345-BCDE-6645-dDDF', 10),
('2345-BCDE-6645-dDDF', 11),
('2345-BCDE-6645-dDDF', 12);
with data
as (
select *
,(in_invoiceid-1)/5 as grp
,case when ((in_invoiceid-1)/5)%2=0 then '1' else '0' end as category
,dense_rank() over(partition by case when ((in_invoiceid-1)/5)%2=0 then '1' else '0' end
order by in_invoiceid) as rnk
from invoicetable a
)
select *
from data a
left join data b
on a.rnk=b.rnk
and b.category=0
where a.category=1
Here is db fiddle link.
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=287f101737c580ca271940764b2536ae
You may try with the following approach. Dividing the table is done with (((ROW_NUMBER() OVER (ORDER BY IN_InvoiceID) - 1) / 5) % 2 = 0) which groups records in left and right groups.
CREATE TABLE #InvoiceTable(
IN_ID varchar(24),
IN_InvoiceID int
)
INSERT INTO #InvoiceTable (IN_ID, IN_InvoiceID)
VALUES
('2345-BCDE-6645-1DDF', 1),
('2345-BCDE-6645-3DDF', 2),
('2345-BCDE-6645-4DDF', 3),
('2345-BCDE-6645-5DDF', 4),
('2345-BCDE-6645-6DDF', 5),
('2345-BCDE-6645-7DDF', 6),
('2345-BCDE-6645-aDDF', 7),
('2345-BCDE-6645-sDDF', 8),
('2345-BCDE-6645-dDDF', 9),
('2345-BCDE-6645-dDDF', 10),
('2345-BCDE-6645-dDDF', 11),
('2345-BCDE-6645-dDDF', 12);
WITH cte AS (
SELECT
IN_ID,
IN_InvoiceID,
CASE
WHEN (((ROW_NUMBER() OVER (ORDER BY IN_InvoiceID) - 1) / 5) % 2 = 0) THEN 'L'
ELSE 'R'
END AS IN_Position
FROM #InvoiceTable
),
cteL AS (
SELECT IN_ID, IN_InvoiceID, ROW_NUMBER() OVER (ORDER BY IN_InvoiceID) AS IN_RowNumber
FROM cte
WHERE IN_Position = 'L'
),
cteR AS (
SELECT IN_ID, IN_InvoiceID, ROW_NUMBER() OVER (ORDER BY IN_InvoiceID) AS IN_RowNumber
FROM cte
WHERE IN_Position = 'R'
)
SELECT cteL.IN_ID, cteL.IN_InvoiceID, cteR.IN_ID, cteR.IN_InvoiceID
FROM cteL
LEFT JOIN cteR ON (cteL.IN_RowNumber = cteR.IN_RowNumber)
Output:
IN_ID IN_InvoiceID IN_ID IN_InvoiceID
2345-BCDE-6645-1DDF 1 2345-BCDE-6645-7DDF 6
2345-BCDE-6645-3DDF 2 2345-BCDE-6645-aDDF 7
2345-BCDE-6645-4DDF 3 2345-BCDE-6645-sDDF 8
2345-BCDE-6645-5DDF 4 2345-BCDE-6645-dDDF 9
2345-BCDE-6645-6DDF 5 2345-BCDE-6645-dDDF 10
2345-BCDE-6645-dDDF 11 NULL NULL
2345-BCDE-6645-dDDF 12 NULL NULL

SQL query with subqueries based on base values

Good morning; I have two tables that I am trying to work with to develop a single query with subquery and having issues if someone could help.
First Table - [MPA_Desc] - There is more data I parsed for example
MPAID Color Model Side
1 085 x1 R
2 777 x1 R
3 085 x1 L
4 777 x1 L
Second Table - [Paintsched] - There is more data I parsed for example
Lot MPAID Amount
1 1 100
2 2 250
3 4 100
4 2 100
I am trying to get this as my query result:
Color R L
085 100 0
777 350 100
This is the query and subquery I am using, It's incomplete and doesn't have the "LH" calculations in it because I want to get the RH right first:
Select distinct(mp.Color), rh.RH
from MPA_Desc MP
right join (Select MPA_Desc.MPAID, MPA_Desc.Color, nullif(sum(qty),0) as RH from PaintSched inner join MPA_Desc on PaintSched.MPAID = MPA_Desc.MPAID
where side = 'r' group by MPA_Desc.MPAID,MPA_Desc.Color) RH
ON mp.MPAID = rh.MPAID
where Model = 'x1'
But this however gives me the following result:
Color R
085 100
085 NULL
777 350
777 Null
I know it's from my full join but I need to show the Null's as "0" and I thought nullif would work but apparently not in a subquery. Secondly I need it to just show the List of color codes by model in the original query and seperate out the sums based on RH or LH parts. Any help would be great, thank you all!
You can use PIVOT
DECLARE #MPA_Desc TABLE (MPAID INT, Color VARCHAR(5), Model VARCHAR(5), Side VARCHAR(5))
INSERT INTO #MPA_Desc VALUES
(1 , '085', 'x1', 'R'),
(2 , '777', 'x1', 'R'),
(3 , '085', 'x1', 'L'),
(4 , '777', 'x1', 'L')
DECLARE #Paintsched TABLE (Lot INT, MPAID INT, Amount INT)
INSERT INTO #Paintsched VALUES
(1 ,1 , 100),
(2 ,2 , 250),
(3 ,4 , 100),
(4 ,2 , 100)
SELECT Color, ISNULL(R,0) R, ISNULL( L,0) L FROM
( SELECT Color, Side, Amount FROM #MPA_Desc D
INNER JOIN #Paintsched P ON D.MPAID = P.MPAID ) SRC
PIVOT (SUM(Amount) FOR Side IN ([R],[L])) PVT
Result:
Color R L
----- ----------- -----------
085 100 0
777 350 100
You need conditional aggregation :
select md.Color,
sum(case when Side = 'R' then ps.amount else 0 end),
sum(case when Side = 'L' then ps.amount else 0 end)
from MPA_Desc md inner join
Paintsched ps
on ps.MPAID = md.MPAID
group by md.Color;
Try the following (Its Dynamic) -:
Declare #sql varchar(MAX),#query nvarchar(MAX)
select #sql=stuff((select distinct ', sum(case when side='''+side+''' then amount else 0 end) as '+side from [MPA_Desc] FOR XML PATH ('')), 1, 1, '' )
set #query='select color,'+#sql+' from [MPA_Desc] m join [Paintsched] n on m.MPAID=n.MPAID group by color'
EXEC sp_sqlexec #query
SQL Server 2014

How to group the records according to the range in SQL

Hi I would like to create a SQL to group the records according to the range
For example, suppose I have
Number Time Price
100 20100810 10.0
100 20100812 15.0
160 20100810 10.0
200 20100810 12.0
210 20100811 13.0
300 20100811 14.0
350 20100810 16.0
Now I need to get the records according to the range of the "Number": [100,200),[200,300),[300,400) and [0,400]. For each range, I need the "Price" of the lastest "Time"
So the results should be
NumberRange Time Price
1 20100812 15.0
2 20100811 13.0
3 20100811 14.0
4 20100812 15.0
How can I construct a SQL statement to produce this?
I am not working on a specific Database. So I am looking for no specific database SQL statement
Use:
SELECT x.rank, x.time, x.price
FROM (SELECT *,
CASE
WHEN number BETWEEN 100 and 199 THEN 1
WHEN number BETWEEN 200 and 299 THEN 2
WHEN number BETWEEN 300 and 399 THEN 3
ELSE NULL
END AS rank
FROM TABLE) x
JOIN (SELECT t.rank,
MAX(t.time) AS max_time
FROM (SELECT *,
CASE
WHEN number BETWEEN 100 and 199 THEN 1
WHEN number BETWEEN 200 and 299 THEN 2
WHEN number BETWEEN 300 and 399 THEN 3
ELSE NULL
END AS rank
FROM TABLE) t
GROUP BY t.rank) y ON y.rank = x.rank
AND y.max_time = x.time
UNION ALL
SELECT x.rank, x.time, x.price
FROM (SELECT *,
CASE
WHEN number BETWEEN 0 and 400 THEN 4
ELSE NULL
END AS rank
FROM TABLE) x
JOIN (SELECT t.rank,
MAX(t.time) AS max_time
FROM (SELECT *,
CASE
WHEN number BETWEEN 0 and 400 THEN 4
ELSE NULL
END AS rank
FROM TABLE) t
GROUP BY t.rank) y ON y.rank = x.rank
AND y.max_time = x.time
Homework?
You could select an additional column with an if statement to determine what range id relevant. Then group by this new column.
Although some of the following requires fall outside of core Standard SQL, they are full Standard SQL features (e.g. row constructors are a full SQL-92 feature, CTEs are a full SQL-99 feature, etc), and will indeed be found in some products such as SQL Server and Oracle:
WITH MyTable (my_Number, my_Time, Price)
AS
(
SELECT my_Number, CAST(my_Time AS DATE),
CAST(Price AS DECIMAL(5, 2))
FROM (
VALUES (100, '2010-08-10', 10),
(100, '2010-08-12', 15),
(160, '2010-08-10', 10),
(200, '2010-08-10', 12),
(210, '2010-08-11', 13),
(300, '2010-08-11', 14),
(350, '2010-08-10', 16)
) AS MyTable (my_Number, my_Time, Price)
), Ranges (NumberRange, range_start, range_end)
AS
(
SELECT NumberRange, range_start, range_end
FROM (
VALUES (1, 100, 200),
(2, 200, 300),
(3, 300, 400),
(4, 0, 400)
) AS Ranges (NumberRange, range_start, range_end)
),
RangesMaxTimes (NumberRange, range_start, range_end, max_time)
AS
(
SELECT R1.NumberRange,
R1.range_start, R1.range_end,
MAX(M1.my_Time) AS max_time
FROM MyTable AS M1
INNER JOIN Ranges AS R1
ON R1.range_start <= M1.my_Number
AND M1.my_Number < R1.range_end
GROUP
BY R1.NumberRange, R1.range_start, R1.range_end
)
SELECT R1.NumberRange, M1.my_Time, M1.Price
FROM MyTable AS M1
INNER JOIN RangesMaxTimes AS R1
ON R1.range_start <= M1.my_Number
AND M1.my_Number < R1.range_end
AND M1.my_Time = R1.max_time;