处理查询以返回员工开始轮班然后到达第一个家的平均时间(此DB假定他们是推销员)。
我有什么:
SELECT l.OFFICE_NAME, crew.EMPLOYEE_NAME, //avg(first arrival time)
FROM LOCAL_OFFICE l, CREW_WORK_SCHEDULE crew,
WHERE l.LOCAL_OFFICE_ID = crew1.LOCAL_OFFICE_ID
你可以看到AVG()命令被注释掉了,因为我知道他们到达工作的时间,以及他们到达第一宫的时间,并且可以使用这个来找到值:
(SELECT MIN(c.ARRIVE)
FROM ORDER_STATUS c
WHERE c.USER_ID = crew.CREW_ID)
-(SELECT START_TIME
FROM CREW_SHIFT_CODES
WHERE WORK_SHIFT_CODE = crew.WORK_SHIFT_CODE)
最好的方法是将上述内容放入AVG()括号吗?只是尝试学习创建查询的最佳方法。如果您想要更多关于任何表格的信息,请询问,但希望他们都被命名,以便您知道他们将返回什么。
答案 0 :(得分:2)
不要想到子查询:它们通常很慢。实际上,它们是逐行(RBAR)操作而不是基于设置
类似于
SELECT
l.OFFICE_NAME, crew.EMPLOYEE_NAME,
AVG(os.minARRIVE - cs.START_TIME)
FROM
LOCAL_OFFICE l
JOIN
CREW_WORK_SCHEDULE crew On l.LOCAL_OFFICE_ID = crew1.LOCAL_OFFICE_ID
JOIN
CREW_SHIFT_CODES cs ON cs.WORK_SHIFT_CODE = crew.WORK_SHIFT_CODE
JOIN
(SELECT MIN(ARRIVE) AS minARRIVE, USER_ID
FROM ORDER_STATUS
GROUP BY USER_ID
) os ON oc.USER_ID = crew.CREW_ID
GROUP B
l.OFFICE_NAME, crew.EMPLOYEE_NAME
由于minARRIVE分组,这可能无法提供正确的数据:ORDER_STATUS没有足够的信息来显示“哪一天”或“哪个班次”。它只是“始终为该用户首次到达”
编辑:
这将为您提供平均分钟
您可以使用DATEADD将其添加回minARRIVE,或使用某些%60(modul0)和/ 60(整数除法)更改为hh:mm
AVG(
DATEDIFF(minute, os.minARRIVE, os.minARRIVE)
)
答案 1 :(得分:2)
根据我的评论,您提供的示例只会将一条记录返回到AVG功能,因此不会做太多。
但是,如果子查询返回了多条记录,那么您将子查询放在AVG()
中的建议就可以了......
SELECT
AVG((SELECT MIN(sub.val) FROM sub WHERE sub.id = main.id GROUP BY sub.group))
FROM
main
GROUP BY
main.group
(平均一组最小值,因此需要两个GROUP BY级别。)
在许多情况下,这会提供良好的性能,并且可维护。但有时子查询会变大,最好使用内联视图重新格式化...
SELECT
main.group,
AVG(sub_query.val)
FROM
main
INNER JOIN
(
SELECT
sub.id,
sub.group,
MIN(sub.val) AS val
FROM
sub
GROUP BY
sub.id
sub.group
)
AS sub_query
ON sub_query.id = main.id
GROUP BY
main.group
注意:虽然看起来好像内联视图会计算出不需要的值(因此效率低下),但大多数RDBMS会优化这一点,因此只有所需的记录才能获得进程。 (优化器知道外部查询如何使用内部查询,并相应地构建执行计划。)