Mysql Postgresql 9.4:在同一查询中使用计算列,并按月对部分结果进行分组

Mysql Postgresql 9.4:在同一查询中使用计算列,并按月对部分结果进行分组,mysql,postgresql,postgresql-9.4,integral,Mysql,Postgresql,Postgresql 9.4,Integral,我正在查询postgresql 9.4数据库,希望使用同一查询中的列执行计算 我试图获得的结果是一个基于总天数的部分值。例如 开工日期:2016年1月1日 持续时间(以月为单位):2 总天数:60天 价值x:120 如果我今天(2016年1月5日)启动查询,我希望获得: partial_result = value_x * passed_days / total_days 120 * 5 / 60 在我的数据集中,我有超过1

我正在查询postgresql 9.4数据库,希望使用同一查询中的列执行计算

我试图获得的结果是一个基于总天数的部分值。例如

  • 开工日期:2016年1月1日
  • 持续时间(以月为单位):2
  • 总天数:60天
  • 价值x:120
如果我今天(2016年1月5日)启动查询,我希望获得:

partial_result = value_x * passed_days / total_days
                  120   *      5      /    60
在我的数据集中,我有超过10万条记录,我需要按月将这个部分值分组(按月添加部分值)

=========================================================================

WITH time_ranges AS (
SELECT       to_date('2014-07-01', 'yyyy-mm-dd') as START_DATE, to_date('2014-07-31', 'yyyy-mm-dd') as END_DATE
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2014-08-31', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2014-09-30', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2014-10-31', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2014-11-30', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2014-12-31', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-01-31', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-02-28', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-03-31', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-04-30', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-05-31', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-06-30', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-07-31', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-08-31', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-09-30', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-10-31', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-11-30', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-12-31', 'yyyy-mm-dd')
  UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2016-01-05', 'yyyy-mm-dd')
)

SELECT time_ranges.end_date, round(SUM(gross_pdu * LEAST(total_days, GREATEST( EXTRACT(DAY FROM(time_ranges.end_date - guarantees_days.start_date)), 0) ) / total_days)::numeric, 2)
FROM
(SELECT
  *,
  EXTRACT(DAY FROM (start_date + (duration_in_months || ' month')::INTERVAL) - start_date) as total_days
FROM subscribed_guarantees
) as guarantees_days
INNER JOIN
time_ranges ON
time_ranges.start_date <= guarantees_days.start_date AND guarantees_days.start_date <= time_ranges.end_date
WHERE INSURANCE_COMPANY = 'INSURANCE COMPANY' AND TAX = 13.5
 GROUP BY
  time_ranges.end_date
 ORDER BY
  time_ranges.end_date
在MySQL中,我可以进行如下计算:

SELECT 
  start_date,
  duration_in_months, 
  @end_date:= DATE_ADD(start_date, INTERVAL duration_in_months MONTH) as end_date,
  @total_days:= DATEDIFF(@end_date, start_date),
  @passed_days:= DATEDIFF(CURDATE(), start_date),
  value_x,
  (value_x * @passed_days / @total_days) as partial_result

  FROM table;
按照本文中的说明,我目前正在PostgreSQL中使用如下查询:

SELECT
  start_date,
  duration_in_months,
  end_date,
  total_days,
  value_x,
  (value_x * passed_days / total_days) as partial_result

  FROM (SELECT *,
         (start_date + (duration_in_months || ' month')::INTERVAL) as end_date,
         EXTRACT(DAY FROM (start_date + (duration_in_months || ' month')::INTERVAL) - start_date) as total_days, 
         EXTRACT(DAY FROM current_date - start_date) as passed_days
        FROM table) as table1;
