使用JOIN构建SQL查询并限制

时间:2017-08-18 16:23:21

标签: sql postgresql join left-join

请帮我构建PostgreSQL查询。 有2个表:产品(ID,标题)和价格(id,product_id,price_type,时刻,价值)

时刻 - 时间戳,可以是过去或未来

假设price_type只有两个选项:零售购买

但是,一种产品可能会有不同时刻的零售价格。

我需要选择所有具有实际零售价和购买价的产品,其中的时刻不到现在。

我可以做到

SELECT 
      products.id, 
      products.title_translations AS title,
      retail_prices.moment AS ret_moment,
      pur_prices.value AS purchase,
      retail_prices.value AS retail
FROM products 
LEFT OUTER JOIN prices AS pur_prices ON products.id=pur_prices.product_id AND pur_prices.price_type='purchase' AND pur_prices.moment<current_timestamp
LEFT OUTER JOIN prices AS retail_prices ON products.id=retail_prices.product_id AND retail_prices.price_type='retail' AND retail_prices.moment<current_timestamp
ORDER BY products.id;

它有效但返回 所有价格的产品,但我只需要最后的价格(按时)。

3 个答案:

答案 0 :(得分:2)

只需使用ROW_NUMBER查找当前时间之前的最后价格

with last_prices as (
    SELECT 
          products.id, 
          products.title_translations AS title,
          prices.moment,
          prices.value,
          prices.price_type,
          ROW_NUMBER() OVER (PARTITION BY product_id, price_type 
                             ORDER BY moment DESC) as rn
    FROM products 
    LEFT JOIN prices
      ON products.id = prices.product_id 
    WHERE moment < now() 
  )
SELECT id, title, 
       MAX(CASE WHEN price_type = 'retail'
                THEN moment
           END) as retail_moment,
       MAX(CASE WHEN price_type = 'retail'
                THEN value
           END) as retail_price,
       MAX(CASE WHEN price_type = 'purchase'
                THEN moment
           END) as purchase_moment,
       MAX(CASE WHEN price_type = 'purchase'
                THEN value
           END) as purchase_price
FROM last_prices     
WHERE rn = 1
GROUP BY id, title
ORDER BY id

答案 1 :(得分:2)

为了让事情井井有条,我会直接考虑,我会使用CTE生成两个价格数据子集,一个用于零售购买一个子集,并按升序排列一个行号,最小数量最多最近时刻小于currenttimestmap。然后当我们加入这些ctes时,我们只返回指定的最小数字。

With Pur_prices as (SELECT P.*, row_Number() over (partition by product_ID order by moment desc) RN
                    FROM prices P 
                    WHERE price_Type = 'purchase'
                    and p.moment < current_timestamp)

, Retail_prices as (SELECT P.*, row_Number() over (partition by product_ID order by moment desc) RN
                    FROM prices P 
                    WHERE price_Type = 'retail'
                    and p.moment < current_timestamp)

SELECT 
      p.id, 
      p.title_translations AS title,
      rp.moment AS ret_moment,
      rp.value AS retail,
      pp.moment AS Pur_moment,
      pp.value AS purchase
FROM products p
LEFT JOIN pur_prices pp
  ON p.id=pp.product_id 
 AND pp.RN = 1  --Only show the most recent price less than current time
LEFT JOIN retail_prices rp
  ON p.id=rp.product_id 
 AND RP.RN = 1 --Only show the most recent price less than current time
ORDER BY p.id;

最终结果应该是所有产品,无论他们是零售价还是购买价;但如果他们确实显示了之前最近时刻的零售/购买价格。我唯一担心的是这意味着所有定价都有一个开始的时刻(不允许空值!)

答案 2 :(得分:0)

您可能希望按照降序排列。 更改 ORDER BY products.id;ORDER BY product.id ASC, moment DESC;