Finding the minimum of two columns from two different rows in a SQL table
-
21-12-2019 - |
Pergunta
I am working on a SQL View which returns difference of two columns and minimum value of two columns that belongs to two different rows of single table.
I was able to find the difference but was not able to return the minimum value of two columns
I have the following table
id Market Grade Term BidVolume Bid Offer OfferVolume
1 Heavy ABC Jun14 1000 -19.5 -17 2500
2 Heavy ABC Jul14 2000 -20 -17.5 1400
3 Sour XYZ Jun14 3000 -30 -17 2300
4 Sour XYZ Jul14 1500 -32 -27 2900
And I have the following SQL query and its results below
CREATE VIEW [dbo].[InferredBids] AS
WITH numbered AS
( SELECT id, product, grade, term, bid, offer, termid, bidVolume, offerVolume,
row_number() OVER (Partition BY Product, Grade ORDER BY termid) i
FROM dbo.CanadianCrudes) --select * from numbered
SELECT r1.id AS Id,
r1.product + '/' + r1.grade AS Market,
r1.term + '/' + r2.term AS Term,
r1.Bid - r2.Offer [Bid], r1.Offer - r2.Bid [Offer]
FROM numbered r1
JOIN numbered r2 ON r1.product = r2.product
AND r1.grade = r2.grade
AND r1.termid+1=r2.termid
AND r1.i<r2.i
AND r1.term!=r2.term
And Results are as follows fro the above query
Market Term Bid Offer
Heavy/ABC Jun14/Jul14 (-19.5-(-17.5))=-2 (-17-(-20))=3
Sour/XYZ Jun14/Jul14 (-30-(-27))=-3 (-17-(-32))=15
But I am trying to include another 2 columns called BidVolume and OfferVolume and results should be something like following
Market Term BidVolume Bid Offer OfferVolume
Heavy/ABC Jun14/Jul14 Min(1000,1400)=1000 (-19.5-(-17.5))=-2 (-17-(-20))=3 Min(2500,2000)=2000
Sour/XYZ Jun14/Jul14 Min(3000,2900)=2900 (-30-(-27))=-3 (-17-(-32))=15 Min(2300,1500)=1500
What would be the best way to include them
Solução
Aggregate functions, such as MIN
are for aggregating across multiple rows, and will not do what you expect here (as you've already found out). Instead, you should use a case
to choose which table and column to show from. Yes, I mean "table" here because your two joined rows are coming from separate logical tables, aliased t1
and t2
.
For example, for BidVolume
:
case when r1.BidVolume < r2.OfferVolume then r1.BidVolume else r2.OfferVolume end
Outras dicas
Sorry -I misread the problem.
The real answer is that the first answer you received was close. The problem is its only comparing 2 of the 4 values.
In your SQL, you are always comparing 2 columns across 2 records - and you need the minimum of 4 different values, so in mysql, you would do this:
least( r1.bidVolume, r1.offerVolume, r2.bidVolume, r2.offerVolume) as Minimum_Volume
here's my original answer for posterity To get the aggregate minimum from two different columns, you need a) expression that obtains the minimum value from the two columns for a given row b) aggregate minimum of the above expression across all rows
For a), I will use mysql "IF" syntax, and you can adjust to the sql of your choice. The following query will select the minimum between the Bid and Offer volumes from the first table you posted on a per Market and per Grade basis:
select Market, Grade, min( if( BidVolume < OfferVolume, BidVolume, OfferVolume)) MinVol
from YourTable
group by Market, Grade
;
If you use the above as a template, you can adjust as needed for other business rules.
The results of the above would be:
Market Grade MinVol
Heavy ABC 1000
Sour XYZ 1500