Campo Booleano no Oracle

145

Ontem, eu queria adicionar um campo booleano a uma tabela Oracle. No entanto, não há realmente um tipo de dados booleano no Oracle. Alguém aqui sabe a melhor maneira de simular um booleano? Pesquisando no assunto, descobrimos várias abordagens

  1. Use um número inteiro e não se preocupe em atribuir nada além de 0 ou 1 a ele.

  2. Use um campo char com 'Y' ou 'N' como os únicos dois valores.

  3. Use uma enumeração com a restrição CHECK.

Os desenvolvedores Oracle experientes sabem qual abordagem é preferida / canônica?

Eli Courtwright
fonte
195
Eu gostaria que o Oracle tivesse um walltipo de dados para poder esmagar minha cabeça ao usar booleanos.
Greg

Respostas:

82

Achei este link útil.

Aqui está o parágrafo destacando alguns dos prós / contras de cada abordagem.

O design mais comum é imitar os muitos sinalizadores booleanos que as visualizações do dicionário de dados da Oracle usam, selecionando 'Y' para verdadeiro e 'N' para falso. No entanto, para interagir corretamente com ambientes host, como JDBC, OCCI e outros ambientes de programação, é melhor selecionar 0 para false e 1 para true para que ele funcione corretamente com as funções getBoolean e setBoolean.

Basicamente, eles defendem o método número 2, por uma questão de eficiência, usando

  • valores de 0/1 (devido à interoperabilidade com JDBC, getBoolean()etc.) com uma restrição de verificação
  • um tipo de CHAR (porque usa menos espaço que NUMBER).

O exemplo deles:

