¿Por qué el SQL ENTRE es inclusivo en lugar de estar medio abierto?

45

Los intervalos semiabiertos (o medio abiertos, medio cerrados , medio acotados ) ( [a,b)donde xpertenece al intervalo iff a <= x < b) son bastante comunes en la programación, ya que tienen muchas propiedades convenientes.

¿Alguien puede ofrecer una justificación que explique por qué SQL BETWEENutiliza un intervalo cerrado ( [a,b])? Esto es especialmente inconveniente para las fechas. ¿Por qué te BETWEENhabrías comportado así?

alex
fuente
Tengo curiosidad, ¿qué propiedades convenientes tienen?
phant0m
2
si no fuera inclusivo, ¿cómo podría consultar fácilmente todos los apellidos en el rango de A a D? o nombres W a Z? Para los números entre 1 y 10 puede buscar 0 <n <11, pero para los caracteres tendría que usar números ASCII. o números unicode? Además, los índices pueden llevarlo fácilmente al inicio de sus datos.
jqa
2
Entiendo que tu frustración, (StartDate> = '2010-01-01' y StartDate <'2011-01-01') funciona de maravilla, usar Entre el equivalente sería (StartDate entre '2010-01-01' y ' 2010-12-31 23:59:59 '), ambos voluminosos y uno necesita saber cuántos días hay en diciembre.
Todd
1
@ phant0m [a, b) U [c, d) == [a, d). [a: int, b: int) contiene exactamente elementos ba. El comentario de Todd muestra cómo funcionan especialmente bien para las fechas (que es donde más los extraño). Básicamente, cuando se codifica, los intervalos semiabiertos tienden a ser más simples, fáciles de usar y robustos.
alex
La mejor respuesta debería haber hecho referencia a la documentación de decisión objetiva de las personas que primero especificaron BETWEEN for SQL, respondiendo así por qué, en lugar de la respuesta subjetiva seleccionada.
Todd

Respuestas:

48

Creo que inclusivo BETWEENes más intuitivo (y aparentemente, también lo hicieron los diseñadores de SQL) que un intervalo semiabierto. Por ejemplo, si digo "Elija un número entre 1 y 10", la mayoría de las personas incluirán los números 1 y 10. El intervalo abierto es particularmente confuso para los no desarrolladores porque es asimétrico. Los no programadores utilizan ocasionalmente SQL para realizar consultas simples, y la semántica semiabierta habría sido mucho más confusa para ellos.

Oleksi
fuente
99
Su ejemplo se centra en números enteros, para números decimales y otras cantidades delimitadas (como fechas), el término entre es ambiguo. Si digo que has hecho X entre 2012 y 2013, no incluyo 2013 (o específicamente el día 2013-01-01)
Todd
44
@Todd Cualquier uso de estos términos es ambiguo. Es por eso que los matemáticos, científicos y programadores expertos documentan su intención como "medio abierta" o algo así. Creo que el punto de la respuesta de Oleski es que SQL originalmente estaba destinado a usuarios finales en lugar de programadores (¡en serio!). Aparentemente, los diseñadores de SQL apuñalaron una definición que creyeron mejor para esa audiencia. Pero, como sugieren los autores de la pregunta, casi abierta es casi siempre mejor para trabajar con rangos como períodos de tiempo.
Basil Bourque
"Creo que inclusivo ENTRE es más intuitivo" es subjetivo. "Los no programadores utilizan ocasionalmente SQL para realizar consultas simples": los no programadores también tendrían que verificar las especificaciones.
Todd
La pregunta también se hace a menudo "Elija un número del 1 al 10" (simplemente para evitar la ambigüedad obvia). Como nota al margen. Dices "elige un número entre 1 y 10"; la mayoría de la gente probablemente no elegiría 1 o 10. De acuerdo, es más un problema de psicología. :) Las personas aún aceptarían 1 y 10 como opciones válidas (a pesar de ser semánticamente incorrectas); pero eso es resultado de la interpretación contextual asumiendo que 1 y 10 son válidos. Si tuviera que decir: "entre 13 y 24" y es más probable que se le pregunte si se incluyen 13 y 24.
Desilusionado
26

PREGUNTA: ¿Por qué el SQL ENTRE es inclusivo?

