Campo booleano en Oracle

145

Ayer quería agregar un campo booleano a una tabla Oracle. Sin embargo, en realidad no hay un tipo de datos booleanos en Oracle. ¿Alguien aquí sabe la mejor manera de simular un booleano? Googleando el tema descubrió varios enfoques

  1. Use un número entero y no se moleste en asignarle nada más que 0 o 1.

  2. Use un campo de caracteres con 'Y' o 'N' como los únicos dos valores.

  3. Use una enumeración con la restricción CHECK.

¿Los desarrolladores experimentados de Oracle saben qué enfoque es el preferido / canónico?

Eli Courtwright
fuente
195
Desearía que Oracle tuviera un walltipo de datos para poder golpearme la cabeza cuando usara booleanos.
Greg

Respuestas:

82

Encontré este enlace útil.

Aquí está el párrafo que destaca algunos de los pros / contras de cada enfoque.

El diseño más comúnmente visto es imitar las muchas banderas booleanas que usan las vistas del diccionario de datos de Oracle, seleccionando 'Y' para verdadero y 'N' para falso. Sin embargo, para interactuar correctamente con entornos host, como JDBC, OCCI y otros entornos de programación, es mejor seleccionar 0 para falso y 1 para verdadero para que pueda funcionar correctamente con las funciones getBoolean y setBoolean.

Básicamente abogan por el método número 2, por el bien de la eficiencia, utilizando

  • valores de 0/1 (debido a la interoperabilidad con JDBC, getBoolean()etc.) con una restricción de verificación
  • un tipo de CHAR (porque usa menos espacio que NUMBER).

Su ejemplo:

