Boolesches Feld in Oracle

145

Gestern wollte ich einer Oracle-Tabelle ein boolesches Feld hinzufügen. In Oracle gibt es jedoch keinen booleschen Datentyp. Kennt hier jemand den besten Weg, um einen Booleschen Wert zu simulieren? Das Googeln des Themas entdeckte mehrere Ansätze

  1. Verwenden Sie eine Ganzzahl und weisen Sie ihr nur 0 oder 1 zu.

  2. Verwenden Sie ein Zeichenfeld mit 'Y' oder 'N' als den einzigen beiden Werten.

  3. Verwenden Sie eine Aufzählung mit der Einschränkung CHECK.

Wissen erfahrene Oracle-Entwickler, welcher Ansatz bevorzugt / kanonisch ist?

Eli Courtwright
quelle
195
Ich wünschte, Oracle hätte einen wallDatentyp, damit ich bei der Verwendung von Booleschen Werten meinen Kopf dagegen schlagen könnte.
Greg

Antworten:

82

Ich fand diese Link nützlich.

Hier ist der Absatz, in dem einige der Vor- und Nachteile jedes Ansatzes hervorgehoben werden.

Das am häufigsten verwendete Design besteht darin, die vielen Booleschen Flags zu imitieren, die in den Datenwörterbuchansichten von Oracle verwendet werden, wobei 'Y' für wahr und 'N' für falsch ausgewählt wird. Um jedoch korrekt mit Hostumgebungen wie JDBC, OCCI und anderen Programmierumgebungen zu interagieren, ist es besser, 0 für false und 1 für true auszuwählen, damit die Funktionen getBoolean und setBoolean ordnungsgemäß ausgeführt werden können.

Grundsätzlich befürworten sie aus Effizienzgründen die Methode 2

  • Werte von 0/1 (wegen der Interoperabilität mit JDBCs getBoolean()usw.) mit einer Prüfbedingung
  • eine Art von CHAR (weil es weniger Speicherplatz als NUMBER benötigt).

Ihr Beispiel:

