Warnung: file_put_contents(/home/www/web1/html/php_dev/test.txt) [function.file-put-contents]: failed to open stream: Permission denied in /home/www/web1/html/php_dev/sys/lib.activity.php (Zeile 58)
Eine Spalte in mehrer aufteilen [Archiv] - PHP-Scripte PHP-Tutorials PHP-Jobs und vieles mehr

- Ad -
php-resource




Archiv verlassen und diese Seite im Standarddesign anzeigen :
Eine Spalte in mehrer aufteilen


 
sili
26-08-2010, 15:28 
 
Hallo
Ich versuche in MySQL eine solche Tabelle

id | text
1 | bla
2 | blup
1 | foo
2 | bar

In ein solches Abfrage-Resultat zu verwandeln:

id | text1 | text2
1 | bla | foo
2 | blup | bar


Hat jemand einen Vorschlag wie ich das am besten erledige?

PS: Das Beispiel ist stark vereinfacht, die Tabelle ist natürlich nicht genau so aufgebaut. Zusätzlich kommt ausserdem noch die Schwierigkeit hinzu, dass pro Id mehrere Texte (0, 1, 2, 3 oder auch 100) verfügbar sein können.

 
eagle275
26-08-2010, 15:31 
 
das mit "mehrere Texte pro id" schreit förmlich nach einer Zuordnungstabelle.... (m : n Relation ... )

die hast du ja vorliegen, alles was der fehlt wäre noch ein Primärschlüssel (1 zusätzliche id-Spalte oder ähnliches) ..

von der Änderung auf eine "breite" Tabelle mit mehr oder weniger Text-spalten pro ID würde ich aus Gründen von Normalisierung ernsthaft abraten

wenn du das dann abfragen willst , dann mit

"SELECT text FROM tabelle where id= 'x' "

dann kannst du in deiner Programmiersprache wunderbar alle gefundenen Text-Einträge zu deiner ID abklappern

 
Kropff
26-08-2010, 15:35 
 
Das sieht aber nach einem gewaltigen Designfehler aus. Beschäftige dich mal mit Normalisierung (http://www.peterkropff.de/site/mysql/normalisierung.htm).

Peter

 
wahsaga
26-08-2010, 15:39 
 
Vielleicht hilft dir GROUP_CONCAT?

 
sili
26-08-2010, 15:41 
 
das mit "mehrere Texte pro id" schreit förmlich nach einer Zuordnungstabelle.... (m : n Relation ... )

die hast du ja vorliegen, alles was der fehlt wäre noch ein Primärschlüssel (1 zusätzliche id-Spalte oder ähnliches) ..
Die entsprechende Spalte ist natürlich bereits vorhanden. Für mein Beispiel habe ich diese nur der Einfachheit halber entfernt. Ausserdem gehe ich davon aus, dass die Spalte für die gesuchte Abfrage nicht relevant ist ;)

von der Änderung auf eine "breite" Tabelle mit mehr oder weniger Text-spalten pro ID würde ich aus Gründen von Normalisierung ernsthaft abraten

wenn du das dann abfragen willst , dann mit

"SELECT * FROM tabelle where id= 'x' "

dann kannst du in deiner Programmiersprache wunderbar alle gefundenen Text-Einträge zu deiner ID abklappern
Das ist mir bewusst und wäre ja auch kein grosses Problem. Allerdings hätte ich gerne eine Lösung in MySQL (falls das so überhaupt möglich ist).

Das sieht aber nach einem gewaltigen Designfehler aus. Beschäftige dich mal mit Normalisierung (http://www.peterkropff.de/site/mysql/normalisierung.htm).
Meine Datenbank ist normalisiert, nur das gezeigte und stark vereinfachte Beispiel ist es nicht ;)

Vielleicht hilft dir GROUP_CONCAT?
Das hilft mir leider auch nicht weiter, da die einzelnen Texte nach der Abfrage jeweils noch weiterverarbeitet werden und dementsprechend als einzelne Variablen vorhanden sein müssen.

 
eagle275
26-08-2010, 16:35 
 