RESPUESTA: Debido a que los diseñadores del lenguaje SQL tomaron una mala decisión de diseño, en el sentido de que no pudieron entregar una sintaxis que permitiera a los desarrolladores especificar cuál de las 4 variantes de ENTRE (cerrado, semiabierto a la izquierda, semiabierto a la derecha o abierto ) preferirían

RECOMENDACIÓN: A menos que / hasta que se modifique el estándar SQL, no use ENTRE las fechas / horas. En su lugar, adopte el hábito de codificar las comparaciones de rango DATE como condiciones independientes en los límites inicial y final de su rango ENTRE. Esto es un poco detallado, pero lo dejará escribiendo condiciones que son intuitivas (por lo tanto, menos propensas a tener errores) y claras para los optimizadores de la base de datos, lo que permite determinar planes de ejecución óptimos e índices que se utilizarán.

Por ejemplo, si su consulta acepta una especificación del día de entrada y debe devolver todos los registros que cayeron en esa fecha, codificaría como:

  • WHERE DATE_FIELD >= :dt AND DATE_FIELD < :dt+1

Tratar de escribir la lógica usando ENTRE arriesga problemas de rendimiento y / o código defectuoso. Tres pasos en falso comunes:

1) WHERE DATE_FIELD BETWEEN :dt AND :dt+1

Esto es casi seguro que es un error: el usuario espera ver solo los registros de una fecha en particular, sin embargo, un día terminará con un informe que contiene registros de las 12:00 a.m. del día siguiente.

2) WHERE TRUNC(DATE_FIELD) = :dt

Da la respuesta correcta, pero la aplicación de la función a DATE_FIELD hará que la mayoría de las indexaciones / estadísticas sean inútiles (aunque a veces los DBA intentarán ayudar agregando índices basados ​​en funciones a los campos de fecha, lo que aún consumirá horas hombre y espacio en disco y agregará gastos generales al DIU operaciones en la mesa)

3) WHERE EVENT_DATE BETWEEN :dt AND :dt + 1-1/24/60/60

Tom Kyte, extraordinario gurú de Oracle, recomienda esta solución poco elegante (IMO). Funciona muy bien hasta que pasa todo el día para encontrar ese "1-1 / 24/06/60" en una consulta que da resultados incompletos ... o hasta que lo use accidentalmente en un campo TIMESTAMP. Además, es un poco patentado; compatible con el tipo de datos DATE de Oracle (que sigue al segundo), pero debe ajustarse a la precisión DATE / TIME de diferentes productos de bases de datos.

SOLUCIÓN: Solicite al comité ANSI SQL que mejore las especificaciones del lenguaje SQL modificando la sintaxis ENTRE para admitir la especificación de alternativas al valor predeterminado CERRADO / INCLUSIVO. Algo así haría el truco:

expr1 ENTRE expr2 [ INCL [USIVE] | EXCL [USIVE]] y expr3 [ INCL [USIVE] | EXCLUSIVO] ]

Considere cuán fácil se vuelve expresar WHERE DATE_FIELD BETWEEN :dt INCLUSIVE AND :dt+1 EXCLUSIVE(o simplemente WHERE DATE_FIELD BETWEEN :dt AND :dt+1 EXCL)

Tal vez ANSI SQL: 2015?

KevinKirkpatrick
fuente
Esta respuesta es un sabio consejo.
Basil Bourque
@KevinKirkPatrick - ¡Gran respuesta! Le sugiero que también trate de encontrar la documentación de decisión como evidencia objetiva del Por qué original.
Todd
3
Personalmente, me gusta exp1 BETWEEN exp2 AND exp3 AND exp1 != exp3la forma en que puedes mantener el operador intermedio para que sepas que es un predicado a distancia, y el predicado de desigualdad asegura que esté semi abierto.
Sentinel
@Sentinel, bien! No voy a declararme un converso prematuramente, pero definitivamente tendré en cuenta esta variante para la próxima vez que codifique condiciones de rango de fechas. A primera vista, tiene un mayor atractivo lingüístico que exp1> = exp2 Y exp1 <exp3; y obviamente resuelve problemas con ENTRE igualmente bien. Me interesaría si algún optimizador muestra una mayor "comprensión" de una variación sobre la otra; Ciertamente, parece plausible que el tuyo también produzca mejores resultados en ese sentido (aunque, francamente, estaría bastante decepcionado con el optimizador que los trató de manera diferente)
KevinKirkpatrick
@KevinKirkpatrick Nunca los he perfilado para determinar si existen diferencias, y yo también estaría decepcionado si las hubiera.
Sentinel
8

