sql - 有没有更好的方法来编写这个 sql 查询(联合)?
问题描述
我想知道在性能和稳定性方面是否有更好的方法来编写这个 sql 查询。
因为,我想我重复了很多次代码,也许我可以用 CASE 子句或其他子句来做到这一点。
SELECT x.Fecha,x.IdTrabajador,Cast(x.Cantidad AS DECIMAL(18, 2)) AS Cantidad,x.Motivo,x.IdTrabajadorIncidencia
FROM (SELECT I.IdTrabajador,I.Fecha,
Datediff(second, I.HoraIngreso, (SELECT HD.HoraInicio
FROM [rrhh].TrabajadorHorarioDetalle HD
INNER JOIN [rrhh].TrabajadorHorario H
ON HD.IdTrabajadorHorario = H.IdTrabajadorHorario
WHERE H.Estado = 1
AND HD.Estado = 1
AND HD.Dia = Datename(dw, I.Fecha)
AND H.IdTrabajador = I.IdTrabajador)) / 3600.0 AS Cantidad,
'Sobretiempo en hora de ingreso...' AS Motivo,I.IdTrabajadorIncidencia
FROM [rrhh].TrabajadorIncidencia I
WHERE I.Estado = 1
AND I.IdIncidencia = 1) AS x
WHERE x.Cantidad > 0.00
UNION
SELECT x.Fecha,x.IdTrabajador,Cast(x.Cantidad AS DECIMAL(18, 2)) AS Cantidad,x.Motivo,x.IdTrabajadorIncidencia
FROM (SELECT I.IdTrabajador,I.Fecha,
Datediff(second, (SELECT HD.HoraInicioRefrigerio
FROM [rrhh].TrabajadorHorarioDetalle HD
INNER JOIN [rrhh].TrabajadorHorario H
ON HD.IdTrabajadorHorario = H.IdTrabajadorHorario
WHERE H.Estado = 1
AND HD.Estado = 1
AND HD.Dia = Datename(dw, I.Fecha)
AND H.IdTrabajador = I.IdTrabajador), I.HoraInicioRefrigerio) / 3600.0 AS Cantidad,
'Sobretiempo en hora de inicio de refrigerio...' AS Motivo,I.IdTrabajadorIncidencia
FROM [rrhh].TrabajadorIncidencia I
WHERE I.Estado = 1
AND I.IdIncidencia = 1) AS x
WHERE x.Cantidad > 0.00
UNION
SELECT x.Fecha,x.IdTrabajador,Cast(x.Cantidad AS DECIMAL(18, 2)) AS Cantidad,x.Motivo,x.IdTrabajadorIncidencia
FROM (SELECT I.IdTrabajador,I.Fecha,
Datediff(second, I.HoraFinRefrigerio, (SELECT HD.HoraFinRefrigerio
FROM [rrhh].TrabajadorHorarioDetalle HD
INNER JOIN [rrhh].TrabajadorHorario H
ON HD.IdTrabajadorHorario = H.IdTrabajadorHorario
WHERE H.Estado = 1
AND HD.Estado = 1
AND HD.Dia = Datename(dw, I.Fecha)
AND H.IdTrabajador = I.IdTrabajador)) / 3600.0 AS Cantidad,
'Sobretiempo en hora de término de refrigerio...' AS Motivo,I.IdTrabajadorIncidencia
FROM [rrhh].TrabajadorIncidencia I
WHERE I.Estado = 1
AND I.IdIncidencia = 1) AS x
WHERE x.Cantidad > 0.00
UNION
SELECT x.Fecha,x.IdTrabajador,Cast(x.Cantidad AS DECIMAL(18, 2)) AS Cantidad,x.Motivo,x.IdTrabajadorIncidencia
FROM (SELECT I.IdTrabajador,I.Fecha,
Datediff(second, (SELECT HD.HoraFin
FROM [rrhh].TrabajadorHorarioDetalle HD
INNER JOIN [rrhh].TrabajadorHorario H
ON HD.IdTrabajadorHorario = H.IdTrabajadorHorario
WHERE H.Estado = 1
AND HD.Estado = 1
AND HD.Dia = Datename(dw, I.Fecha)
AND H.IdTrabajador = I.IdTrabajador), I.HoraSalida) / 3600.0 AS Cantidad,
'Sobretiempo en hora de salida...' AS Motivo,I.IdTrabajadorIncidencia
FROM [rrhh].TrabajadorIncidencia I
WHERE I.Estado = 1
AND I.IdIncidencia = 1) AS x
WHERE x.Cantidad > 0.00
UNION
--Search Horas Extras (HE25 y HE35) in table TrabajadorIncidencia
SELECT x.Fecha,x.IdTrabajador,Cast(x.Cantidad AS DECIMAL(18, 2)) AS Cantidad,x.Motivo,x.IdTrabajadorIncidencia
FROM (SELECT I.IdTrabajador,I.Fecha,Datediff(second, I.HoraIngreso, I.HoraSalida) / 3600.0 AS Cantidad,'Sobretiempo en hora extra registrada...' AS Motivo,I.IdTrabajadorIncidencia
FROM [rrhh].TrabajadorIncidencia I
WHERE I.Estado = 1
AND ( I.IdIncidencia = 2
OR I.IdIncidencia = 4 )) AS x
WHERE x.Cantidad > 0.00
ORDER BY x.Fecha;
前面的 sql 查询运行良好,但可能会更好。谢谢。
解决方案
您可以使用公用表表达式 (CTE) 来分解问题。在下面的示例中,我将问题分解为各个部分。我认为最终结果更容易遵循。
不要认为 CTE 会创建任何额外的处理。我经常对 SQL Server 的查询计划器如何高效地使用它们感到惊讶。
一些警告:结果可能会有所不同,因为 DATEDIFF 函数中的 SELECT 已被删除并替换为 JOIN。我将假设您与给定的谓词具有一对一的关系,否则您会遇到错误。此外,我可能在剪切和粘贴时犯了一个错误,所以如果它没有运行,请不要感到惊讶。
WITH TrabajadorIncidenciaDetalleCte AS (
SELECT I.*, HD.HoraInicio, HD.HoraFinRefrigerio, HD.HoraFin
FROM [rrhh].TrabajadorIncidencia I
INNER JOIN [rrhh].TrabajadorHorarioDetalle HD ON HD.Dia = DATENAME(dw, I.Fecha)
INNER JOIN [rrhh].TrabajadorHorario H ON HD.IdTrabajadorHorario = H.IdTrabajadorHorario AND H.IdTrabajador = I.IdTrabajador
WHERE H.Estado = 1 AND HD.Estado = 1 AND I.Estado = 1 AND I.IdIncidencia = 1
)
, IncidenciaCte AS (
SELECT IdTrabajador,Fecha, DATEDIFF(second, HoraIngreso, HoraInicio) AS Cantidad,
'Sobretiempo en hora de ingreso...' AS Motivo, IdTrabajadorIncidencia
FROM TrabajadorIncidenciaDetalleCte
UNION ALL
SELECT IdTrabajador,Fecha, DATEDIFF(second, HoraInicioRefrigerio, HoraFinRefrigerio) AS Cantidad,
'Sobretiempo en hora de término de refrigerio...' AS Motivo, IdTrabajadorIncidencia
FROM TrabajadorIncidenciaDetalleCte
UNION ALL
SELECT IdTrabajador,Fecha, DATEDIFF(second, HoraFin, HoraSalida) AS Cantidad,
'Sobretiempo en hora de salida...' AS Motivo, IdTrabajadorIncidencia
FROM TrabajadorIncidenciaDetalleCte
UNION ALL
SELECT IdTrabajador, Fecha, DATEDIFF(second, HoraIngreso, HoraSalida) AS Cantidad,
'Sobretiempo en hora extra registrada...' AS Motivo, IdTrabajadorIncidencia
FROM [rrhh].TrabajadorIncidencia
WHERE Estado = 1 AND ( IdIncidencia = 2 OR IdIncidencia = 4 )
)
SELECT x.Fecha, x.IdTrabajador,
CAST((x.Cantidad / 3600.0) AS DECIMAL(18, 2)) AS Cantidad,
x.Motivo, x.IdTrabajadorIncidencia
FROM IncidenciaCte x
WHERE x.Cantidad > 0.00
ORDER BY x.Fecha;
推荐阅读
- python - 鼠标停止时如何显示此消息
- python - 我们如何编写查询集来比较不同模型的两个 id 并以 html 形式获取与 id 相关的数据,如名称、地址
- c# - 使用 .NET 4.5 的 64 位应用程序调用本机 DLL 方法时出现错误 0xc0000374
- php - PHP/HTML 表单:将多个用户输入存储在一个数组中
- ios - 在界面生成器中寻求手动更新 xib(自定义视图)cocoatouch 类文件的方法?
- visual-studio-code - Pylance 和 matplotlib 的问题
- reactjs - 传递道具进行渲染
- html - 如何在css中断词
- common-lisp - 默认情况下,KEYWORD 包中包含哪些符号?
- python - 为什么使用小数法时 0.2 不等于 0.2?