我想知道是否有写这个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;
该WHERE x.Cantidad > 0.00
意味着你消除子查询没有匹配任何行并返回NULL
任何结果。
如果子查询返回多行您当前的查询将失败与错误。如果你很高兴没有错误走在不测,那么你可以使用INNER JOIN
而不是4个类似的子查询,然后CROSS APPLY ... VALUES
四个联接的列值UNPIVOT成行。然后UNION
是到最后的分支。
SELECT I.Fecha,
I.IdTrabajador,
CAST(x.Cantidad / 3600.0 AS DECIMAL(18, 2)) AS Cantidad,
x.Motivo,
I.IdTrabajadorIncidencia
FROM [rrhh].TrabajadorIncidencia I
INNER JOIN [rrhh].TrabajadorHorario H
ON H.IdTrabajador = I.IdTrabajador
AND H.Estado = I.Estado
INNER JOIN [rrhh].TrabajadorHorarioDetalle HD
ON HD.IdTrabajadorHorario = H.IdTrabajadorHorario
AND HD.Estado = H.Estado
CROSS APPLY ( VALUES (DATEDIFF(second, I.HoraIngreso, HD.HoraInicio), 'Sobretiempo en hora de ingreso...'),
(DATEDIFF(second, HD.HoraFinRefrigerio, I.HoraInicioRefrigerio), 'Sobretiempo en hora de inicio de refrigerio...'),
(DATEDIFF(second, I.HoraFinRefrigerio, HD.HoraFinRefrigerio), 'Sobretiempo en hora de término de refrigerio...'),
(DATEDIFF(second, HD.HoraFin, I.HoraSalida), 'Sobretiempo en hora de salida...') ) x(Cantidad, Motivo)
WHERE x.Cantidad > 0
AND I.Estado = 1
AND I.IdIncidencia = 1
AND HD.Dia = DATENAME(dw, I.Fecha)
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 Fecha;