Tanto inclusivo ( a <= x <= b) como exclusivo ( a < x < b) son casi igualmente comunes, por lo que al hacer los estándares simplemente tenían que elegir uno. "Entre" en inglés común es típicamente inclusivo, y una declaración SQL está destinada a leerse de manera similar a una oración en inglés, por lo que inclusivo fue una elección sensata.

Matt S
fuente
44
En realidad, el uso en inglés es aún más variado, ya que dejó de lado medio abierto. Cuando decimos "el almuerzo es entre el mediodía y la 1:00 p.m." nos referimos a medio abierto en el sentido de que se espera que regrese a clase / trabajo a las 13: 00: 00,000, con el descanso hasta el primer momento, pero sin incluirlo la hora en punto. a <= x < bestá medio abierto.
Basil Bourque
1
@BasilBourque: Esto puede deberse a una precisión infinita, por ejemplo, el almuerzo es entre mediodía y 12: 59: 99.9999999999999 ....
Brendan
@Brendan Sí, estás haciendo mi punto. La precisión infinita (o ambigua) es uno de los problemas que se maneja utilizando el enfoque medio abierto para definir un lapso de tiempo. El punto aquí es que en la conversación en inglés manejamos intuitivamente los rangos abiertos y cerrados (como se menciona en esta respuesta), así como los rangos medio abiertos sin pensarlo mucho. Cada enfoque tiene un propósito. Es por eso que la definición SQL de ENTRE es menos que óptima. Idealmente, SQL seguiría la sugerencia de KevinKirkpatrick .
Basil Bourque
2
Se supone que SQL es similar al inglés, y aunque inclusivo y exclusivo puede ser igualmente común, es un lenguaje de consulta para analistas y programadores. Como programador, creo que está mal definido, pero eso no importa, solo evito usar "ENTRE" de todos modos. No es un gran trato.
Todd
5

El operador no se llama ∩[a,b), se llama BETWEEN, por lo que es mucho más apropiado que su semántica sea la de la frase inglesa "está entre" que la del predicado matemático "está en intervalo semiabierto".

AakashM
fuente
Hay que tener en cuenta todas las aplicaciones, no solo las aplicaciones en inglés para conjuntos de enteros. "entre 1 y 10", "entre mediodía y 1 p.m.", "entre 1.0 y 5.0" (gramos). "entre 5,50 y 10,30" (dólares). Las cantidades continuas se supondrían lógicamente (en inglés) como exclusivas.
Todd
1
El problema es que el BETWEENoperador no utiliza la semántica de la frase inglesa "is between". En inglés "entre" es el tiempo, el espacio o el intervalo que separa las cosas (es decir, es exclusivo ). Si intentas patear un gol, la pelota debe ir entre los postes para anotar. Si golpeas la publicación que no pasa entre ellos, no hay puntaje para ti.
Desilusionado
1
@CraigYoung como sugiere la respuesta aceptada (y estoy de acuerdo), "si digo" Elija un número entre 1 y 10 ", la mayoría de las personas incluirán los números 1 y 10 [en su rango de posibles respuestas]". En un dominio espacial , estoy de acuerdo con usted, pero para los números, diría que es diferente. ¡Sin embargo, es mejor para el idioma inglés y el uso que aquí!
AakashM
@AakashM Lo que quiero decir es que has hecho un reclamo sobre el idioma inglés que es simplemente falso por definición de diccionario de la palabra "entre", para justificar la semántica de programación. El hecho de que haya una comprensión común de la frase "entre 1 y 10" tiene menos que ver con el significado de "entre" y más que ver con las posiciones 1 y 10 en el sistema de números decimales. La "autocorrección" del cerebro humano ignora que "entre" excluye los puntos finales en este caso porque parece ridículo significar "de 2 a 9". Pruebe lo mismo con "entre 13 y 24". O incluso "entre 0 y 11".
Desilusionado
Entre usted y yo, las afirmaciones categóricas sobre los lenguajes naturales generalmente no son seguras.
AakashM