Pregunta

Estoy usando DATEDIFF en una instrucción SQL.Estoy a seleccionar, y tengo que utilizar en la cláusula where así.Esta declaración no funciona...

SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
WHERE InitialSave <= 10

Se da el mensaje: Nombre de columna no válido "InitialSave"

Pero esta instrucción funciona bien...

SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
WHERE DATEDIFF(ss, BegTime, EndTime) <= 10

El programador me dice que esto es ineficiente (parece que estoy llamando a la función dos veces).

Por lo tanto, dos preguntas.¿Por qué no la primera instrucción de trabajo?Es ineficiente para hacer uso de la segunda declaración?

¿Fue útil?

Solución

No se puede acceder a las columnas definidas en la instrucción SELECT en la cuenta de que, porque no están generados hasta después de la, donde ha ejecutado.

Usted puede hacer esto sin embargo

select InitialSave from 
(SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable) aTable
WHERE InitialSave <= 10

Como comentario - En esencia, esto mueve el DATEDIFF en el comunicado, donde en función de dónde se definió por primera vez. Uso de las funciones de las columnas en donde las declaraciones hace que los índices de no utilizarse la forma más eficiente y deben evitarse si es posible, sin embargo, si usted tiene que utilizar datediff entonces usted tiene que hacerlo!

Otros consejos

Nota: Cuando originalmente escribí esta respuesta me dijo que un índice en una de las columnas puede crear una consulta que funciona mejor que otras respuestas (y mencionó Dan Fuller).Sin embargo, yo no estaba pensando en el 100% correctamente.El hecho es que, sin una columna calculada o indexadas (materializado) punto de vista, un análisis completo de la tabla va a ser se requiere, porque la fecha de dos columnas que se comparan son de la mismo tabla!

Creo que todavía hay valor en la siguiente información, a saber: 1) la posibilidad de un mejor desempeño en la situación de derecho, como cuando la comparación es entre las columnas de diferentes tablas, y 2) promover el hábito de los desarrolladores de SQL de las siguientes mejores prácticas y la forma de su pensamiento en la dirección correcta.

Hacer Las Condiciones Sargable

La mejor práctica que me estoy refiriendo es el pasar de una columna a estar solo en un lado del operador de comparación, así:

SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM dbo.MyTable T
WHERE T.EndTime <= T.BegTime + '00:00:10'

Como dije, esto no va a evitar una exploración en una sola tabla, sin embargo, en una situación como esta podría hacer una gran diferencia:

SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM
   dbo.BeginTime B
   INNER JOIN dbo.EndTime E
      ON B.BeginTime <= E.EndTime
      AND B.BeginTime + '00:00:10' > E.EndTime

EndTime está en condiciones ahora solo en un lado de la comparación.Suponiendo que el BeginTime la tabla tiene muchos menos filas, y la EndTime la tabla tiene un índice en la columna EndTime, este llevará a cabo lejos, mucho mejor que cualquier cosa usando DateDiff(second, B.BeginTime, E.EndTime).Es ahora sargable, lo que significa que hay un válido argumento de búsqueda"--así como el motor de exploraciones el BeginTime tabla, se puede buscar en el EndTime tabla.La selección cuidadosa de la columna que está en un lado del operador es necesario-puede ser vale la pena experimentar por poner BeginTime por sí mismo haciendo algo de álgebra para cambiar a AND B.BeginTime > E.EndTime - '00:00:10'

Precisión de DateDiff

También debo señalar que DateDiff no volver transcurrido tiempo, pero en lugar de ello, se cuenta el número de los límites de cruzó.Si una llamada a DateDiff utilizando segundos devuelve 1, esto podría significar 3 ms transcurrido el tiempo, o podría significar 1997 ms!Esto es esencialmente una precisión de +- 1 unidades de tiempo.Para la mejor precisión de +- 1/2 unidad de tiempo, es conveniente que la consulta siguiente comparación 0 a EndTime - BegTime:

SELECT DateDiff(second, 0, EndTime - BegTime) AS InitialSave
FROM MyTable
WHERE EndTime <= BegTime + '00:00:10'

Esto ahora tiene un máximo de error de redondeo de solo un segundo total, no dos (en efecto, de un piso (a) la operación).Tenga en cuenta que sólo se puede restar el datetime tipo de datos-para restar un date o un time valor, usted tiene que convertir a datetime o utilizar otros métodos para obtener la mejor precisión (un montón de DateAdd, DateDiff y, posiblemente, otros no deseado, o tal vez con una mayor precisión el tiempo de la unidad y división).

Este principio es especialmente importante cuando el recuento de unidades más grandes, tales como horas, días, o meses.Un DateDiff de 1 month podría ser 62 días de diferencia (creo que el 1 de julio de 2013 - Agosto 31 de 2013)!

más allá de lo que es "trabajo", es necesario utilizar un índice

utilizar una columna calculada con un índice o una vista con un índice, de lo contrario recorrido de tabla. cuando recibe suficientes filas, se sentirá la DOLOR de la exploración lenta!

columna calculada y index:

ALTER TABLE MyTable ADD
    ComputedDate  AS DATEDIFF(ss,BegTime, EndTime)
GO
CREATE NONCLUSTERED INDEX IX_MyTable_ComputedDate  ON MyTable 
    (
    ComputedDate
    ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

crear un índice de vista y:

CREATE VIEW YourNewView
AS
SELECT
    KeyValues
        ,DATEDIFF(ss, BegTime, EndTime) AS InitialSave
    FROM MyTable
GO
CREATE CLUSTERED INDEX IX_YourNewView
    ON YourNewView(InitialSave)
GO

Se tiene que utilizar la función en lugar del alias de columna - que es lo mismo con la cuenta (*), etc. PITA

.

Como alternativa, puede utilizar columnas calculadas .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top