create table tbool (bool char check (bool in (0,1));
insert into tbool values(0);
insert into tbool values(1);`
ColinYounger
fuente
31
Aconsejo no usar 'N' e 'Y' ya que depende del idioma. Los anglófonos a veces olvidan que la mayor parte del mundo no representa el concepto de verdad con la letra Y. Por el contrario, el significado de 0 y 1 es constante a través de las barreras del idioma.
Andrew Spencer
77
0 y 1 como valores booleanos no son consistentes dentro de la informática: los lenguajes de tipo script de shell tienden a tener 0 como éxito y no cero como error, mientras que los lenguajes de tipo C tienden a tener 0 como error y no cero como éxito.
Phil
41
Como valores booleanos , no son ambiguos. Los códigos de retorno del proceso no son valores booleanos.
Andrew Spencer
13
¿Por qué se ignoró todo este párrafo del enlace proporcionado en esta respuesta? "El diseño más comúnmente visto es imitar las muchas banderas booleanas que utilizan las vistas del diccionario de datos de Oracle, seleccionando 'Y' para verdadero y 'N' para falso. Sin embargo, para interactuar correctamente con entornos host, como JDBC, OCCI, y otros entornos de programación, es mejor seleccionar 0 para falso y 1 para verdadero para que pueda funcionar correctamente con las funciones getBoolean y setBoolean ". Afirman que si bien 'Y / N' es común, se recomienda usar '0/1' para aumentar la compatibilidad con los entornos host.
justin.hughey
28

Oracle mismo usa Y / N para valores booleanos. Para completar, debe tenerse en cuenta que pl / sql tiene un tipo booleano, solo las tablas no lo tienen.

Si está utilizando el campo para indicar si el registro necesita ser procesado o no, puede considerar usar Y y NULL como valores. Esto genera un índice muy pequeño (lectura rápida) que ocupa muy poco espacio.

Leigh Riffel
fuente
77
+1 Buen punto sobre las vistas y tablas internas de Oracle usando S / N. Si Oracle lo hace así, ¡debe ser correcto! :)
Jeffrey Kemp
¿Puedes explicar cómo Y y NULL hacen un índice pequeño en comparación con Y y N?
styfle
66
Los NULL no están indexados en Oracle, por lo que si su índice contiene algunos caracteres Y, pero en su mayoría NULL, tendrá un índice muy pequeño.
Leigh Riffel
25

Para usar la menor cantidad de espacio, debe usar un campo CHAR restringido a 'Y' o 'N'. Oracle no es compatible con los tipos de datos BOOLEAN, BIT o TINYINT, por lo que el byte de CHAR es lo más pequeño posible.

Bill el lagarto
fuente
19

La mejor opción es 0 y 1 (como números; otra respuesta sugiere 0 y 1 como CHAR para la eficiencia espacial, pero eso es demasiado retorcido para mí), usando NOT NULL y una restricción de verificación para limitar el contenido a esos valores. (Si necesita que la columna sea anulable, no se trata de un booleano sino de una enumeración con tres valores ...)

Ventajas de 0/1:

  • Idioma independiente. 'Y' y 'N' estarían bien si todos lo usaran. Pero ellos no. En Francia usan 'O' y 'N' (lo he visto con mis propios ojos). No he programado en Finlandia para ver si usan 'E' y 'K' allí, sin duda son más inteligentes que eso, pero no puedes estar seguro.
  • Congruente con la práctica en lenguajes de programación ampliamente utilizados (C, C ++, Perl, Javascript)
  • Juega mejor con la capa de aplicación, por ejemplo, Hibernate
  • Conduce a un SQL más conciso, por ejemplo, para descubrir cuántos plátanos están listos para comer en select sum(is_ripe) from bananaslugar de select count(*) from bananas where is_ripe = 'Y'o incluso (yuk)select sum(case is_ripe when 'Y' then 1 else 0) from bananas

Ventajas de 'Y' / 'N':

  • Ocupa menos espacio que 0/1
  • Es lo que sugiere Oracle, por lo que podría ser a lo que algunas personas están más acostumbradas

Otro póster sugería 'Y' / nulo para ganancias de rendimiento. Si ha demostrado que necesita el rendimiento, entonces es lo suficientemente justo, pero evítelo ya que hace que las consultas sean menos naturales (en some_column is nulllugar de some_column = 0) y en una unión izquierda combinará la falsedad con registros inexistentes.

Andrew Spencer
fuente
3
Usted encuentra que en estos días muchos booleanos son TriState, es decir, verdadero, falso y desconocido. que encaja perfectamente con la idea nula de la base de datos. simplemente porque muchas veces saber que no se ha dado una respuesta es de vital importancia
MikeT
1
Sí, se puede requerir verdadero-falso-desconocido, aunque si fuera exigente (que soy), diría que no debería describirse realmente como un booleano, porque no lo es.
Andrew Spencer
2
si va a ser tan exigente, puede hacer el mismo argumento para cada tipo de datos. como en la definición estricta de entero, doble (supongo que debería decir que la doble longitud dos complementan el punto flotante), binario, cadena, etc. todos asumen que se proporciona un valor, pero las implementaciones de la base de datos siempre agregan una opción de valor nulo Boolean no es diferente
MikeT
1
Es cierto, en una nota positiva para su método, si configura su número correctamente, también se puede almacenar en el mismo byte único que un campo char, lo que anula el argumento de tamaño contra el uso de 0/1, no puedo encontrar el enlace actualmente, pero el almacenamiento para un número varía de 1 a 22 bytes dependiendo de la configuración
MikeT
44
Sospecho que los votos negativos se deben a un punto de vista heredado para elegir la implementación más eficiente en memoria. Hoy en día, la eficiencia de la memoria es una prioridad mucho menor y debe tenerse en cuenta después de la usabilidad y compatibilidad. A cualquiera que pueda responder a este comentario, le recomiendo leer sobre optimización prematura. Eso es exactamente lo que está ocurriendo al elegir 'S / N' basado únicamente en la eficiencia de la memoria. Está perdiendo la compatibilidad nativa con un conjunto de marcos comúnmente utilizados debido a esa decisión.
justin.hughey
5

Ya sea 1/0 o Y / N con una restricción de verificación. El camino del éter está bien. Personalmente prefiero 1/0 ya que hago mucho trabajo en perl, y hace que sea realmente fácil hacer operaciones booleanas en campos de bases de datos.

Si quieres una discusión realmente profunda de esta pregunta con uno de los principales jefes de Oracles, mira lo que Tom Kyte tiene para decir sobre esto Aquí

Matthew Watson
fuente
Se dice que 1/0 es "menos eficiente en memoria" pero ... también me gusta más (e hibernar aparentemente requiere 1/0 para un booleano)
rogerdpack
1/0 es el valor predeterminado de Hibernate para un booleano, pero puede definir cualquier mapeo personalizado que desee.
Andrew Spencer
@rogerdpack eso se debe a que un campo char es 1 byte o 2 bytes para nchar, donde, según cómo se defina, un Número puede ser de 1 a 22 bytes
MikeT
4

La base de datos en la que hice la mayor parte de mi trabajo utilizaba 'Y' / 'N' como booleanos. Con esa implementación, puedes realizar algunos trucos como:

  1. Cuente las filas que son verdaderas:
    SELECCIONE SUMA (CASO CUANDO BOOLEAN_FLAG = 'Y' ENTONCES 1 OTRO 0) DESDE X

  2. Al agrupar filas,
    imponga la lógica "Si una fila es verdadera, entonces todas son verdaderas": SELECCIONE MAX (BOOLEAN_FLAG) DE Y
    Por el contrario, use MIN para forzar la agrupación falsa si una fila es falsa.

Erick B
fuente
44
de hecho, los ejemplos mostrados también son útiles para el enfoque 0/1, y, en mi humilde opinión, más rápido.
igorsantos07
2

Un ejemplo de trabajo para implementar la respuesta aceptada agregando una columna "booleana" a una tabla existente en una base de datos Oracle (usando el 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))
);

Esto crea una nueva columna en my_table_namellamada my_new_boolean_columncon valores predeterminados de 0. La columna no aceptará NULLvalores y restringirá los valores aceptados a cualquiera 0o 1.

Ben.12
fuente
1

En nuestras bases de datos usamos una enumeración que asegura que la pasemos VERDADERO o FALSO. Si lo hace en cualquiera de las dos primeras formas, es demasiado fácil comenzar a agregar un nuevo significado al entero sin pasar por un diseño adecuado, o terminar con ese campo de caracteres que tiene Y, y, N, n, T, t, F, f valores y tener que recordar qué sección de código usa qué tabla y qué versión de true está usando.

Ryan Ahearn
fuente