SQL用于标识具有价格更改的行,逐个项目

时间:2018-04-17 00:32:47

标签: sql postgresql

我有一张桌子,里面有成千上万的水果商品。一些水果商品立即销售,其他水果商品在随后的日期以较低的价格重新定价以清理库存。每个商品条目都有唯一的ID / SKU,但在以新价格重新输入时会获得新的行ID。

Original Table                  
ID  Date    UID Fruit   Variety Price
1   3/1/18  100100  Apple   Fiji    2.99
2   3/1/18  100101  Apple   Gala    3.99
3   3/1/18  100102  Apple   HoneyCrisp  4.99
4   3/1/18  100201  Orange  Navel   2.49
5   3/1/18  100202  Orange  Clementine  2.79
6   3/1/18  100301  Cherry  Bing    1.99
7   3/1/18  100302  Cherry  Black   2.29
8   3/8/18  100100  Apple   Fiji    2.69
9   3/8/18  100202  Orange  Clementine  2.15
10  3/15/18 100302  Cherry  Black   1.79
11  3/22/18 100102  Apple   HoneyCrisp  4.49
12  3/29/18 100201  Orange  Navel   2.19

我正在寻找输出,其中列出了价格变化的项目,按UID分组,以便重新定价的项目显示在彼此相邻的行中,因此很容易在价格变化中查看比较,像这样:

Desired Results                 
ID  Date    UID Fruit   Variety Price
1   3/1/18  100100  Apple   Fiji    2.99
8   3/8/18  100100  Apple   Fiji    2.69
5   3/1/18  100202  Orange  Clementine  2.79
9   3/8/18  100202  Orange  Clementine  2.15
7   3/1/18  100302  Cherry  Black   2.29
10  3/15/18 100302  Cherry  Black   1.79
3   3/1/18  100102  Apple   HoneyCrisp  4.99
11  3/22/18 100102  Apple   HoneyCrisp  4.49
4   3/1/18  100201  Orange  Navel   2.49
12  3/29/18 100201  Orange  Navel   2.19

谢谢!

4 个答案:

答案 0 :(得分:2)

以下内容应该有效:

select t.ID, t.Date, t.UID, t.Fruit, t.Variety, t.Price
from tbl t 
join (
    select UID 
    from tbl 
    group by UID 
    having count(1) >= 2
) t2 
on t2.UID = t.UID 
where t.Fruit = 'Apple' -- if you want to filter by a particular fruit
order by t.UID, t.Date

基本上,您只是将表连接到自身的子集,其中该子集表示UID在表中多次出现的任何项。

当然,您需要替换实际的列名和表名。

编辑:窗口函数可能是实现第二个期望结果集的最佳方法:

select q.UID, q.Fruit, q.Variety, avg(percent_drop) 
from (
    select t.*
    , t2.price as reduced_price
    , (t.price - t2.price)::NUMERIC(10,2) as price_drop
    , (1 - (t2.price / t.price::FLOAT))::NUMERIC(10, 2) as percent_drop
    from (
      select row_number() over (partition by t.UID order by t.Date), t.* 
      from tbl t
    ) t
    join (
      select row_number() over (partition by t.UID order by t.Date), t.* 
      FROM tbl t
    ) t2
    on t2.UID = t.UID 
    and t2.row_number = t.row_number + 1
) q
group by q.UID, q.Fruit, q.Variety

请注意,这会再次将表格与自身联系起来,但这一次它会查找最近的"邻居"排,凭借日期。请注意,无论价格是增加还是减少,此查询都有效,但列别名假设在以后重新添加项目时价格会降低。目前UID,Fruit和Variety的外部查询分组可以查看每个UID基础上的平均%价格下降,但您可以在不执行任何分组的情况下查看所有产品的平均值所有在外部查询。

答案 1 :(得分:2)

我会使用窗口函数来执行此操作:

select ID, Date, UID, Fruit, Variety, Price
from (select t.*,
             min(t.price) over (partition by t.fruit, t.variety) as min_price,
             max(t.price) over (partition by t.fruit, t.variety) as max_price
      from t 
     ) t
