MySQL: Spaltennamen von NULL-Werten in separate Spalte ausgeben?


Status
Dieses Thema wurde gelöst! Zur Lösung gehen…
#1
Hallo liebe Foren-Gemeinde,

da ihr mir hier schon einmal prima geholfen habt, versuche ich es doch glatt noch einmal bei euch :)
Ich möchte gerne, dass mir ausgewählte Spaltennamen zu jedem Datensatz Komma separiert in eine eigene Spalte ausgegeben werden, bei denen bestimmte Werte NULL sind.

Als Beispiel:

Tabelle: Kontakte

1. Spalte: Vorname
2. Spalte: Nachname
3. Spalte: Geburtsdatum
4. Spalte: Telefonnummer
__________________________
5. Spalte: FEHLENDE INFOS

Die Spalten 1-4 sind teilweise leer (NULL). Von diesen möchte ich jetzt gerne die Spaltennamen Komma separiert in die Spalte "FEHLENDE INFOS" ausgegeben haben.

Beispiel 1:

1. Vorname: Max
2. Nachname: Muster
3. Geburtsdatum: NULL
4. Telefonnummer: NULL
__________________________
5. FEHLENDE INFOS: Geburtsdatum, Telefonnummer


Beispiel 2:

1. Vorname: Max
2. Nachname: NULL
3. Geburtsdatum: 01.01.1970
4. Telefonnummer: NULL
__________________________
5. FEHLENDE INFOS: Nachname, Geburtsdatum

Hat jemand einen Tipp für mich?
Stehe hier (als Newbie) leider gerade auf dem Schlauch und hoffe auf eure Hilfe.

Beste Grüße,
Canju
 

Yaslaw

n/a
Moderator
#2
Am elegantesten lässt sich das mit dem MySQL-Befehl make_set() umsetzen
SQL:
select 
	t.*,
	make_set(
		if(vorname is null, 1, 0)
		| if(nachname is null, 2, 0)
		| if(geburtsdatum is null, 4, 0)
		| if(telefonnummer is null, 8, 0),
		'vorname', 'nachname', 'geburtsdatum', 'telefonnummer'	
	) as missing
from my_table t;
der | ist ein Bit-OR.
Code:
vorname | nachname | geburtsdatum | telefonnummer | missing
--------|----------|--------------|---------------|---------------------------
Max     | Muster   |              |               | geburtsdatum,telefonnummer
        | Meier    | #12/01/1976# |               | vorname,telefonnummer
 
Zuletzt bearbeitet:
#3
Am elegantesten lässt sich das mit dem MySQL-Befehl make_set() umsetzen
SQL:
select
    t.*,
    make_set(
        if(vorname is null, 1, 0)
        | if(nachname is null, 2, 0)
        | if(geburtsdatum is null, 4, 0)
        | if(telefonnummer is null, 8, 0),
        'vorname', 'nachname', 'geburtsdatum', 'telefonnummer' 
    ) as missing
from my_table t;
der | ist ein Bit-OR.
Code:
vorname | nachname | geburtsdatum | telefonnummer | missing
--------|----------|--------------|---------------|---------------------------
Max     | Muster   |              |               | geburtsdatum,telefonnummer
        | Meier    | #12/01/1976# |               | vorname,telefonnummer


Hey Yaslaw,

lieben Dank für deine Antwort.
Ich konnte die Select / make_set Kombination bei mir anwenden.

Ich habe auch einige andere Felder bei mir hinzugefügt, bspw.:

Code:
select
    t.*,
    make_set(
        if(vorname is null, 1, 0)
        | if(nachname is null, 2, 0)
        | if(geburtsdatum is null, 4, 0)
        | if(telefonnummer is null, 8, 0)
        | if(feld4 is null, 16, 0)
        | if(feld5 is null, 32, 0),
        | if(feld5 ='', 32, 0), // weil manchmal auch "leere Strings" vorhanden
        | if(feld6 is null, 64, 0),
        | if(feld7 is null, 128, 0),
        'vorname', 'nachname', 'geburtsdatum', 'telefonnummer', 'feld4', 'feld5', 'feld6', 'feld7'
    ) as missing
from my_table t;

Ich muss aber gestehen, dass ich das nicht zu 100% kapiert habe, es funktioniert einwandfrei danke nochmal.

Kannst du mir helfen make_set richtig zu verstehen?

Ich kapiere einfach nicht so ganz weshalb 1,2,4,8,16,32,64,128. Das Muster (2er Potenz) ist zu erkennen nur mir leuchtet nicht ein wie ich auf die korrekte Bitzahl komme (MAKE_SET(bits,str1,str2,...)), die mir dann den richtigen "Spaltennamen" zurückgibt.

