Postgres get first and last version for individual vendor

瘦欲@ 提交于 2020-01-14 13:53:08

问题


I have mapping table for RFQ(request for quotation) and Vendor's bid amount with version.

Table :

id  rfq_id(FK)  vendor_id(FK)   amount  version
-----------------------------------------------

 1      1           1            100      1
 2      1           1            90       2
 3      1           1            80       3
 4      1           2            50       1
 5      1           7            500      1
 6      1           7            495      2
 7      1           7            500      3
 8      1           7            525      4
 9      1           7            450      5
 10     1           7            430      6 
 11     2           1            200      1
 12     2           2            300      1
 13     2           2            350      2
 14     2           3            40       1
 15     3           4            70       1 

In above table, I want analysis for vendor's first and last bid for particular rfq_id.

Expected Output for rfq_id=1 :

vendor_id   first_bid   last_bid
---------------------------------
    1           100         80
    2           50          50
    7           500         430

From Postgres : get min and max rows count in many to many relation table I have came to know about window and partition. So I have tried below query.

SELECT 
  vendor_id,
  version,
  amount,
  first_value(amount) over w as first_bid,
  last_value(amount) over w as last_bid,
  row_number() over w as rn
FROM   
   rfq_vendor_version_mapping
where
   rfq_id=1
   WINDOW w AS (PARTITION BY vendor_id order by version)
ORDER by vendor_id;

With above query, every vendor's maximum rn is my output.

http://sqlfiddle.com/#!15/f19a0/7


回答1:


Window functions add columns to all the existing rows, instead of grouping input rows into a single output row. Since you are only interested in the bid values, use a DISTINCT clause on the fields of interest.

Note that you need a frame clause for the WINDOW definition to make sure that all rows in the partition are considered. By default, the frame in the partition (the rows that are being used in calculations) runs from the beginning of the partition to the current row. Therefore, the last_value() window function always returns the value of the current row; use a frame of UNBOUNDED PRECEDING TO UNBOUNDED FOLLOWING to extend the frame to the entire partition.

SELECT DISTINCT
  vendor_id,
  version,
  amount,
  first_value(amount) OVER w AS first_bid,
  last_value(amount) OVER w AS last_bid
  row_number() over w as rn
FROM   
   rfq_vendor_version_mapping
WHERE rfq_id = 1
WINDOW w AS (PARTITION BY vendor_id ORDER BY version
             ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
ORDER BY vendor_id;



回答2:


You have to GROUP BY vendor_id because you want just one row per vendor_id:

SELECT 
  vendor_id,
  MAX(CASE WHEN rn = 1 THEN amount END) AS first_bid,
  MAX(CASE WHEN rn2 = 1 THEN amount END) AS last_bid
FROM (  
   SELECT 
     vendor_id,
     version,
     amount,
     row_number() over (PARTITION BY vendor_id order BY version) as rn,
     row_number() over (PARTITION BY vendor_id order BY version DESC) as rn2
   FROM   
      rfq_vendor_version_mapping
   WHERE
      rfq_id=1) AS t
GROUP BY vendor_id 
ORDER by vendor_id;

The query uses conditional aggregation in order to extract amount values that correspond to first and last bid.

Demo here




回答3:


Without ORDER BY OLAP-functions default to ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING but with ORDER BY this changes to ROW UNBOUNDED PRECEDING.

You were quite close, but you need two different windows:

select vendor_id, amount as first_bid, last_bid
from 
 (
    SELECT 
      vendor_id,
      version,
      amount,
      last_value(amount) -- highest version's bid
      over (PARTITION BY vendor_id 
            order by version
            rows between unbiunded preceding and unbounded following) as last_bid,
      row_number()
      over (PARTITION BY vendor_id 
            order by version) as rn
    FROM   
       rfq_vendor_version_mapping
    where
       rfq_id=1 
 ) as dt
where rn = 1 -- row with first version/bid
ORDER by vendor_id;


来源:https://stackoverflow.com/questions/40520986/postgres-get-first-and-last-version-for-individual-vendor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!