hm .. ich weiß nicht , was komplizierter ist ...


eine Spalte in 10 Zeilen zu lesen, oder 1 Zeile mit 10 spalten


von daher ... warum soll dir mysql da noch was "kochen" wenn es dir bereits die gewünschten Daten serviert?

 
onemorenerd
26-08-2010, 16:37 
 
Meine Datenbank ist normalisiert, nur das gezeigte und stark vereinfachte Beispiel ist es nicht
Das ist ein Widerspruch in sich. Eine Datenbank oder vielmehr ein Schema ist erst dann normalisiert, wenn sie – als Ganzes – den Normalisierungskriterien entspricht. Sobald eine einzige Relation/Tabelle nicht Normalform hat, gilt das ganze Schema als nicht normalisiert.
Das ist keine theoretische Kümmelkernspalterei, sondern soll dich dazu bewegen, diese Tabelle zu normalisieren. ;)

Übrigens geht es afaik gar nicht ohne Normalisierung. Um die Tupel (1,bla) und (1,foo) zum Ergebnis (1, bla, foo) umzuwandeln, musst du in der Query angeben, dass bla in text1 und foo in text2 gehört. Da sich die Tupel aber nur im Attribut text unterscheiden (die ID ist gleich), musst du - entweder die Strings bla und foo (bzw. alle Werte von text) in der Query in IF-ELSE-Klauseln verbasteln
- oder die möglicherweise zugrundeliegende Modulo-Entscheidung nutzen (Vorkommen von ID x durchnummerieren, bei geraden Nummern text in text1, bei ungeraden in text2). Das geht zum einen nur bei totaler Ordnung (ODER BY) und andererseits mangels Row-Counter nur mit Hilfe einer Prozedur (wenn überhaupt).

Lange Rede … Normalisieren! Punkt.

 
sili
27-08-2010, 15:18 
 
hm .. ich weiß nicht , was komplizierter ist ...

eine Spalte in 10 Zeilen zu lesen, oder 1 Zeile mit 10 spalten

von daher ... warum soll dir mysql da noch was "kochen" wenn es dir bereits die gewünschten Daten serviert?
Welches komplizierter ist, ist mir nicht so wichtig. Allerdings gehe ich davon aus, dass ein DB-Engine grössere Datenmengen wesentlich schneller bearbeiten kann als PHP.

Das ist ein Widerspruch in sich. Eine Datenbank oder vielmehr ein Schema ist erst dann normalisiert, wenn sie – als Ganzes – den Normalisierungskriterien entspricht. Sobald eine einzige Relation/Tabelle nicht Normalform hat, gilt das ganze Schema als nicht normalisiert.
Da stimme ich dir voll und ganz zu. Nur frage ich mich, wie du anhand eines "stark vereinfachten" Beispiels auf meine Relation und deren angeblich fehlende Normalisierung schliessen kannst ;)
Also nochmals: Das Beispiel ist extrem vereinfacht und kommt so NIRGENDS in meiner Datenbank vor. Meine Relationen SIND normalisiert. Im Beispiel fehlen nur die entscheidenden Attribute um das Beispiel einfach zu halten.

Um die Tupel (1,bla) und (1,foo) zum Ergebnis (1, bla, foo) umzuwandeln, musst du in der Query angeben, dass bla in text1 und foo in text2 gehört. Da sich die Tupel aber nur im Attribut text unterscheiden (die ID ist gleich), musst du - entweder die Strings bla und foo (bzw. alle Werte von text) in der Query in IF-ELSE-Klauseln verbasteln
- oder die möglicherweise zugrundeliegende Modulo-Entscheidung nutzen (Vorkommen von ID x durchnummerieren, bei geraden Nummern text in text1, bei ungeraden in text2). Das geht zum einen nur bei totaler Ordnung (ODER BY) und andererseits mangels Row-Counter nur mit Hilfe einer Prozedur (wenn überhaupt).
Die Benennung der Spalten ist momentan zweitrangig und kann für ein kleines Proof-of-Concept ohne weiteres statisch erfolgen. Am liebsten würde ich die Bezeichner aber anhand der Werte aus einer anderen Tabelle nennen. Aber das ist dann wieder ein anderes Thema ;)

 
AmicaNoctis
27-08-2010, 15:26 
 
