我想知道在性能和稳定性方面是否有更好的方法来编写此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查询工作正常,但可能会更好。 谢谢。
答案 0 :(得分:1)
您可以使用公用表表达式(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;
答案 1 :(得分:0)
WHERE x.Cantidad > 0.00
意味着您消除了子查询不匹配任何行并返回NULL
的所有结果。
如果子查询返回多行,您当前的查询将失败并显示错误。如果您很乐意避免出现这种错误,那么可以使用INNER JOIN
而不是4个类似的子查询,然后使用CROSS APPLY ... VALUES
将四个联接的列值取消透视成行。然后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;