我有这个架构
我希望有一个查询来计算每个小时每月每位顾问的费用。换句话说,一名顾问每个月有一份工资,我想把他/她当月工作的小时数除以工资。
.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);
还有其他办法吗?是否可以在一个查询中解决它?
答案 0 :(得分:2)
模型对我来说并不完全清楚,所以我假设如下:
salaries.date
被定义为date
列,用于存储顾问付款的日期tasks.init_time
和task.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_time
和finish_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
,因为无论如何它们肯定被定义为varchar
或text
。
我为此做的样本数据:http://sqlfiddle.com/#!15/ae0c9
有点无关,但是: 您还应该不将组列列表放在括号中。将列列表放在Postgres的括号中会创建一个匿名记录,这与具有多个列完全不同。对于选择列表中的列也是如此。
答案 1 :(得分:0)
如果所有目标都将它放在一个查询中,那么只需确认一下,您是否尝试使用CTE实现它? 像
;WITH cte_pymt
AS
(
//Your existing query 1
)
SELECT <your required data> FROM cte_pymt