
Bedeutet, ich habe einen String mit 31 Zeichen der je Zeichen den Zustand 1 oder 0 einnehmen kann.
- 1 steht für aktiv
- 0 steht für inaktiv
Beispieldaten:
'0000000001010001000000000000000'
'0000000000000000111111000011010'
Um dies anhand eines verständlichen Beispiels zu verifizieren, habe ich mir eine Dienstplan-Tabelle ausgedacht.
Beispiel:
Ein Arzt arbeitet an einem Tag in einem speziellen Krankenhausabteil.
Ziel ist es, für Abteil und Arzt eine Monats-Bitliste zu erstellen.
Heißt, an welchen Tagen im Monat arbeitet der Arzt in dem jeweiligen Abteil.

Beispiel-DDL und -DML:
SET DEFINE OFF; -- DDL CREATE TABLE "DIENSTPLAN" ( "ORT" VARCHAR2(100), "ARZT" VARCHAR2(50), "TAG" DATE ) ; -- DML Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Donald Duck',to_date('01.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Kinder- und Jugendmedizin Zentrum','Dr. Modesty Blaise',to_date('01.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Hautklinik','Dr. Lucky Luke',to_date('01.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Hautklinik','Dr. Modesty Blaise',to_date('03.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Hautklinik','Dr. Theodor Pussel',to_date('17.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Hautklinik','Dr. Theodor Pussel',to_date('18.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Hautklinik','Dr. Theodor Pussel',to_date('19.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Hautklinik','Dr. Theodor Pussel',to_date('20.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Hautklinik','Dr. Theodor Pussel',to_date('21.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Hautklinik','Dr. Theodor Pussel',to_date('22.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Donald Duck',to_date('02.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Donald Duck',to_date('03.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Donald Duck',to_date('10.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Donald Duck',to_date('12.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Donald Duck',to_date('14.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Christopher Robins',to_date('16.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Lucky Luke',to_date('17.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Lucky Luke',to_date('15.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Christopher Robins',to_date('04.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Christopher Robins',to_date('06.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Kinder- und Jugendmedizin Zentrum','Dr. Lucky Luke',to_date('10.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Kinder- und Jugendmedizin Zentrum','Dr. Lucky Luke',to_date('12.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Kinder- und Jugendmedizin Zentrum','Dr. Christopher Robins',to_date('30.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Kinder- und Jugendmedizin Zentrum','Dr. Lucky Luke',to_date('16.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Kinder- und Jugendmedizin Zentrum','Dr. Modesty Blaise',to_date('17.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Kinder- und Jugendmedizin Zentrum','Dr. Modesty Blaise',to_date('15.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Kinder- und Jugendmedizin Zentrum','Dr. Modesty Blaise',to_date('04.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Kinder- und Jugendmedizin Zentrum','Dr. Donald Duck',to_date('06.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Kinder- und Jugendmedizin Zentrum','Dr. Donald Duck',to_date('04.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Hautklinik','Dr. Modesty Blaise',to_date('02.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Hautklinik','Dr. Theodor Pussel',to_date('30.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Kinder- und Jugendmedizin Zentrum','Dr. Modesty Blaise',to_date('28.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Hautklinik','Dr. Theodor Pussel',to_date('28.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Donald Duck',to_date('28.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Hautklinik','Dr. Theodor Pussel',to_date('27.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Donald Duck',to_date('27.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Kinder- und Jugendmedizin Zentrum','Dr. Modesty Blaise',to_date('27.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Lucky Luke',to_date('18.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Chirurgische Klinik','Dr. Donald Duck',to_date('19.10.2015 00:00','DD.MM.YYYY HH24:MI')); Insert into DIENSTPLAN (ORT,ARZT,TAG) values ('Kinder- und Jugendmedizin Zentrum','Dr. Modesty Blaise',to_date('18.10.2015 00:00','DD.MM.YYYY HH24:MI'));
Nun habe ich mir zwei Ansätze überlegt, um dieses Problem zu lösen.
1. SQL mit Hilfe von CONNECT BY
SELECT DP_MONAT.ORT, DP_MONAT.ARZT, LISTAGG(CASE WHEN DP_TAG.TAG IS NOT NULL THEN '1' ELSE '0' END , '') WITHIN GROUP (ORDER BY DP_MONAT.TAG) AS TAGESLEISTE FROM (/* DIENSTPLAN Monat bilden */ SELECT ORT, ARZT, TAG FROM ( /* Liste mit 31 Zeilen bilden */ SELECT TO_DATE(TO_CHAR(ROWNUM,'00')||'.10.2015','dd.mm.yyyy') TAG FROM DUAL CONNECT BY LEVEL <= 31 ) CROSS JOIN ( /* Eindeutige Liste aus DIENSTPLAN, ohne Datum */ SELECT DISTINCT ORT, ARZT FROM DIENSTPLAN ) ORDER BY 1,2,3 ) DP_MONAT LEFT JOIN DIENSTPLAN DP_TAG ON ( DP_MONAT.ORT = DP_TAG.ORT AND DP_MONAT.ARZT = DP_TAG.ARZT AND DP_MONAT.TAG = DP_TAG.TAG ) GROUP BY DP_MONAT.ORT, DP_MONAT.ARZT
2. SQL mit "ausgeklügelter" CASE WHEN Logik
SELECT ORT, ARZT, CASE WHEN INSTR(TL,';01;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';02;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';03;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';04;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';05;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';06;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';07;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';08;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';09;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';10;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';11;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';12;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';13;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';14;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';15;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';16;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';17;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';18;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';19;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';20;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';21;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';22;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';23;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';24;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';25;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';26;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';27;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';28;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';29;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';30;') > 0 THEN '1' ELSE '0' END || CASE WHEN INSTR(TL,';31;') > 0 THEN '1' ELSE '0' END AS TAGESLEISTE FROM ( SELECT DP.ORT, DP.ARZT, ';'||LISTAGG(TO_CHAR(DP.TAG,'dd') , ';') WITHIN GROUP (ORDER BY DP.TAG)||';' AS TL FROM DIENSTPLAN DP GROUP BY DP.ORT, DP.ARZT )
In beiden Fällen kommt das gleiche Ergebnis raus.

IMHO:
Ich würde Lösung 2 verwenden, da hier der wenigste DB-Traffic erzeugt wird.
Die Oracle DB kann aber noch mehr.
Von Haus aus bringt die Oracle DB auch eigene BIT Verarbeitungsfunktionen (BIT_AND, BIT_OR,...) mit sich. Mit deren Hilfe Sie BIT Strings vergleichen können.
Hierzu ein einfaches Beispiel:
SELECT utl_raw.BIT_AND( t.A, t.B ) SET_IN_A_AND_B, length(replace(utl_raw.BIT_AND( t.A, t.B ), '0', '')) SET_IN_A_AND_B_COUNT, utl_raw.BIT_AND( t.A, utl_raw.bit_complement(t.B) ) ONLY_SET_IN_A, length(replace(utl_raw.BIT_AND( t.A, utl_raw.bit_complement(t.B) ),'0','')) ONLY_SET_IN_A_COUNT, utl_raw.BIT_AND( t.B, utl_raw.bit_complement(t.A) ) ONLY_SET_IN_A, length(replace(utl_raw.BIT_AND( t.B, utl_raw.bit_complement(t.A) ),'0','')) ONLY_SET_IN_A_COUNT, utl_raw.BIT_OR( t.A, t.B ) SET_IN_A_OR_B FROM (SELECT '1110000001010100001000000011000' A, '0000000000000010110000000000000' B FROM dual) t

Fazit:
Sie müssen keine komplexen PL/SQL Funktionen bauen um BIT-Listen zu erstellen oder zu verarbeiten. Mit etwas SQL und der Verwendung von Oracle Funktionen ist sehr viel möglich.