[MySQL, phpmyadmin] mehrere Werte in Index-Feld eintragen

rince1984

Mitglied
Hallo zusammen,

ich versuche gerade für ein Projekt eine Webseite zu erstellen mit deren Hilfe eine Person über eine Suchmaske einen Kunden* suchen und auswählen kann.
Nach Auswahl eines Kunden sollen die Kundendetails angezeigt und eine Dropdownliste zur Auswahl der zum Kunden passenden Kampagnen* angezeigt werden.
Nach Auswahl der gewünschten Kampagne und Klick auf einen Button soll statt der Kampagnen-Dropdownliste eine Dropdown-Liste aller Produkte* der ausgewählten Kampagne angezeigt werden.
Nach Auswahl des Produkts und Klick auf einen Button werden die Produktdetails angezeigt und es erscheint wiederum ein Button der ein PHP-Script zum Export der Kunden- und Produktdaten ausführt.
*(Werte/Daten stehen in einer MySQL-Datenbank)

Prinzipiell habe ich das schon alles hinbekommen. Mein Problem ist nur, dass einem Kunden auch mehrere Kampagnen zugewiesen sein können, ich aber Kunden nicht doppelt anlegen und mit der entsprechenden Kampagne verknüpfen möchte (sonst gibt meine Suche diese Kunden auch entsprechend oft als Ergebnis aus).
In meiner Datenbank habe ich mit Hilfe von phpmyadmin bereits eine Beziehung mit Hilfe von Fremdschlüsseln hergestellt. Die Tabellen "Kunden" und "Produkte" sind beide Child-Tabellen der Tabelle "Kampagnen". Primärschlüssel ist "kampagnen_id" in der Tabelle "Kampagnen".

Aufbau Tabelle "Kunden":
kunden_id | kunden_name | kampagnen_id
1 | ABC GmbH | 1
2 | XYZ AG | 1
3 | Muster | 2

Aufbau Tabelle "Kampagnen":
kampagnen_id | kampagnen_name
1 | Business
2 | Party
3 | Freizeit

Aufbau Tabelle "Produkte":
produkt_id | produkt_details | kampagnen_id
1 | Flyer | Bunter Flyer | 2
2 | Briefpapier | Firmenbriefpapier Vordruck | 1
3 | Visitenkarte | Schlicht | 1
4 | Spielbrett | Mensch ärgere dich nicht | 3

Beispiel:
- Der Kunde ABC GmbH soll sowohl der Kampagne 1 (Business), als auch der Kampagne 2 (Party) zugewiesen sein. Nach Auswahl des Kunden ABC GmbH sollen nun die Kampagnen 1 und 2 in einer Dropdown-Liste zur Auswahl stehen.
- Der Kunde XYZ AG soll den Kampagnen 1, 2 und 3 zugewiesen sein.
- Der Kunde Muster soll nur der Kampagne 2 zugewiesen sein.

Gibt es eine Möglichkeit bei einem Kunden (Datensatz) mehrere Kampagnen-IDs einzutragen?
Oder gibt es einen anderen sinnvollen Weg ohne, dass ich pro zugewiesener Kamapagne einen weiteren Datensatz anlegen muss?


Über Lösungsansätze würde ich mich sehr freuen.

Danke und viele Grüße
Thomas
 

sheel

I love Asm
Hi

da fehlt einfach etwas allgemeine Normalisierung, und nicht in "Childtabellen" zu denken:

Vorher:
Aufbau Tabelle "Kunden":
kunden_id | kunden_name | kampagnen_id
1 | ABC GmbH | 1
2 | XYZ AG | 1
3 | Muster | 2

Nachher:
Aufbau Tabelle "Kunden":
kunden_id | kunden_name
1 | ABC GmbH
2 | XYZ AG
3 | Muster
Aufbau Tabelle "KundenKampagnen":
kunden_id | kampagnen_id
1 | 1
2 | 1
3 | 2

...
Das Selbe für die Tabelle Produkte
 

Improof

Erfahrenes Mitglied
Hi Thomas,

du hast da eine 1:n Beziehung gebaut (1 Kampagne <-> n Kunden). Also 1 Kampagne kann mehreren Kunden zugewiesen werden. Andersrum kann dann aber 1 Kunde auch nur 1 Kampagne haben.

Kunden doppelt anlegen auf keinen Fall!

Was du brauchst ist eine n:m Beziehung (n Kampagnen <-> m Kunden). Das machst du, indem du zuerst die "kampagnen_id" aus Tabelle "Kunden" entfernst.
Dann erstellst du dir eine Zwischentabelle (z.B. ZWT_Kunden_Kampagnen), die nichts enthält außer der "kunden_id" und der "kampagnen_id" und diese beiden Felder als gemeinsamen PRIMARY KEY.

Für dein genanntes Beispiel würde die Tabelle dann wie folgt aussehen:

ZWT_Kunden_Kampagnen
kunden_id | kampagnen_id
1 | 1
1 | 2
2 | 1
2 | 2
2 | 3
3 | 2


Gruß
Daniel

EDIT:
Da war @sheel wohl etwas schneller als ich ;)
 

rince1984

Mitglied
Hi sheel und Daniel,

vielen Dank für eure sehr hilfreichen Antworten! Das klingt für mich logisch und ich hatte auch schon in diese Richtung gedacht, konnte es gedanklich aber nicht voll zu Ende bringen (manchmal steht man einfach komplett auf dem Schlauch!).