create table tbool (bool char check (bool in (0,1));
insert into tbool values(0);
insert into tbool values(1);`
ColinYounger
fonte
31
Aconselho não usar 'N' e 'Y', pois depende do idioma. Os anglófonos às vezes esquecem que a maior parte do mundo não representa o conceito de verdade com a letra Y. Por outro lado, o significado de 0 e 1 é constante através das barreiras linguísticas.
Andrew Spencer
7
0 e 1 como valores booleanos não são consistentes na ciência da computação - as linguagens do tipo shell script tendem a ter 0 como sucesso e diferente de zero como falha, enquanto as linguagens do tipo C tendem a ter 0 como falha e diferente de zero como sucesso.
Phil
41
Como valores booleanos , eles não são ambíguos. Os códigos de retorno do processo não são valores booleanos.
Andrew Spencer
13
Por que esse parágrafo inteiro do link fornecido foi ignorado nesta resposta? "O design mais comum é imitar os muitos sinalizadores booleanos que as visualizações do dicionário de dados da Oracle usam, selecionando 'Y' para verdadeiro e 'N' para falso. No entanto, para interagir corretamente com ambientes de host, como JDBC, OCCI, e outros ambientes de programação, é melhor selecionar 0 para false e 1 para true para que ele funcione corretamente com as funções getBoolean e setBoolean. " Eles afirmam que, embora 'S / N' seja comum, é recomendável usar '0/1' para aumentar a compatibilidade com ambientes host.
Justin.hughey
28

O próprio Oracle usa Y / N para valores booleanos. Para completar, deve-se notar que o pl / sql tem um tipo booleano, são apenas as tabelas que não.

Se você estiver usando o campo para indicar se o registro precisa ser processado ou não, considere usar Y e NULL como valores. Isso cria um índice muito pequeno (leia rapidamente) que ocupa muito pouco espaço.

Leigh Riffel
fonte
7
+1 Bom argumento sobre as visualizações e tabelas internas do Oracle usando Y / N. Se a Oracle fizer dessa maneira, deve estar certo! :)
Jeffrey Kemp
Você pode explicar como Y e NULL fazem um pequeno índice em comparação com Y e N?
styfle
6
NULLs não são indexados no Oracle, portanto, se seu índice contiver alguns caracteres Y, mas principalmente NULLs, você terá um índice muito pequeno.
Leigh Riffel
25

Para usar a menor quantidade de espaço, você deve usar um campo CHAR restrito a 'Y' ou 'N'. O Oracle não suporta os tipos de dados BOOLEAN, BIT ou TINYINT, portanto, um byte de CHAR é o menor possível.

Bill the Lizard
fonte
19

A melhor opção é 0 e 1 (como números - outra resposta sugere 0 e 1 como CHAR para eficiência de espaço, mas isso é um pouco distorcido para mim), usando NOT NULL e uma restrição de verificação para limitar o conteúdo a esses valores. (Se você precisa que a coluna seja anulável, não é um booleano com o qual você está lidando, mas uma enumeração com três valores ...)

Vantagens de 0/1:

  • Linguagem independente. 'Y' e 'N' ficariam bem se todos usassem. Mas eles não. Na França, eles usam 'O' e 'N' (eu já vi isso com meus próprios olhos). Não programei na Finlândia para ver se eles usam 'E' e 'K' lá - sem dúvida, são mais espertos do que isso, mas você não pode ter certeza.
  • Congruente com a prática em linguagens de programação amplamente usadas (C, C ++, Perl, Javascript)
  • Joga melhor com a camada de aplicação, por exemplo, Hibernate
  • Leva a SQL mais sucinto, por exemplo, para descobrir quantas bananas estão prontas para comer em select sum(is_ripe) from bananasvez de select count(*) from bananas where is_ripe = 'Y'ou mesmo (yuk)select sum(case is_ripe when 'Y' then 1 else 0) from bananas

Vantagens de 'Y' / 'N':

  • Ocupa menos espaço que 0/1
  • É o que a Oracle sugere, então pode ser o que algumas pessoas estão mais acostumadas

Outro pôster sugeria 'Y' / nulo para ganhos de desempenho. Se você provou que precisa do desempenho, é justo o suficiente, mas evite, pois isso torna a consulta menos natural (em some_column is nullvez de some_column = 0) e em uma junção esquerda, você confundirá a falsidade com registros inexistentes.

Andrew Spencer
fonte
3
Você acha que hoje em dia muitos booleanos são TriState, isto é, verdadeiro, falso e desconhecido. o que se encaixa perfeitamente com a idéia nula do banco de dados. simplesmente porque um monte de vezes, sabendo nenhuma resposta foi dada é de vital importância
miket
1
Sim, verdadeiro-falso-desconhecido pode ser necessário, embora se eu fosse exigente (o que sou), diria que não deveria ser descrito como um booleano, porque não é.
Andrew Spencer
2
se você for tão exigente, poderá argumentar o mesmo para todos os tipos de dados. como em definição estrita número inteiro, duplo (acho que devo dizer que o comprimento duplo aumenta o ponto flutuante), binário, string etc. todos assumem que um valor é fornecido, mas as implementações de banco de dados sempre adicionam uma opção de valor nulo Boolean não é diferente
MikeT
1
true, em uma observação positiva para o seu método, se você configurar seu número corretamente, ele também poderá ser armazenado no mesmo byte de um campo char, que anula o argumento de tamanho contra o uso de 0/1, não consigo encontrar o link atualmente, mas armazenamento de um número varia de 1 - 22 bytes, dependendo da configuração
miket
4
Suspeito que os votos negativos se devam a um ponto de vista herdado na escolha da implementação com mais eficiência de memória. Essa eficiência de memória dos dias de hoje é muito menos prioritária e deve ser levada em consideração após a usabilidade e a compatibilidade. Para qualquer pessoa que possa responder a esse comentário, recomendo ler sobre otimização prematura. É exatamente isso que ocorre ao escolher 'S / N' puramente com base na eficiência da memória. Você está perdendo a compatibilidade nativa com um conjunto de estruturas comumente usadas por causa dessa decisão.
Justin.hughey
5

1/0 ou Y / N com uma restrição de verificação. éter é bom. Pessoalmente, prefiro 1/0, pois faço muito trabalho em perl, e isso facilita muito a operação booleana de perl nos campos do banco de dados.

Se você quiser uma discussão realmente aprofundada dessa questão com um dos honchos do Oracles, confira o que Tom Kyte tem a dizer sobre isso. Aqui

Matthew Watson
fonte
1/0 é dito ser "menos eficiente de memória", mas ... eu gosto mais também (e hibernar aparentemente requer 1/0 para um booleano)
rogerdpack
1/0 é o padrão do Hibernate para um booleano, mas você pode definir qualquer mapeamento personalizado que desejar.
Andrew Spencer
@rogerdpack eis porque um campo char é um byte, ou 2 bytes para nchar, enquanto que, dependendo como é definido um número pode ser de 1 a 22 bytes
miket
4

O banco de dados em que fiz a maior parte do meu trabalho usou 'Y' / 'N' como booleanos. Com essa implementação, você pode executar alguns truques como:

  1. Contar linhas verdadeiras:
    SELECT SUM (CASE WHEN BOOLEAN_FLAG = 'Y' THEN 1 ELSE 0 0) FROM X

  2. Ao agrupar linhas, aplique a lógica "Se uma linha for verdadeira, todas serão verdadeiras":
    SELECT MAX (BOOLEAN_FLAG) FROM Y
    Por outro lado, use MIN para forçar o agrupamento false se uma linha for falsa.

Erick B
fonte
4
de fato, os exemplos mostrados também são úteis para a abordagem 0/1 - e, IMHO, mais rápido.
igorsantos07
2

Um exemplo de trabalho para implementar a resposta aceita adicionando uma coluna "Boolean" a uma tabela existente em um banco de dados oracle (usando o numbertipo):

ALTER TABLE my_table_name ADD (
my_new_boolean_column number(1) DEFAULT 0 NOT NULL
CONSTRAINT my_new_boolean_column CHECK (my_new_boolean_column in (1,0))
);

Isso cria uma nova coluna my_table_namechamada my_new_boolean_columncom valores padrão de 0. A coluna não aceita NULLvalores e restringe os valores aceitos a0 ou 1.

Ben.12
fonte
1

Em nossos bancos de dados, usamos uma enumeração que garante que passamos TRUE ou FALSE. Se você fizer uma das duas primeiras maneiras, é muito fácil começar a adicionar novo significado ao número inteiro sem passar por um design adequado ou terminar com esse campo char com Y, y, N, n, T, t, Valores F, f e ter que lembrar qual seção do código usa qual tabela e qual versão de true está usando.

Ryan Ahearn
fonte