Hallo,

wenn es immer die gleiche Anzahl an Texten pro ID ist, könnte man das mit einer Abfrage erledigen. Wenn aber eine ID beliebig oft vorkommt, geht es nicht, weil Abfragen mit einer dynamischen Anzahl Spalten nicht möglich sind.

MySQL kann zwar schneller mit großen Datenmengen umgehen, aber bei der Formatierung/Gruppierung der Ausgabe sind dem Grenzen gesetzt. In deinem Falle kommst du mit PHP wirklich günstiger, selbst wenn es wirklich immer zwei Texte pro ID sein sollten.

Gruß,

Amica

 
eagle275
27-08-2010, 15:27 
 
das Problem ist ... deine gewünschte Abfrage ist leider nicht normalisiert - und stellt daher die Datenbank vor entsprechende Probleme ...

An der Stelle kannst du eigentlich nur mit deiner Programmiersprache arbeiten, um die gewünschte Zusammenstellung zu erreichen ... deren Sinn leider nicht so ganz offensichtlich ist

 
AmicaNoctis
27-08-2010, 15:39 
 
das Problem ist ... deine gewünschte Abfrage ist leider nicht normalisiert

Sili sagt, die DB sei es und aus dem gegebenen Beispiel geht auch nicht das Gegenteil hervor, weswegen ich mich frage, warum das hier die ganze Zeit pauschal unterstellt wird.

 
sili
27-08-2010, 15:39 
 
Dann werde ich das wohl doch mit PHP erledigen müssen.

An der Stelle kannst du eigentlich nur mit deiner Programmiersprache arbeiten, um die gewünschte Zusammenstellung zu erreichen ... deren Sinn leider nicht so ganz offensichtlich ist
Um das ganze Mal etwas zu erklären: Es gibt eine Tabelle welche eine unbeschränkte Anzahl Suchmuster (XPATH, Reguläre Ausdrücke, ...) speichert. Anschliessend werden Dokumente durchsucht und die gefundenen Daten in der Tabelle vom Beispiel mit ID, Dokument-ID, Muster-ID und Text gespeichert. Nun sollen diese Daten in einer Übersicht dargestellt werden. Mit PHP ist das ja keine Sache, aber MySQL wäre mir lieber gewesen ;)

 
onemorenerd
27-08-2010, 16:21 
 
Also nochmals: Das Beispiel ist extrem vereinfacht und kommt so NIRGENDS in meiner Datenbank vor. Meine Relationen SIND normalisiert. Im Beispiel fehlen nur die entscheidenden Attribute um das Beispiel einfach zu halten.
Wenn man "entscheidende" Dinge weglässt, darf man sich nicht wundern, wenn man falsch verstanden wird. ;)

Ich ging davon aus, dass sich die Tupel nur im Attribut text unterscheiden. Ist wohl nicht so. Anscheinend kann mit IF-ELSE-Konstrukten anhand irgendwelcher Attribute entschieden werden, ob text zu text1 oder text2 wird.

 
sili
27-08-2010, 22:45 
 
Und es geht doch :)

Hier als kleiner Ansatz:
SELECT `gid`,
GROUP_CONCAT(IF(`id`=1, `text`, NULL)) AS `text1`,
GROUP_CONCAT(IF(`id`=2, `text`, NULL)) AS `text2`
FROM `table`
GROUP BY `gid`

(wahsaga hatte also doch Recht ;))

Allerdings produziert das nicht genau die Ansicht aus dem Beispiel, aber von der Idee her funktioniert es.

Falls es nun auch noch mit dynamischen Namen und Anzahl Einträgen funktionieren muss, kann man den GROUP_CONCAT() Teil immer noch mit PHP/wasimmer zusammenbasteln.

- -

Alle Zeitangaben in WEZ +2. Es ist jetzt 04:51 Uhr.