2011-03-09 25 views
5

Supongo que siempre he supuesto que las funciones escalares en la parte seleccionada de una consulta SQL solo se aplicarán a las filas que cumplan con todos los criterios de la cláusula where.¿Se pueden aplicar las funciones escalares antes de filtrar cuando se ejecuta una instrucción SQL?

Hoy estaba depurando un código de un proveedor y tuve esa suposición cuestionada. La única razón por la que se me ocurre la falla de este código es que se llama a la función Substring() a los datos que deberían haber sido filtrados por la cláusula WHERE. Pero parece que la llamada de subcadena se está aplicando antes de que ocurra el filtrado, la consulta está fallando. Aquí hay un ejemplo de lo que quiero decir. Digamos que tenemos dos tablas, cada una con 2 columnas y con 2 filas y 1 fila respectivamente. La primera columna en cada una es solo una identificación. NAME es solo una cadena, y NAME_LENGTH nos dice cuántos caracteres en el nombre con la misma ID. Tenga en cuenta que solo los nombres con más de un carácter tienen una fila correspondiente en la tabla LONG_NAMES.

NAMES: ID, NAME 
    1, "Peter" 
    2, "X" 
LONG_NAMES: ID, NAME_LENGTH 
    1, 5 

Si quiero una consulta para imprimir los nombres con los últimos 3 letras cortadas, por primera vez podría intentar algo como esto (suponiendo sintaxis de SQL Server por ahora):

SELECT substring(NAME,1,len(NAME)-3) 
    FROM NAMES; 

lo haría pronto descubro que esto me daría un error, porque cuando llegue a "X" intentará usar un número negativo para en la llamada de subcadena, y fallará. La forma en que mi proveedor decidió resolver esto fue filtrando las filas donde las cadenas eran demasiado cortas para que la consulta de len 3 funcionara. Lo hizo mediante la unión a otra tabla:

SELECT substring(NAMES.NAME,1,len(NAMES.NAME)-3) 
    FROM NAMES 
     INNER JOIN LONG_NAMES 
      ON NAMES.ID = LONG_NAMES.ID; 

A primera vista, esta consulta parece que podría trabajar. La condición de unión eliminará cualquier fila que tenga campos NAME suficientemente cortos para que falle la llamada de subcadena.

Sin embargo, de lo que puedo observar, SQL Server veces tratan de calcular la expresión de la subcadena para todo en la mesa, y luego aplicar la unión de filtrar filas. ¿Se supone que esto sucederá de esta manera? ¿Hay un orden de operaciones documentado donde pueda saber cuándo sucederán ciertas cosas? ¿Es específico para un motor de Base de datos particular o parte del estándar SQL? Si decidiera incluir algún predicado en mi tabla de NOMBRES para filtrar los nombres cortos, (como len (NAME)> 3), ¿SQL Server también podría elegir aplicar eso después de intentar aplicar la subcadena? Si es así, parece que la única forma segura de hacer una subcadena sería envolverla en un constructo "case when" en el select?

+4

Sí. 'CASE' es la única forma segura de hacerlo. Consulte http://stackoverflow.com/questions/5191701/tsql-divide-by-zero-encountered-despite-no-columns-containing-0/5203211#5203211 para obtener una buena respuesta sobre este tema. –

+0

@Martin gracias por el enlace. No pude encontrar la manera de buscar preguntas similares a esta, ya que es algo abstracto. –

Respuesta

0

Estás pensando en algo llamado plan de ejecución de consultas. Se basa en reglas de optimización de consultas, índices, búferes temporales y estadísticas de tiempo de ejecución. Si está utilizando SQL Managment Studio tiene una caja de herramientas sobre su editor de consultas donde puede ver el plan de ejecución estimado, muestra cómo su consulta cambiará para ganar algo de velocidad. Entonces, si solo usó su tabla Name y está en buffer, el motor podría primero intentar subconsultar sus datos, y luego unirlos con otra tabla.

2

Martin dio este enlace que explica bastante bien lo que está sucediendo: el optimizador de consultas tiene rienda suelta para reordenar las cosas como quiera. Estoy incluyendo esto como una respuesta para poder aceptar algo. Martin, si creas una respuesta con tu enlace en ella, con gusto la aceptaré en lugar de esta.

Quiero dejar mi pregunta aquí porque creo que es difícil de encontrar, y mi frase particular del problema puede ser más fácil de encontrar para otra persona en el futuro.

TSQL divide by zero encountered despite no columns containing 0

EDIT: A medida que más respuestas han llegado, estoy otra vez confundido. Todavía no parece claro cuándo exactamente el optimizador puede evaluar cosas en la cláusula de selección. Supongo que tendré que buscar el estándar SQL yo mismo y ver si puedo darle sentido.

+0

Un dbms que cumpla con los estándares SQL tiene * algo * de libertad para reordenar cosas, pero no tiene rienda suelta para reordenar las cosas como lo desee. Todavía se requiere para producir los mismos resultados que una evaluación de la consulta sin lápiz optimizado, fuerza bruta, paso a paso, lápiz y papel. Y en este caso, estoy bastante seguro de que eso significa que tiene que actuar como si evaluara la cláusula WHERE antes de evaluar la cláusula SELECT. (Consulte mi respuesta con referencias en algún lugar). –

+1

@Catcall - Esto se ha planteado anteriormente en el sitio de Microsoft Connect. Consulte https://connect.microsoft.com/SQLServer/feedback/details/537419/sql-server-should-not-raise-illogical-errors –

+0

Creo que preferiría haber dicho "tiene rienda suelta para reordenar las cosas sin embargo" le gusta, siempre y cuando produzca el mismo resultado que una evaluación no optimizada, fuerza bruta, paso a paso, con lápiz y papel de la misma consulta ". –

1

Joe Celko, quien ayudó a escribir los primeros estándares de SQL, ha publicado algo similar varias veces en varios grupos de noticias de USENET. (Me estoy salteando las cláusulas que no se aplican a su declaración SELECT). Por lo general, dijo algo así como "Así se supone que las declaraciones actúan como funcionan". En otras palabras, las implementaciones de SQL deberían comportarse exactamente como si hicieran estos pasos, sin que en realidad se les requiera hacer cada uno de estos pasos.

  1. Construir una mesa de trabajo de todos los constructores tabla en la cláusula .
  2. Elimine de la tabla de trabajo las filas que no satisfacen la cláusula WHERE .
  3. Construya las expresiones en la cláusula SELECT contra la tabla de trabajo.

Por lo tanto, a continuación, no SQL dbms debería actuar como si evaluara funciones en la cláusula SELECT antes de que actúe como si aplicara la cláusula WHERE.

En una publicación reciente, Joe expands the steps to include CTEs.

CJ Date y Hugh Darwen dicen esencialmente lo mismo en el capítulo 11 ("Expresiones de tabla") de su libro Una guía para el estándar SQL. También observan que este capítulo corresponde a la sección "Especificación de consulta" (¿secciones?) En los estándares SQL.

+0

¿Las uniones se consideran parte de la cláusula where o una fase separada? –

+0

En las cosas que leí, las cláusulas JOIN fueron consideradas como uno de los muchos "constructores de tablas en la cláusula FROM". –

Cuestiones relacionadas