sql选择数字分割总和函数

时间:2016-04-12 02:57:05

标签: sql postgresql

我有这个架构

enter image description here

我希望有一个查询来计算每个小时每月每位顾问的费用。换句话说,一名顾问每个月有一份工资,我想把他/她当月工作的小时数除以工资。

.A

在选择

中无法执行此操作
SELECT
    concat_ws(' ', consultants.first_name::text, consultants.last_name::text) as name,
    EXTRACT(MONTH FROM tasks.init_time) as task_month,
    SUM(tasks.finish_time::timestamp::time - tasks.init_time::timestamp::time) as duration,
    EXTRACT(MONTH FROM salaries.payment_date) as salary_month,
    salaries.payment
FROM consultants
INNER JOIN tasks ON consultants.id = tasks.consultant_id
INNER JOIN salaries ON consultants.id = salaries.consultant_id
WHERE EXTRACT(MONTH FROM tasks.init_time) = EXTRACT(MONTH FROM salaries.payment_date)
GROUP BY (consultants.id, EXTRACT(MONTH FROM tasks.init_time), EXTRACT(MONTH FROM salaries.payment_date), salaries.payment);

还有其他办法吗?是否可以在一个查询中解决它?

2 个答案:

答案 0 :(得分:2)

对此答案的假设:

模型对我来说并不完全清楚,所以我假设如下:

  • 您正在使用PostgreSQL
  • salaries.date被定义为date列,用于存储顾问付款的日期
  • tasks.init_timetask.finish_time定义为timestamp存储数据&顾问开始并完成特定任务的时间。

据我所知,您加入 这个月的错误是错误的。首先,因为它还包括来自不同年份的月份,但更重要的是因为这将导致salaries的同一行出现多次的结果。我认为你需要加入完整的日期:

FROM consultants c 
  JOIN tasks t ON c.id = t.consultant_id
  JOIN salaries s ON c.id = s.consultant_id 
                 AND t.init_time::date = s.payment_date --<< here

如果我对数据类型的假设是正确的,那么转换为timestamp然后回到time是没用的也是错误的。没用,因为你可以简单地减去时间戳和错误,因为你忽略了时间戳中的实际日期,所以如果init_timefinish_time不在同一天,那么(尽管不太可能),结果是错误的。

因此,持续时间的计算可以简化为:

t.finish_time - t.init_time

要获得每月每小时的费用,您需要将interval(从一个时间戳减去另一个时间戳时的结果)转换为表示小时数的小数,您可以通过从中提取秒数来实现间隔然后除以3600,例如

extract(epoch from sum(t.finish_time - t.init_time)) / 3600)

如果您将付款总额除以该数字,则可获得每月每小时的费用:

SELECT concat_ws(' ', c.first_name, c.last_name) as name,
       to_char(s.payment_date, 'yyyy-mm') as salary_month,
       extract(epoch from sum(t.finish_time - t.init_time)) / 3600 as worked_hours, 
       sum(s.payment) / (extract(epoch from sum(t.finish_time - t.init_time)) / 3600) as cost_per_hour
FROM consultants c 
  JOIN tasks t ON c.id = t.consultant_id
  JOIN salaries s ON c.id = s.consultant_id AND t.init_time::date = s.payment_date
GROUP BY c.id, to_char(s.payment_date, 'yyyy-mm') --<< no parentheses!
order by name, salary_month;

如果您希望按月分解报告,您应该将月份转换为包含年份的内容。我使用to_char()来获取只有年份和月份的字符串。您还需要从salaries.payment子句中删除group by

您也不需要支付月份&#34;和#34;工资月&#34;因为两者总是和连接条件相同。

最后,您不需要为名称列投放::text,因为无论如何它们肯定被定义为varchartext

我为此做的样本数据:http://sqlfiddle.com/#!15/ae0c9

有点无关,但是: 您还应该将组列列表放在括号中。将列列表放在Postgres的括号中会创建一个匿名记录,这与具有多个列完全不同。对于选择列表中的列也是如此。

答案 1 :(得分:0)

如果所有目标都将它放在一个查询中,那么只需确认一下,您是否尝试使用CTE实现它? 像

    ;WITH cte_pymt
    AS
    (
    //Your existing query 1
    )
    SELECT <your required data> FROM cte_pymt