我需要您的帮助,以便:

  • 在PostgreSQL中使用计算变量,就像在MySQL中一样在查询中使用公式,或者找到其他方法使查询更具可读性
  • 将分部结果按月份分组
  • 插入where子句以确保


    passed_days>=0且passed_days首先,您的MySQL查询不能保证工作。MySQL文档非常明确,
    SELECT
    中表达式的求值顺序可以是任意的。因此,可以在设置变量之前计算最后一个表达式(实际上,它们将被设置为前一行中的值)

    在Postgres中,我认为您对子查询或CTE的想法是正确的。您只需引用不带
    @
    的列。我不知道具体的日期算法是否正确,但这是等效的查询:

    SELECT start_date, duration_in_months, end_date, total_days, value_x,
           (value_x * passed_days / total_days) as partial_result
    FROM (SELECT t.*,
                 (start_date + (duration_in_months || ' month')::INTERVAL) as end_date,
                 EXTRACT(DAY FROM (start_date + (duration_in_months || ' month')::INTERVAL) - start_date) as total_days, 
                 EXTRACT(DAY FROM current_date - start_date) as passed_days
          FROM table t
         ) t;
    

    extract(day)
    在我看来是错误的,但您是从
    间隔中提取日期,而不是从日期/时间表达式中提取。我认为它可以满足您的需要。

    因为您的表达式相互使用,所以应该使用多个子查询(如果您不想重复任何表达式)

    或者,您可以使用f.ex:

    DATEDIFF
    可以在PostgreSQL中使用
    date1-date2
    进行计算,无需使用
    EXTRACT
    (但参数的类型必须为
    date
    timestamp(tz)
    差异产生
    interval
    s)


    您可以使用来约束
    通过的天数
    (如果您想选择所有行),但如果您愿意,也可以在
    中的
    中使用
    通过的天数

    我在PostgreSQL中找到了一个合适的解决方案:

    • 按月分组:在查询开始时与table as()语句一起使用。然后做一个内部连接
    • 声明变量:使用子查询
    =========================================================================

    WITH time_ranges AS (
    SELECT       to_date('2014-07-01', 'yyyy-mm-dd') as START_DATE, to_date('2014-07-31', 'yyyy-mm-dd') as END_DATE
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2014-08-31', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2014-09-30', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2014-10-31', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2014-11-30', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2014-12-31', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-01-31', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-02-28', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-03-31', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-04-30', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-05-31', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-06-30', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-07-31', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-08-31', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-09-30', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-10-31', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-11-30', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2015-12-31', 'yyyy-mm-dd')
      UNION SELECT to_date('2014-07-01', 'yyyy-mm-dd'), to_date('2016-01-05', 'yyyy-mm-dd')
    )
    
    SELECT time_ranges.end_date, round(SUM(gross_pdu * LEAST(total_days, GREATEST( EXTRACT(DAY FROM(time_ranges.end_date - guarantees_days.start_date)), 0) ) / total_days)::numeric, 2)
    FROM
    (SELECT
      *,
      EXTRACT(DAY FROM (start_date + (duration_in_months || ' month')::INTERVAL) - start_date) as total_days
    FROM subscribed_guarantees
    ) as guarantees_days
    INNER JOIN
    time_ranges ON
    time_ranges.start_date <= guarantees_days.start_date AND guarantees_days.start_date <= time_ranges.end_date
    WHERE INSURANCE_COMPANY = 'INSURANCE COMPANY' AND TAX = 13.5
     GROUP BY
      time_ranges.end_date
     ORDER BY
      time_ranges.end_date
    
    时间范围如下的
    (
    选择截止日期(“2014-07-01”、“yyyy-mm-dd”)作为开始日期,选择截止日期(“2014-07-31”、“yyyy-mm-dd”)作为结束日期
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2014-08-31”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2014-09-30”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2014-10-31”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2014-11-30”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2014-12-31”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2015-01-31”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2015-02-28”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2015-03-31”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2015-04-30”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2015-05-31”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2015-06-30”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2015-07-31”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2015-08-31”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2015-09-30”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2015-10-31”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2015-11-30”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2015-12-31”、“yyyy-mm-dd”)
    工会选择截止日期(“2014-07-01”、“yyyy-mm-dd”)和截止日期(“2016-01-05”、“yyyy-mm-dd”)
    )
    选择时间范围。结束日期,四舍五入(总和(总pdu*最小(总天数),最大(提取(日期从(时间范围。结束日期-保证天数。开始日期)),0))/总天数)::数字,2)
    从…起
    (选择
    *,
    提取(从(开始日期+(持续时间以月为单位)::间隔)-开始日期)起的天作为总天数
    从认购的担保中
    )就像你的日子一样
    内连接
    时间范围
    
    谢谢你的回答。所以你认为在博士后中没有更好的方法吗?你将如何按月份对部分结果进行分组?以及如何确保通过天数为最大(通过天数,0)和最小(通过天数,总天数)?@mabe02。我在MySQL代码中没有看到任何这样的检查。但是在这两个数据库中,您都可以使用
    least()
    grest()
    。您能提供一些详细信息吗,比如您查询的表的DDL?你也可以用它;)创建表订阅担保(id整数、保险公司字符变化、总pdu数字(8,2)、税数字(8,2)、无时区的开始日期时间戳、持续时间(以月为单位)整数、“数字”整数、车牌字符变化、客户姓氏字符变化、客户姓名字符变化、经销商名称字符变化、产品描述字符变化、汽车信息模型