create table tbool (bool char check (bool in (0,1));
insert into tbool values(0);
insert into tbool values(1);`
ColinYounger
quelle
31
Ich rate von der Verwendung von 'N' und 'Y' ab, da dies sprachabhängig ist. Anglophone vergessen manchmal, dass der größte Teil der Welt den Begriff der Wahrheit nicht mit dem Buchstaben Y repräsentiert. Im Gegensatz dazu ist die Bedeutung von 0 und 1 über Sprachbarrieren hinweg konstant.
Andrew Spencer
7
0 und 1 als boolesche Werte sind in der Informatik nicht konsistent - Shell-Skriptsprachen haben in der Regel 0 als Erfolg und Nicht-Null als Fehler, während C-Typ-Sprachen 0 als Fehler und Nicht-Null als Erfolg haben.
Phil
41
Als boolesche Werte sind sie eindeutig. Prozessrückgabecodes sind keine booleschen Werte.
Andrew Spencer
13
Warum wurde dieser gesamte Absatz des angegebenen Links in dieser Antwort ignoriert? "Das am häufigsten verwendete Design besteht darin, die vielen Booleschen Flags zu imitieren, die in den Datenwörterbuchansichten von Oracle verwendet werden, wobei 'Y' für true und 'N' für false ausgewählt wird. Um jedoch korrekt mit Hostumgebungen wie JDBC, OCCI, zu interagieren, In anderen Programmierumgebungen ist es besser, 0 für false und 1 für true auszuwählen, damit es mit den Funktionen getBoolean und setBoolean ordnungsgemäß funktioniert. " Sie geben an, dass, obwohl 'J / N' üblich ist, die Verwendung von '0/1' zur Erhöhung der Kompatibilität mit Host-Umgebungen empfohlen wird.
justin.hughey
28

Oracle selbst verwendet J / N für boolesche Werte. Der Vollständigkeit halber sollte angemerkt werden, dass pl / sql einen booleschen Typ hat, es sind nur Tabellen, die dies nicht tun.

Wenn Sie das Feld verwenden, um anzugeben, ob der Datensatz verarbeitet werden muss oder nicht, können Sie Y und NULL als Werte verwenden. Dies führt zu einem sehr kleinen (schnell lesbaren) Index, der sehr wenig Platz benötigt.

Leigh Riffel
quelle
7
+1 Guter Punkt zu den internen Ansichten und Tabellen von Oracle mit J / N. Wenn Oracle es so macht, muss es richtig sein! :)
Jeffrey Kemp
Können Sie erklären, wie Y und NULL im Vergleich zu Y und N einen kleinen Index bilden?
Styfle
6
NULL-Werte werden in Oracle nicht indiziert. Wenn Ihr Index also einige Y-Zeichen enthält, aber meistens NULL-Werte, haben Sie einen sehr kleinen Index.
Leigh Riffel
25

Um möglichst wenig Speicherplatz zu nutzen, sollten Sie ein CHAR-Feld verwenden, das auf 'Y' oder 'N' beschränkt ist. Oracle unterstützt keine BOOLEAN-, BIT- oder TINYINT-Datentypen, daher ist das Byte von CHAR so klein wie möglich.

Bill die Eidechse
quelle
19

Die beste Option ist 0 und 1 (als Zahlen - eine andere Antwort schlägt 0 und 1 als CHAR vor für die aber das ist mir etwas zu verdreht), wobei NOT NULL und eine Prüfbedingung verwendet werden, um den Inhalt auf diese Werte zu beschränken. (Wenn die Spalte nullwertfähig sein soll, handelt es sich nicht um einen Booleschen Wert, sondern um eine Aufzählung mit drei Werten ...)

Vorteile von 0/1:

  • Sprachunabhängig. 'Y' und 'N' wären in Ordnung, wenn alle es benutzen würden. Aber sie tun es nicht. In Frankreich verwenden sie 'O' und 'N' (ich habe dies mit eigenen Augen gesehen). Ich habe in Finnland nicht programmiert, ob sie dort 'E' und 'K' verwenden - zweifellos sind sie schlauer als das, aber Sie können nicht sicher sein.
  • Übereinstimmend mit der Praxis in weit verbreiteten Programmiersprachen (C, C ++, Perl, Javascript)
  • Spielt sich besser mit der Anwendungsschicht, z. B. Ruhezustand
  • Führt zu prägnanterem SQL, um beispielsweise herauszufinden, wie viele Bananen select sum(is_ripe) from bananasanstelle von select count(*) from bananas where is_ripe = 'Y'oder sogar (yuk) essfertig sind.select sum(case is_ripe when 'Y' then 1 else 0) from bananas

Vorteile von 'Y' / 'N':

  • Nimmt weniger Platz als 0/1 ein
  • Es ist das, was Oracle vorschlägt, also könnte es das sein, woran manche Leute eher gewöhnt sind

Ein anderes Poster schlug 'Y' / null für Leistungssteigerungen vor. Wenn Sie bewiesen haben, dass Sie die Leistung benötigen, dann fair genug, aber ansonsten vermeiden, da dies das Abfragen weniger natürlich macht ( some_column is nullstatt some_column = 0) und in einem linken Join Falschheit mit nicht vorhandenen Datensätzen in Verbindung bringt.

Andrew Spencer
quelle
3
Sie finden, dass heutzutage viele Boolesche Werte TriState sind, dh wahr, falsch und unbekannt. das passt perfekt zur Datenbank-Null-Idee. einfach, weil es oft von entscheidender Bedeutung ist, zu wissen, dass keine Antwort gegeben wurde
MikeT
1
Ja, wahr-falsch-unbekannt kann erforderlich sein, aber wenn ich wählerisch wäre (was ich bin), würde ich sagen, dass es nicht wirklich als Boolescher Wert beschrieben werden sollte, weil es nicht so ist.
Andrew Spencer
2
Wenn Sie so wählerisch sind, können Sie für jeden Datentyp das gleiche Argument vorbringen. Wie unter strikter Definition Ganzzahl, Double (ich denke, ich sollte sagen, dass Zweier mit doppelter Länge Gleitkomma ergänzen), Binär, String usw. setzen alle einen Wert voraus, aber Datenbankimplementierungen fügen immer eine Nullwertoption hinzu. Boolean ist nicht anders
MikeT
1
Wenn Sie Ihre Nummer korrekt konfigurieren, kann sie auch im selben Einzelbyte wie ein Zeichenfeld gespeichert werden, wodurch das Größenargument gegen die Verwendung von 0/1 ungültig wird. Ich kann den Link derzeit jedoch nicht finden Speicher für eine Zahl reicht von 1 - 22 Bytes je nach Konfiguration
MikeT
4
Ich vermute, dass die Abstimmungen auf einen alten Standpunkt bei der Auswahl der speichereffizientesten Implementierung zurückzuführen sind. Die heutige Speichereffizienz hat weitaus weniger Priorität und sollte nach Benutzerfreundlichkeit und Kompatibilität berücksichtigt werden. Jedem, der auf diesen Kommentar antworten kann, empfehle ich, sich über vorzeitige Optimierung zu informieren. Genau dies geschieht, wenn 'J / N' nur auf der Grundlage der Speichereffizienz ausgewählt wird. Aufgrund dieser Entscheidung verlieren Sie die native Kompatibilität mit einer Reihe häufig verwendeter Frameworks.
justin.hughey
5

Entweder 1/0 oder J / N mit einer Prüfbeschränkung. Äther Weg ist in Ordnung. Ich persönlich bevorzuge 1/0, da ich viel in Perl arbeite, und es macht es wirklich einfach, Perl-Boolesche Operationen an Datenbankfeldern durchzuführen.

Wenn Sie eine wirklich eingehende Erörterung dieser Frage mit einem von Oracles Kopf honchos wollen, prüfen, was Tom Kyte dazu zu sagen hat hier

Matthew Watson
quelle
1/0 soll "weniger speichereffizient" sein, aber ... ich mag es auch mehr (und für den Ruhezustand ist anscheinend 1/0 für einen Booleschen
Wert
1/0 ist die Standardeinstellung von Hibernate für einen Booleschen Wert. Sie können jedoch eine beliebige benutzerdefinierte Zuordnung definieren.
Andrew Spencer
@rogerdpack das ist, weil ein char Feld 1 Byte oder 2 Bytes für nchar ist, wobei je nach Definition eine Zahl 1 bis 22 Bytes sein kann
MikeT
4

Die Datenbank, an der ich den größten Teil meiner Arbeit gemacht habe, verwendete 'Y' / 'N' als Boolesche Werte. Mit dieser Implementierung können Sie einige Tricks ausführen wie:


  1. Zählen Sie die zutreffenden Zeilen: SELECT SUM (CASE WHEN BOOLEAN_FLAG = 'Y' THEN 1 ELSE 0) FROM X.


  2. Erzwingen Sie beim Gruppieren von Zeilen die Logik "Wenn eine Zeile wahr ist, sind alle wahr": SELECT MAX (BOOLEAN_FLAG) FROM Y
    Verwenden Sie umgekehrt MIN, um die Gruppierung false zu erzwingen, wenn eine Zeile false ist.

Erick B.
quelle
4
Tatsächlich sind die gezeigten Beispiele auch für den 0/1-Ansatz nützlich - und meiner Meinung nach schneller.
igorsantos07
2

Ein funktionierendes Beispiel zum Implementieren der akzeptierten Antwort durch Hinzufügen einer "Booleschen" Spalte zu einer vorhandenen Tabelle in einer Oracle-Datenbank (unter Verwendung des numberTyps):

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))
);

Dadurch wird eine neue my_table_nameaufgerufene Spalte my_new_boolean_columnmit den Standardwerten 0 erstellt. Die Spalte akzeptiert keine NULLWerte und beschränkt die akzeptierten Werte auf entweder 0oder 1.

Ben.12
quelle
1

In unseren Datenbanken verwenden wir eine Aufzählung, die sicherstellt, dass wir sie entweder TRUE oder FALSE übergeben. Wenn Sie eine der beiden ersten Methoden ausführen, ist es zu einfach, der Ganzzahl entweder eine neue Bedeutung hinzuzufügen, ohne ein ordnungsgemäßes Design zu durchlaufen, oder das Zeichenfeld mit Y, y, N, n, T, t, zu erhalten. F, f Werte und sich merken müssen, welcher Codeabschnitt welche Tabelle verwendet und welche Version von true verwendet wird.

Ryan Ahearn
quelle