Und warum jeweils die 0 noch dahinter?
Kann ich das beliebig erweitern oder stoße ich irgendwann an eine Grenze?

Sorry für's löchern, lässt mir aber gerade keine Ruhe :)

Beste Grüße,
Canju
 

Yaslaw

n/a
Moderator
#4
Das ganze musst du dir als Bit-Maske vorstellen
Code:
Wert            str1 | str2 | str3 | str4 | str5
bit                1 |    2 |    4 |    8 |   16
bits  5=1+4:       1 |    0 |    1 |    0 |    0
Die letzte Zeile ist der Wert, der dann du errechnest. In dem Fall 5. Also 1 | 4 oder 1+4. Wenn dann in Bits zerlegt wird, dann gibt es ja diese bekannte 0/1er Maske. Diese über die Resultate gelegt zeigt an, welche Werte genommen werden sollen.

Die 0: Du wilst ja eine Zahl errechnen, die die nachher die Maske bestimmt. Also entweder eine Zahl oder 0.

Noch was. DU hast Felder die Null oder '' sein können. Diese würde ich zur Sicherheit immer so prüfen, dass er bei Null ein Leerstring macht und diesen dann mit einem Leerstring vergleicht. Sicherheitshalber setze ich meistens noch ein trim() drauf, um auch Felder mit einem nur einem Leerzeichen als Leer zu definieren
Ist eleganter als deine Lösung
SQL:
if(trim(ifnull(t.feld5, '')) = '', 32, 0),
 
#5
Prima, danke dir. Das Licht am Ende des Tunnels nähert sich :)

Zu: if(trim(ifnull(t.feld5, '')) = '', 32, 0),:
Ich habe vor das make_set später in ein UPDATE zu setzen und per cron auszuführen, sodass über das Feld missing (lege ich vorher natürlich in der DB an) jederzeit ersichtlich ist welche Daten fehlen und entsprechende Maßnahmen getroffen werden können.
Würde das trim dann den Originalzustand (also NULL) im Zuge des Updates überall durch ein '' ersetzen?
Oder dient dies nur als "Hilfsoperation"?
 

Yaslaw

n/a
Moderator
#6
Das Original wird nie berührt.
ifnull() gibt den Wert zurück, falls dieser null ist, dann den 2ten Wert.
trim() gibt ein Wert zurück, bei dem Leerzeichen am Anfang und am Ende entfernt wurde
 
#7
Dank dir nochmal ganz herzlich.
Habe deine Lösungsansätze alle einbauen können. Das Update und der Cron laufen jetzt.
Prima, dass es Leute wie dich gibt, mach weiter so. (Thumbs up).
 
#8
ich muss doch nochmal eine Frage hinterher schicken.

Wenn ich EINEN Spaltennamen angezeigt bekommen möchte, sofern 2 Felder fehlen, muss ich doch ein UND mit in das Bit-OR einfügen oder?

| if(trim(ifnull(feld5, '')) AND trim(ifnull(feld6, '')) = '', 16, 0),

PHP:
$sqlOutputMissingFieldnames = <<<SQL
UPDATE t1 as t1
LEFT JOIN t2 as t2 on t1.id = t2.id
SET
    missing_data=
        make_set(
        if(trim(ifnull(feld1, '')) = '', 1, 0)
        | if(trim(ifnull(feld2, '')) = '', 2, 0)
        | if(trim(ifnull(feld3, '')) = '', 4, 0)
        | if(trim(ifnull(feld4, '')) = '', 8, 0)
        | if(trim(ifnull(feld5, '')) AND trim(ifnull(feld6, '')) = '', 16, 0),
        'Spaltenname1', ' Spaltenname2', ' Spaltenname3', ' Spaltenname4', ' Spaltenname5'
        )
WHERE feld ='xxx'
AND feld = 'xxx'
SQL;
Wenn also feld5 UND feld6 NULL sind, dann möchte ich "Spaltenname5" ausgegeben bekommen.
(Da das Firmendaten sind muss ich die Felder leider "anonymisieren")

Magst du mir nochmal auf die Sprünge helfen?
 

Yaslaw

n/a
Moderator
#9
Auch die SPalte 5 musst du noch mit '' vergleichen.
Setze es zur Sicherheit mal in eine Klammer.
SQL:
| if((trim(ifnull(feld5, '')) = '' AND trim(ifnull(feld6, '')) = ''), 16, 0)
Im Zweifelfall mal das ganze mit Zeileumbruch schreiben, dann sieht man schneller wo eine Klammer zuviel oder zuwenig ist
SQL:
| if(
		(
			trim(ifnull(feld5, '')) = '' 
			AND trim(ifnull(feld6, '')) = ''
		),
		 16, 
		 0
	)
 
Status
Dieses Thema wurde gelöst! Zur Lösung gehen…