【问题标题】:Recursive select with conditions带条件的递归选择
【发布时间】:2013-01-11 20:25:42
【问题描述】:

我的问题如下:

  1. 我需要检查一个选择的值(average)是否为空
  2. 如果是,请运行选择以查找不同时期(日期)中的第一个非空值。
  3. 在此之后,执行一个操作来检查(日期 - 范围)的时间段,这是
  4. 然后做平均

人类语言

我想要所有产品的平均成本按期间分组

如果在特定期间,产品没有发票,我需要获取上一期间的平均值(如果有平均成本)。

期间不是月份,它们由客户定义,可以重叠 2 个月,例如:

2012-01-01 - 2012-01-29
2012-01-30 - 2012-02-27

如何在一个查询中做到这一点?
查询大致如下(average是我要比较值的列):

select
    p.id
    ,(select 
        avg(cost)
    from 
        invoices i 
    where 
        i.product_id = p.id 
        and i.add_date between $start_date
        and $end_date
    ) as average
from
    products p;

表/数据/查询

看到这个要点(它不是原始数据库,我现在做这个测试): https://gist.github.com/4520123

【问题讨论】:

  • 请写一个更能描述问题的标题。
  • 现在可以了吗?在 Postgre SQL 查询中使用条件递归选择
  • 请提供示例数据和预期输出。你可能认为这个问题很清楚,但大多数阅读的人不明白你想问什么。
  • @GordonLinoff 我现在编辑帖子。我认为当时的信息很好。
  • 顺便说一句,当我们询问样本数据时,something like this is what we were hoping for(左侧的测试设置,而不是右侧的不可能查询):

标签: php sql database postgresql


【解决方案1】:

解决问题的另一种方法是:

  1. 查找具有可用数据的最新月份。
  2. 从第一步获取当月的 avg()。

查询:

SELECT i.product_id, 
       max(date_trunc('month',i.add_date)) as last_month
FROM invoices i 
GROUP BY i.product_id

将为您提供上个月每个产品的可用数据。

然后:

SELECT p.id,
       avg(inv.cost)
FROM products p
JOIN invoices inv 
  ON inv.product_id = p.id
JOIN (SELECT i.product_id, 
             max(date_trunc('month',i.add_date)) as last_month
      FROM invoices i 
      GROUP BY i.product_id) last_inv 
  ON last_inv.product_id = inv.product_id
  AND last_inv.last_month = date_trunc('month',inv.add_date)

获取上个月的avg

【讨论】:

  • 这是一个很好的解决方案伊戈尔。我会尝试运行它。但就我而言,更好的解决方案是在一个查询中完成所有查询。
  • @PatrickMaciel 您只需要运行第二个查询。它有第一个作为子查询。我写它只是为了解释它是如何工作的。
  • @PatrickMaciel:您可以轻松地将其打包到一个查询中。使用子选择或 CTE。这是更好的解决方案,因为只计算相关的平均值。您的想法(当我阅读您的问题时),一个 recursive 查询,计算平均值是不可能的。 I tried it and failed with ERROR: aggregate functions not allowed in a recursive query's recursive term..
  • @ErwinBrandstetter 感谢我的朋友。我将尝试遵循此解决方案和您的评论。再次感谢。
【解决方案2】:

我想我明白了。您想连续检查不同时期的平均值。以下是三个时段的示例:

select p.id,
       coalesce(cost_period1, cost_period2, cost_period3) as average
from products p left outer join
     (select i.product_id, 
             avg(case when i.add_date between $start_date1 and $end_date1 then cost
                 end) as cost_period1,
             avg(case when i.add_date between $start_date2 and $end_date2 then cost
                 end) as cost_period2,
             avg(case when i.add_date between $start_date3 and $end_date3 then cost
                 end) as cost_period3
      from invoices i
      group by i.product_id
     ) ip
     on p.id = ip.product_id

这是一个未经测试的查询。在子查询中计算每个周期的平均值,然后选择第一个非NULL值。

根据您的评论,您只需将其转换为每个月的单独行。这里是一个典型的方式。 . .按年和月分组,然后选择最近可用的。

select p.id, avgcost
from products p left outer join
     (select ip.*, row_number() over (partition by product_id order by yearmon desc) as seqnum
      from (select i.product_id, year(add_date)*12+month(add_date) as yearmon,
                   avg(cost) as avgcost
            from invoices i
            group by i.product_id, year(add_date)*12+month(add_date)
           ) ip
      where seqnum = 1
     ) ip
     on p.id = ip.product_id

【讨论】:

  • 感谢您的帮助,但不是这样,因为我没有“excacly”期间的日期。我需要回来,月复一月,直到找到结果。
【解决方案3】:

我在同事朋友的帮助下使用此查询解决了这个问题。

我所做的是,我获取了最后一次购买(发票)、特定产品(饮料)并计算了平均值。

    select (sum(aux.price * aux.quantity) / sum(aux.quantity))
    from (select    inp.price, inp.quantity, prd.product, drk.drink_num, inv.add_date
                        from    invoices                                inv
            inner join invoice_products inp on inp.invoice = inv.invoice
            inner join products                 prd on prd.product = inp.product
            inner join drinks                       drk on drk.product = prd.product) aux,
    date_period dtp
    where 
            aux.add_date between dtp.starting_date and dtp.ending_date
            and aux.drink_num = 1836 -- example id
            and dtp.year <= 2012 -- current year search
    group by
            dtp.year,
            dtp.period
    order by 
            dtp.year desc,
            dtp.period desc
    limit 1

无论如何,谢谢大家!

【讨论】:

    猜你喜欢
    • 2023-03-31
    • 2016-06-24
    • 1970-01-01
    • 1970-01-01
    • 2013-01-17
    • 2018-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多