我正在尝试编写SQL查询,以便为给定时间段内给定用户执行的操作生成摘要行。我有以下相关的表结构:
用户
audit_periods(可以处理,运送,休息等)
audit_tasks
audit_task_types
对于给定时期内的每个用户,我想创建类似以下数据行的内容:
users.id users.email time_spent_processing time_spent_shipping ... number_of_scans number_of_pallets
将通过计算每个用户来计算:
我已经用尽了所有的SQL技巧(并不多),并提出了类似以下的内容:
select
u.id as user_id,
u.email as email,
u.team as team,
ap.period_type as period_type,
att.name,
time_to_sec(
timediff(least("2011-03-17 00:00:00", ifnull(ap.finished_at, utc_timestamp())), greatest("2011-03-16 00:00:00", ap.started_at))
) as period_duration,
sum(at.score) as period_score
from audit_periods as ap
inner join users as u on ap.user_id = u.id
left join audit_tasks as at on at.audit_period_id = ap.id
left join audit_task_types as att on at.audit_task_type_id = att.id
where (ap.started_at >= "2011-03-16 00:00:00" or (ap.finished_at >= "2011-03-17 00:00:00" and ap.finished_at <= "2011-03-17 00:00:00"))
and (ap.finished_at <= "2011-03-17 00:00:00" or (ap.started_at >= "2011-03-16 00:00:00" and ap.started_at <= "2011-03-16 00:00:00"))
and u.team in ("Foo", "Bar")
group by u.id, ap.id, at.id
但这似乎在功能上等同于最终选择所有审计任务。我也试过一些子查询,但收效甚微。更直接地,这会产生类似(跳过不太重要的列)的内容:
user_id | period_type | period_duration | name | score
1 processing 1800s scan 200
1 shipping 1000s place_in_pallet 100
1 shipping 1000s place_in_pallet 100
1 break 500s null null
我想要的时候:
user_id | processing | shipping | break | scan | place_in_pallet | score
1 1800s 1000s 500s 1 2 400
我可以轻松获取给定用户的所有audit_tasks并将其汇总到代码中,但我可能会在给定时间内获取数十万个audit_tasks,因此需要在SQL中完成。
只是要清楚 - 我正在寻找一个查询来为每个用户生成一行,其中包含从其他3个表中收集的摘要数据。因此,对于每个用户,我想知道他花了多少时间在每种类型的audit_period(3600秒处理,3200秒发货等),以及他执行的每个audit_task中有多少(5次扫描,放入10个项目)托盘等)。
我认为我有一个解决方案的元素,我只是将它们拼凑在一起时遇到了麻烦。我确切地知道如何在Ruby / Java / etc中实现这一点,但我认为我不太了解SQL以便知道我缺少哪个工具。我需要临时桌吗?工会?其他一些构造完全?
非常感谢任何帮助,我可以澄清上述内容是否完全无意义。
答案 0 :(得分:1)
您需要将其分解为两个交叉表查询,这些查询通过用户提供有关audit_periods的信息,另一个查询将由用户提供audit_task信息,然后将其连接到Users表。目前尚不清楚如何在每种情况下汇总信息。例如,如果给定用户有10 audit_period
行,那么查询应如何汇总这些持续时间?我假设这里的持续时间总和,但你可能想要一个最小值或最大值,甚至可能需要一个整体增量。
Select U.user_id
, AuditPeriodByUser.TotalDuration_Processing As processing
, AuditPeriodByUser.TotalDuration_Shipping As shipping
, AuditPeriodByUser.TotalDuration_Break As break
, AuditTasksByUser.TotalCount_Scan As scan
, AuditTasksByUser.TotalCount_Place_In_Pallet As place_in_pallet
, AuditTasksByUser.TotalScore As score
From users As U
Left Join (
Select AP.user_id
, Sum( Case When AP.period_type = 'processing'
Then Time_To_Sec(
TimeDiff(
Coalesce(AP.started_at, UTC_TIMESTAMP()), AP.finished_at ) ) )
As TotalDuration_Processing
, Sum( Case When AP.period_type = 'shipping'
Then Time_To_Sec(
TimeDiff(
Coalesce(AP.started_at, UTC_TIMESTAMP()), AP.finished_at ) ) )
As TotalDuration_Shipping
, Sum( Case When AP.period_type = 'break'
Then Time_To_Sec(
TimeDiff(
Coalesce(AP.started_at, UTC_TIMESTAMP()), AP.finished_at ) ) )
As TotalDuration_Break
From audit_periods As AP
Where AP.started_at >= @StartDate
And AP.finished_at <= @EndDate
Group by AP.user_id
) As AuditPeriodByUser
On AuditPeriodByUser.user_id = U.user_id
Left Join (
Select AP.user_id
, Sum( Case When AT.Name = 'scan' Then 1 Else 0 End ) As TotalCount_Scan
, Sum( Case When AT.Name = 'place_in_pallet' Then 1 Else 0 End ) As TotalCount_Place_In_Pallet
, Sum( AT.score ) As TotalScore
From audit_tasks As AT
Join audit_task_types As ATT
On ATT.id = AT.audit_task_type_id
Join audit_periods As AP
On AP.audit_period_id = AP.id
Where AP.started_at >= @StartDate
And AP.finished_at <= @EndDate
Group By AP.user_id
) As AuditTasksByUser
On AuditTasksByUser.user_id = U.user_id