Ich werde es ausprobieren und gebe dann eine Rückmeldung.

Viele Grüße
Thomas
 

rince1984

Mitglied
So, jetzt hab ich das mal entsprechend in der Datenbank umgesetzt und auch an meinem PHP-Code etwas gewerkelt. Leider klappt der Abruf der Kampagnen-ID aus der Zwischentabelle nicht und ich komme nicht drauf warum nicht...

Meine Zwischentabelle habe ich "kunden_kampagnen" genannt.

Folgend mein PHP-Code:
PHP:
session_start();

// Übergabe des Ergebnis aus der Suche (Suche ist in anderer PHP-Datei)
$suchErgebnis = $_POST['Kunde'];

include("datenbankverbindung.php");

// Abfrage des zum Suchergebnis passenden Datensatzes (Kundenname)
$abfrage = 'SELECT * FROM Kunden WHERE kunden_name LIKE \''.$suchErgebnis.'\'';
$ergebnis = mysqli_query($verbindung, $abfrage);

// Datensätze in Variable speichern zur späteren Verwendung (und in Session speichern für spätere Verwendung in externen PHP-Dateien)
while($row = mysqli_fetch_object($ergebnis)) {
    $kdID = $row->kunden_id;
    $_SESSION['kdID'] = $kdID;
    $name = $row->kunden_name;
    $_SESSION['kdName'] = $name;
}

// Abfrage der Kampagnien-ID in der Zwischentabelle kunden_kampagnen
$abfrage2 = 'SELECT * FROM kunden_kampagnen WHERE kunden_id LIKE \''.$kdID.'\'';
$ergebnis2 = mysqli_query($verbindung, $abfrage2);

if($suchErgebnis <> "") {
    while ($row = mysqli_fetch_object($ergebnis2)) {
        $varKampagnenID = $row->kamapgnen_id;
            echo "<tr><td class='tdLeft'><b>Kampagnen-ID:</b></td> <td class='tdLeft'>" . $varKampagnenID . "</td></tr>";
    }
}
echo "</table></div></div>";

// Abfrage 
$abfrage3 = 'SELECT * FROM Kampagnen WHERE kampagnen_id LIKE \''.$varKampagnenID.'\'';
$ergebnis3 = mysqli_query($verbindung, $abfrage3);

if($suchErgebnis <> "") {
    echo "<div class='row'><div class='col-md-4 col-md-offset-4 text-center'>";
    echo "<h3>Kampagnenauswahl</h3>";
    echo "<form id='formKampagnen' action='' method='post'>";
    echo "<select id='selectKampagne' class='form-control' name='selectKampagne'>";
    while ($row = mysqli_fetch_object($ergebnis3)) {
        $varKampagnenName = $row->kampagnen_name;


        echo "<option value=" . $varKampagnenID . ">" . $varKampagnenName . "</option>";
    }
    echo "</select>";
    echo "<br /><button id='btnProdukte' type='submit' class='btn btn-info'>Produkte</button><br />";
    echo "</form>";
    echo "</div></div>";

}

mysqli_close($verbindung);

Sicherlich nicht der schönste Codeaufbau, aber prinzipiell konnte ich mit diesem Konstrukt bisher gut arbeiten (nach Kundenauswahl eine Dropdown der passenden Produkte usw.; allerdings ohne Zwischentabelle).
So wird allerdings die Kampagnen-ID nicht ausgegeben, obwohl er die entsprechende Anzahl an Reihen scheinbar erkennt (der statische Text vor der Variablen wird x-fach ausgegeben).

Habt ihr nochmal einen Tipp für mich?
Leider finde ich kein vernünftig erklärtes Tutorial zu diesem konkreten Thema (n:m Beziehung Daten auslesen).

Viele Grüße
Thomas
 

sheel

I love Asm
Hi

bei
PHP:
$varKampagnenID = $row->kamapgnen_id;
hat sich ein Schreibfehler eingeschlichen (kamapgnen)

Wenn dann noch immer nur die Anzahl passt (aber die Werte nicht),
lass dir in der Schleife einmal var_dump($row) ausgeben, statt spezifischer Werte,
und schalt das Errorreporting am Scriptanfang ein:
PHP:
error_reporting(E_ALL);
ini_set('display_errors', true);
.
PS: Mysqli, sehr gut :)
 

rince1984

Mitglied
Vielen Dank für deine Antwort. Ich habe mir den Code-Teil gefühlt tausend mal durchgelesen, weil ich auch zuerst auf einen Schreibfehler getippt hatte. Es war tatsächlich nur dieser Fehler. :confused:

Ich denke, dass ich das Wort Kampagne durch ein leichter zu schreibendes Synonym ersetzen werde. Das Wort ist ja fast genauso fehleranfällig wie "Personalisierung". :rolleyes:

PS: Und wieder habe ich das Problem, dass ich das Thema nicht schließen kann. Oben bei der Überschrift gibt es keinen Schließen-Button/-Link. Nachdem scheinbar einige Leute hier im Forum in der Vergangenheit und aktuell das gleiche Problem haben wäre doch ein Thread mit Screenshot etc. sinnvoll?!
 
Zuletzt bearbeitet:

sheel

I love Asm
Erledigtbutton: Das Problem ist schon bekannt ja, aber eine Lösung,
die dem Admin vom Aufwand her zumutbar ist, ist leider unbekannt :rolleyes: