2011-01-07 15 views
1

Ich versuche, ein einfaches Tagging-System (Herumspiele in php) zu implementieren ...Erste GROUP_CONCAT Werte als Einzelwert

ich den folgenden SQL-Befehl verwenden, um den erforderlichen Thread, dessen Autor und die Tags zu bekommen assoziiert mit ihm:

$thread = select_Query("SELECT thread.title, thread.id as t_id, 
         thread.content, author.username, author.id as a_id, 
         GROUP_CONCAT(DISTINCT tags.name ORDER BY tags.name DESC SEPARATOR ',') AS tags 
         FROM thread JOIN thread_tags ON thread.id = thread_tags.thread_id 
         JOIN tags ON thread_tags.tag_id = tags.id 
         INNER JOIN author on author.id = thread.author_id 
         WHERE thread.id = $id", $link); 

Wie Sie sehen können, verwende ich GROUP_CONCAT. Das funktioniert gut, aber wenn ich das tue, erscheinen die Tags alle in einer Variablen und ich weiß, dass ich $pieces = explode(",", $thread['tags]); verwenden kann. Gibt es eine andere Möglichkeit, dies zu tun? Ich frage das, weil Tags leicht zu trennen sind, wenn es etwas komplizierter ist (z. B. etwas, das das Trennzeichen enthält).

Mein Datenbankschema ist wie folgt:

thread: id, Inhalt, Titel, author_id

thread_tags: id, tag_id, thread_id

tags: id, name

+1

Warum sollte ein Tag ein Trennzeichen enthalten? Ich würde denken, dass das Programm selbst das als eine Tag-Trennung zählen und entsprechend behandeln sollte. –

+1

Keine Tags, etwas anderes, das auch eine Eins-zu-viele-Beziehung mit dem Thread haben könnte. "Tags sind jedoch einfach zu trennen, wenn es etwas komplizierter ist (z. B. etwas, das den Begrenzer enthält)." Der Teil sagt jedoch etwas komplizierter. – eddienotizzard

+0

gibt es einige Hinweise über group_concat in diesem Beitrag http://stackoverflow.com/questions/452357/mysql-group-concat-escaping –

Antwort

1

Versuchen Sie nicht, mehrere Werte in eine einzelne Zelle zu zerquetschen. Dies ist nicht die Art und Weise, wie SQL für die Verwendung entwickelt wurde. Wenn Sie richtig darauf hinweisen, kann dies zu Problemen führen, wenn Ihr Trennzeichen als einer der Werte angezeigt wird.

Zum Glück gibt es eine Möglichkeit, dies zu lösen, indem Sie Ihre Abfrage neu schreiben. Die Lösung besteht darin, mehrere Zeilen anstelle mehrerer Werte in einer Zelle zurückzugeben. Effektiv sind Sie Normalisierung Ihre Ergebnismenge.

Mit anderen Worten, statt dies:

1 tag_1,tag_2,tag_3 
2 tag_2,tag_4,tag_5 

tun:

1 tag_1 
1 tag_2 
1 tag_3 
2 tag_2 
2 tag_4 
2 tag_5 

dies tut naiverweise zur Folge haben kann, die gleichen Werte für die anderen Spalten in Duplizieren die Bandbreite verschwenden werden kann unnötig wenn diese Spalten möglicherweise viele Daten enthalten könnten. Die Lösung hierfür besteht in der Verwendung von zwei Abfragen.

Mit anderen Worten, anstatt dies:

1 foo bar tag_1 
1 foo bar tag_2 
1 foo bar tag_3 
2 baz qux tag_2 
2 baz qux tag_4 
2 baz qux tag_5 

tun:

Result 1: 
1 foo bar 
2 baz qux 

Result 2: 
1 tag_1 
1 tag_2 
1 tag_3 
2 tag_2 
2 tag_4 
2 tag_5 

nun Ihre Ergebnismenge in Normalform. Beachten Sie außerdem, dass Sie eine DISTINCT-Operation nicht mehr ausführen müssen, da Ihre Ergebnisse bereits eindeutig sind.Tatsächlich stimmen diese beiden Abfragen viel besser mit Ihren ursprünglichen Datenbanktabellen überein, sodass die Abfragen viel einfacher und schneller ausgeführt werden können.

+0

Ich habe gerade eine Antwort geschrieben, die im Grunde genau gesagt, also +1 von mir! – araqnid

+0

Er macht das schon, schau dir seine Anfrage an. Seine Gruppe concat, also hat er kein Ergebnis-Set, das den Thread-Titel, den Inhalt usw. für jede einzelne Zeile dupliziert. – profitphp

+0

@profitphp: Ich denke, du hast missverstanden. Er hat versucht, das Problem der Duplizierung von Zeilen zu lösen, indem mehrere Werte in eine einzelne Zelle gefüllt wurden. Während das "funktioniert", ist es nicht der "SQL-Weg", es zu tun. Ich denke, du musst meine ganze Antwort sorgfältig lesen - es mag auf den ersten Blick scheinen, dass er nur den ersten Teil der Antwort anwenden muss, aber sobald er das getan hat, wird er sehen, dass er auch die zweite anwenden muss. Es wäre viel einfacher, dies zu sehen, wenn Sie die Abfrage und die Ergebnisse auf dem Bildschirm hätten, aber Sie müssen es sich nur vorstellen. Ich habe Beispiele bereitgestellt, die das Vorstellen erleichtern sollen. –

1

Die meisten Tagging-Systeme haben einen festen Satz von Anforderungen, welche Zeichen in Tags enthalten sein dürfen oder nicht. Sie könnten einfach , Zeichen in Ihren Tags verbieten, und es würde gut funktionieren.

2

Sie können das Trennzeichen, das GROUP_CONCAT verwendet, zu etwas ändern, das nicht im Tag erscheint, möglicherweise das '|' Charakter.

GROUP_CONCAT(DISTINCT tags.name ORDER BY tags.name DESC SEPARATOR '|') 

Sie können das Tag-Feld auch überprüfen und sicherstellen, dass es das Trennzeichen nicht enthält.