Por que o SQL BETWEEN é inclusivo e não meio aberto?


45

Intervalos semi-abertos (ou semi-abertos, semi-fechados , meio-limitados ) ( [a,b), onde xpertencem ao intervalo iff a <= x < b) são bastante comuns na programação, pois possuem muitas propriedades convenientes.

Alguém pode oferecer uma justificativa que explica por que o SQL BETWEENusa um intervalo fechado ( [a,b])? Isso é esp. inconveniente para datas. Por que você se BETWEENcomportaria assim?


Estou curioso, que propriedades convenientes eles têm?
Phant0m

2
se não fosse inclusivo, como você poderia consultar facilmente todos os sobrenomes no intervalo de A a D? ou nomes W a Z? Para números entre 1 e 10, você pode procurar 0 <n <11, mas para caracteres você precisaria usar números ASCII? ou números unicode? Além disso, os índices podem levá-lo facilmente ao início dos seus dados.
JQA

2
Entendo sua frustração, (StartDate> = '2010-01-01' e StartDate <'2011-01-01'), funciona lindamente, para usar Entre o equivalente seria (StartDate entre '2010-01-01' e ' 2010-12-31 23:59:59 '), tanto o volumoso quanto o necessário para saber quantos dias existem em dezembro.
Todd

1
@ phant0m [a, b) U [c, d) == [a, d). [a: int, b: int) contém exatamente ba elementos. O comentário de Todd mostra como eles funcionam especialmente bem em datas (que são as que mais sinto falta deles). Basicamente, ao codificar, os intervalos semi-abertos tendem a ser mais simples, fáceis de usar e robustos.
21713 alex

A melhor resposta deve ter feito referência à documentação de decisão objetiva das pessoas que primeiro especificaram BETWEEN for SQL, respondendo dessa forma a Por que, em vez da resposta subjetiva selecionada.
Todd

Respostas:


48

Eu acho que inclusivo BETWEENé mais intuitivo (e aparentemente os designers de SQL também) do que um intervalo semiaberto. Por exemplo, se eu disser "Escolha um número entre 1 e 10", a maioria das pessoas incluirá os números 1 e 10. O intervalo aberto é realmente particularmente confuso para os não desenvolvedores, porque é assimétrico. Ocasionalmente, o SQL é usado por não programadores para fazer consultas simples, e a semântica semi-aberta teria sido muito mais confusa para eles.


9
Seu exemplo se concentra em números inteiros, para números decimais e outras quantidades delimitadas (como datas), o termo entre é ambíguo. Se eu disser que você fez o X entre 2012 e 2013, não incluo 2013 (ou especificamente o dia 01-01-2013)
Todd

4
@ Todd Qualquer uso destes termos é ambíguo. É por isso que matemáticos, cientistas e programadores experientes documentam sua intenção como "semi-aberta" ou algo assim. Eu acho que o ponto da resposta de Oleski é que o SQL foi originalmente destinado a usuários finais e não a programadores (realmente!). Aparentemente, os designers de SQL avaliaram a definição que acharam melhor para esse público. Mas, como sugerem os autores da pergunta, a abertura pela metade é quase sempre melhor para trabalhar com intervalos como períodos de tempo.
Basil Bourque

"Eu acho que inclusivo ENTRE é mais intuitivo" é subjetivo. "Ocasionalmente, o SQL é usado por não programadores para fazer consultas simples" - Os não programadores precisariam igualmente verificar as especificações.
Todd


A pergunta também é feita com frequência "Escolha um número de 1 a 10" (simplesmente para evitar a óbvia ambiguidade). Como uma nota rodapé. Você diz "escolha um número entre 1 e 10"; a maioria das pessoas provavelmente não escolheria 1 ou 10. É verdade que isso é mais um problema de psicologia. :) As pessoas ainda aceitariam 1 e 10 como escolhas válidas (apesar de serem semanticamente incorretas); mas isso é resultado da interpretação contextual assumindo que 1 e 10 são válidos. Se você dissesse: "entre 13 e 24" e é mais provável que lhe perguntem se 13 e 24 estão incluídos.
Desiludido

26

PERGUNTA: Por que o SQL BETWEEN é inclusivo?

RESPOSTA: Como os projetistas da linguagem SQL tomaram uma péssima decisão de design, falharam em fornecer sintaxe que permitiria aos desenvolvedores especificar qual das 4 variantes de BETWEEN (fechada, semi-aberta-esquerda, semi-aberta-direita ou aberta). ) eles preferem.

RECOMENDAÇÃO: A menos que / até que o padrão SQL seja alterado, não use BETWEEN para datas / horas. Em vez disso, adquira o hábito de codificar comparações de intervalo DATE como condições independentes nos limites de início e fim do seu intervalo BETWEEN. Isso é um pouco detalhado, mas deixa você escrevendo condições que são intuitivas (com menor probabilidade de serem com erros) e claras para os otimizadores de banco de dados, permitindo que planos de execução ideais sejam determinados e índices sejam usados.

Por exemplo, se sua consulta está aceitando uma especificação do dia de entrada e deve retornar todos os registros que caíram nessa data, você codificaria como:

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

Tentar escrever a lógica usando BETWEEN arrisca problemas de desempenho e / ou código de buggy. Três erros comuns:

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

Isso é quase certamente um bug - o usuário espera ver apenas registros para uma data específica, mas um dia será encerrado com um relatório contendo registros a partir das 12:00 do dia seguinte.

2) WHERE TRUNC(DATE_FIELD) = :dt

Dá a resposta certa, mas a aplicação da função para DATE_FIELD tornará inútil a maioria das estatísticas / indexação (embora algumas vezes os DBAs tentem ajudar adicionando índices baseados em funções aos campos de data - ainda gastando horas-homem e espaço em disco e adicionando sobrecarga ao DIU operações sobre a mesa)

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

Tom Kyte, extraordinário guru da Oracle, recomenda esta solução menos que elegante (IMO). Funciona muito bem até que você gaste o dia todo para descobrir que "1-1 / 24/06/60" em uma consulta que fornece resultados incompletos ... ou até que você o use acidentalmente em um campo TIMESTAMP. Além disso, é um pouco proprietário; compatível com o tipo de dados DATE do Oracle (que acompanha o segundo), mas precisa ser ajustado com a precisão DATE / TIME de diferentes produtos de banco de dados.

SOLUÇÃO: Solicite ao comitê ANSI SQL que aprimore as especificações da linguagem SQL modificando a sintaxe BETWEEN para oferecer suporte à especificação de alternativas ao padrão CLOSED / INCLUSIVE. Algo assim faria o truque:

expr1 ENTRE expr2 [ INCL [USIVE] | EXCL [USIVE]] E expr3 [ INCL [USIVE] | EXCL [USIVE]]

Considere o quão fácil se torna para expressar WHERE DATE_FIELD BETWEEN :dt INCLUSIVE AND :dt+1 EXCLUSIVE(ou apenas WHERE DATE_FIELD BETWEEN :dt AND :dt+1 EXCL)

Talvez ANSI SQL: 2015?


Esta resposta é um sábio conselho.
Basil Bourque

@KevinKirkPatrick - Ótima resposta! Sugiro que você também tente encontrar a documentação da decisão como evidência objetiva do Por que original.
Todd

3
Pessoalmente, gosto exp1 BETWEEN exp2 AND exp3 AND exp1 != exp3dessa maneira de manter o operador entre para que você saiba que é um predicado à distância, e o predicado da desigualdade garante que ele seja semi-aberto.
Sentinel

@ Sentinel, Nice! Não vou me declarar um convertido prematuramente, mas definitivamente lembrarei dessa variante para quando codificar as condições do período. À primeira vista, ele tem um apelo linguístico maior do que exp1> = exp2 AND exp1 <exp3; e obviamente resolve problemas com BETWEEN igualmente bem. Eu ficaria interessado se algum otimizador mostrar maior "entendimento" de uma variação sobre a outra; Certamente, parece plausível que o seu pode produzir melhores resultados a esse respeito, bem como (embora, francamente, eu ficaria muito decepcionado com o otimizador que os tratou de maneira diferente)
KevinKirkpatrick

@KevinKirkpatrick Eu nunca os perfilei para verificar se existem diferenças, e eu também ficaria decepcionado se houvesse.
Sentinel

8

Tanto inclusivo ( a <= x <= b) quanto exclusivo ( a < x < b) são igualmente comuns, portanto, ao criar os padrões, eles simplesmente tiveram que escolher um. "Entre" no inglês comum é geralmente inclusivo, e uma instrução SQL deve ser semelhante a uma frase em inglês, portanto, inclusivo foi uma escolha sensata.


4
Na verdade, o uso em inglês é ainda mais misto quando você deixa de fora o meio aberto. Quando dizemos "o almoço é entre meio-dia e 13:00", entendemos meio aberto, pois você deve voltar às aulas / trabalho às 13: 00: 00.000, com o intervalo subindo, mas sem incluir o primeiro momento da aula. a hora de uma hora. a <= x < bé meio aberto.
Basil Bourque

1
@BasilBourque: Isto pode ser devido a precisão infinita - por exemplo, o almoço é entre meio-dia e 12: 59: 99,9999999999999 ....
Brendan

@Brendan Sim, você está fazendo o meu ponto. A precisão infinita (ou ambígua) é um dos problemas resolvidos usando a abordagem semi-aberta para definir um período de tempo. O ponto aqui é que, nas conversas em inglês, lidamos intuitivamente com aberto e fechado (como mencionado nesta resposta), bem como intervalos semiabertos sem muita reflexão. Cada abordagem serve a um propósito. É por isso que a definição SQL de BETWEEN é abaixo do ideal. Idealmente, o SQL seguiria a sugestão de KevinKirkpatrick .
Basil Bourque

2
Supõe-se que o SQL seja semelhante ao inglês e, embora inclusivo e exclusivo possam ser igualmente comuns, é uma linguagem de consulta para analistas e programadores. Como programador, acho que está definido errado, mas isso realmente não importa, apenas evito usar "ENTRE" de qualquer maneira. Não é grande coisa.
Todd

5

O operador não é chamado ∩[a,b), é chamado BETWEEN, por isso é consideravelmente mais apropriado que sua semântica seja a da frase em inglês "está entre" do que a do predicado matemático "está em intervalo semiaberto".


É preciso considerar todos os aplicativos, não apenas os aplicativos em inglês para conjuntos de números inteiros. "entre 1 e 10", "entre meio-dia e 13h", "entre 1,0 e 5,0" (gramas). "entre 5,50 e 10,30" (dólares). Quantidades contínuas seriam logicamente (em inglês) assumidas como exclusivas.
Todd

1
O problema é que o BETWEENoperador não usa a semântica da frase em inglês "is between". Em inglês, "entre" é o tempo, espaço ou intervalo que separa as coisas (ou seja, é exclusivo ). Se você tentar chutar um gol, a bola terá que ir entre os postes para marcar. Se você acertar o post sem passar entre eles - nenhuma pontuação para você.
Desiludido

1
@CraigYoung, como sugere a resposta aceita (e eu concordo), "se eu disser" Escolha um número entre 1 e 10 ", a maioria das pessoas incluirá os números 1 e 10 [no intervalo de respostas possíveis]". Em um domínio espacial, eu concordo com você, mas para números eu diria que é diferente. Melhor para o idioma e uso do inglês do que aqui!
AakashM

@AakashM Meu argumento é que você fez uma afirmação sobre o idioma inglês, que é simplesmente falsa pela definição de dicionário da palavra "entre", para justificar a semântica de programação. O fato de haver um entendimento comum da frase "entre 1 e 10" tem menos a ver com o significado de "entre" e mais a ver com as posições 1 e 10 no sistema de números decimais. A "correção automática" do cérebro humano ignora que "entre" exclui pontos finais neste caso porque parece ridículo significar "de 2 a 9". Tente o mesmo com "entre 13 e 24". Ou até "entre 0 e 11".
Desiludido

Entre você e eu, afirmações categóricas sobre linguagens naturais são geralmente inseguras.
AakashM
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.