where min_price <> max_price
order by fruit, variety, date;

答案 2 :(得分:1)

您可以在子查询上使用 Windows函数的另一种方法。

您可以将条件置于SELECT t.ID, t.Date, t.UID, t.Fruit, t.Variety, t.Price FROM ( SELECT uid,ROW_NUMBER() OVER(partition by UID ORDER BY UID, Date) RK FROM T )t2 INNER JOIN t t on t.uid = t2.uid AND RK >= 2 order by t.UID, t.Date 条款

然后自我加入。

UUID

sqlfiddle:http://sqlfiddle.com/#!15/755a0/22

答案 3 :(得分:0)

你也可以尝试这样的事情:

WITH FDATA AS(
SELECT 1 "ID",   CAST('2018/01/03' AS DATE) DT,  100100 "UID",  'Apple' FRUIT,   'Fiji' VARIETY,  '2.99' PRICE FROM DUAL
UNION
SELECT 2   , CAST('2018/01/03' AS DATE)  , 100101,  'Apple'  ,  'Gala'        ,'3.99' FROM DUAL
UNION        
SELECT 3   , CAST('2018/01/03' AS DATE)  , 100102,  'Apple'  ,  'HoneyCrisp'  ,'4.99' FROM DUAL
UNION        
SELECT 4   , CAST('2018/01/03' AS DATE)  , 100201,  'Orange' ,  'Navel'      , '2.49' FROM DUAL
UNION        
SELECT 5   , CAST('2018/01/03' AS DATE)  , 100202,  'Orange' ,  'Clementine'  ,'2.79' FROM DUAL
UNION        
SELECT 6   , CAST('2018/01/03' AS DATE)  , 100301,  'Cherry' ,  'Bing'       , '1.99' FROM DUAL
UNION        
SELECT 7   , CAST('2018/01/03' AS DATE)  , 100302,  'Cherry' ,  'Black'      , '2.29' FROM DUAL
UNION        
SELECT 8   , CAST('2018/03/08' AS DATE)  , 100100,  'Apple'  ,  'Fiji'       , '2.69' FROM DUAL
UNION        
SELECT 9   , CAST('2018/03/08' AS DATE)  , 100202,  'Orange' ,  'Clementine' , '2.15' FROM DUAL
UNION        
SELECT 10  , CAST('2018/03/15' AS DATE)  , 100302,  'Cherry' ,  'Black'      , '1.79' FROM DUAL
UNION        
SELECT 11  , CAST('2018/03/22' AS DATE)  , 100102,  'Apple'  ,  'HoneyCrisp' , '4.49' FROM DUAL
UNION        
SELECT 12  , CAST('2018/03/29' AS DATE)  , 100201,  'Orange' ,  'Navel'      , '2.19' FROM DUAL
UNION
SELECT 13   , CAST('2018/03/10' AS DATE)  , 100301,  'Cherry' ,  'Bing'       , '1.99' FROM DUAL
UNION        
SELECT 14   , CAST('2018/03/30' AS DATE)  , 100100,  'Apple'  ,  'Fiji'       , '3.19' FROM DUAL
)--SELECT "UID", FRUIT, VARIETY, PRICE, DT, MIN(PRICE) OVER (PARTITION BY UID, FRUIT, VARIETY) MIN_PRICE, MAX(PRICE) OVER (PARTITION BY UID, FRUIT, VARIETY) MAX_PRICE FROM FDATA;
SELECT
"ID", DT, "UID", FRUIT, VARIETY, PRICE
FROM(
SELECT 
"ID", "UID", FRUIT, VARIETY, PRICE, DT, MAX(PRICE) OVER (PARTITION BY UID, FRUIT, VARIETY) - MIN(PRICE) OVER (PARTITION BY UID, FRUIT, VARIETY) CHG
FROM FDATA)
WHERE CHG > 0
ORDER BY "UID", DT;