# [SQL] Drei Tabellen Verknüpfen - JOIN korrekt?



## boykottke (25. Januar 2008)

Hallo, 

Ich arbeite mal wieder an einem Problem, dass sich mir so bisher noch nicht gestellt hat und weswegen ich doch mal lieber nachfrage:

Also: ich habe drei Tabellen - Post, Postcontent, Comment - die ich miteinander verknüpfen will. Bisher konnte ich das durch einen einfachen Left Join machen, da in jeder Tabelle pro Post_ID nur ein Eintrag vorgelegen hat, bzw. bei Comment nur via Count zugeordnet wurde. 

Kleines Beispiel:  


```
SELECT A.*, COUNT(B.comments_post) AS count_comments, C.* 
FROM siu2_posts AS A 
LEFT JOIN siu2_comments AS B ON A.post_id = B.comments_post 
LEFT JOIN siu2_postcontent AS C ON A.post_id = C.postcontent_post 
WHERE A.post_ucat=25 AND A.post_show= 1 
GROUP BY A.post_id 
ORDER BY A.post_date LIMIT 0, 5
```
 
JETZT soll es aber möglich sein, bei Postcontent in Zukunft auch mehrere Inhalte einem Post zuzuordnen (wenn Beispielsweise ein Post eine Art Terminkalender ist, der schlicht mehrere Zeilen hat).

Mit dem derzeitigen Code wird jedem Post allerdings nur genau ein Postcontent zugeordnet. Ist es möglich, das irgendwie zu ändern?

Ich danke euch schon jetzt mal für eure Hilfe.

_______________________________


Edit: Sorry, mir ist grade aufgefallen, dass ich im Header "SQL" geschrieben habe. das ist natürlich quatsch. Es geht hier um MySQL...


----------



## Bheliaz (25. Januar 2008)

Hi boykottke,

ganz verstehe ich dein Problem nicht, denn wenn du zu einem Post mehrere Postcontent Einträge in der postcontent-Tabelle eingetragen hast, gibt der left-join 
einfach mehrere Ergebniszeilen zu einem Post zurück.

Ich kann mir nur vorstellen, dass dein Problem der Aufbau der Tabellen ist, 
also von Haus aus eine 1:1-Beziehung abgebildet wird ... 

In dem Fall kann man durch einen geänderten Join nicht viel machen.

Aber bevor ich hier noch weitere Theorien aufstelle, wäre der aufbau der Tabellen
nicht schlecht, damit ich mir ein Bild machen kann.

lg Andi


----------



## boykottke (25. Januar 2008)

mhh... die Tabellenstruktur ist gerade etwas im Fluss, da ich gerade von zwei auf drei Tabellen umstelle, eben genau um dieses Ziel wie oben beschrieben zu erreichen. Derzeit sieht sie so aus (ich geb dir mal die  SQL-Struktur, damit du sie bei dir lokal abbilden kannst):


```
--
-- Tabellenstruktur für Tabelle `siu2_comments`
--
CREATE TABLE `siu2_comments` (
  `comments_id` int(11) NOT NULL auto_increment,
  `comments_post` varchar(50) NOT NULL,
  `comments_postcontent` varchar(50) NOT NULL,
  `comments_name` varchar(50) NOT NULL default '',
  `comments_mail` varchar(50) NOT NULL default '',
  `comments_page` varchar(50) NOT NULL default '',
  `comments_content` longtext NOT NULL,
  `comments_date` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `comments_ip` varchar(50) NOT NULL default '',
  `comments_host` varchar(50) NOT NULL default '',
  `comments_show` tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (`comments_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
 
-- --------------------------------------------------------
--
-- Tabellenstruktur für Tabelle `siu2_postcontent`
--
CREATE TABLE `siu2_postcontent` (
  `postcontent_id` int(11) NOT NULL auto_increment,
  `postcontent_post` varchar(50) collate latin1_general_ci NOT NULL,
  `postcontent_title` varchar(100) collate latin1_general_ci NOT NULL,
  `postcontent_content` longtext collate latin1_general_ci NOT NULL,
  `postcontent_date_1` datetime NOT NULL,
  `postcontent_date_2` datetime NOT NULL,
  `postcontent_creator` varchar(50) collate latin1_general_ci NOT NULL,
  `postcontent_show` int(1) NOT NULL default '0',
  PRIMARY KEY  (`postcontent_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=1 ;
 
-- --------------------------------------------------------
--
-- Tabellenstruktur für Tabelle `siu2_posts`
--
CREATE TABLE `siu2_posts` (
  `post_id` int(11) NOT NULL auto_increment,
  `post_ucat` varchar(50) NOT NULL default '',
  `post_title` varchar(50) NOT NULL default '',
  `post_content` longtext NOT NULL,
  `post_date` datetime NOT NULL default '0000-00-00 00:00:00',
  `post_creator` varchar(50) NOT NULL default '',
  `post_show` tinyint(1) NOT NULL default '0',
  `post_comments` tinyint(1) NOT NULL default '0',
  `post_rss` int(1) NOT NULL default '0',
  `post_pdf` int(1) NOT NULL default '0',
  `post_print` int(1) NOT NULL default '0',
  PRIMARY KEY  (`post_id`),
  KEY `post_ucat` (`post_ucat`),
  KEY `post_title` (`post_title`),
  KEY `post_date` (`post_date`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
```
 
Die Verbindung zwischen allen Tabellen bildet also die post_id, die in den anderen tabellen jeweils unter dem Titel comments_post bzw. postcontent_post wiederzuentdecken ist. Also für mich sieht das nicht unbedingt so aus, als sollte da nur eine Zeile ausgegeben werden ... Was meinst du?

Odre muss ich eventuell die Auswertung der Daten durch die PHP-Schleife abändern? aber normalerweise habe ich mir ja die gelieferten Daten drucken lassen und als nicht geliefert erkannt... Mhh...


----------



## Bheliaz (25. Januar 2008)

Hallo boykottke,

habe jetzt etwas mit deinem SELECT herumprobiert und muss sagen, Es wundert mich dass sowas in MySQL funktioniert. Arbeite normalerweise mit Oracle und da würde ein derartiges SELECT sofort in einen Fehler münden. Aber gut.

Das Problem ist folgendes:

```
GROUP BY A.post_id
```

Du willst bei deinem Select ja alle Spalten der Posts- und Postcontent-Tabelle. Zusätzlich zählst du die comments. Wenn du allerdings ein Group by auf die post_id machst, bekommst du immer nur eine Ergebniszeile pro Post, auch wenn du in den anderen Tabellen mehrere Datensätze hast, deren Fremdschlüssel auf den selben Datensatz deiner posts-Tabelle verweisen. Mysql scheint in einem derartigen Fall einfach die Inhalte des ersten Datensatzes der Postcontent-Tabelle zurückzugeben.

Einfachste Lösung wäre, wenn du auch die postcontent_id ins group by einbeziehen würdest. 


```
GROUP BY A.post_id, C.postcontent_id
```

Allerdings wirst du dann auch in deinem PHP-Code einiges umstellen müssen würde ich schätzen. Bezüglich PHP kann ich dir aber leider nicht weiterhelfen, das ist leider nicht meine Welt .

lg Andi


----------



## boykottke (26. Januar 2008)

Oh ja, wem sagst du das. Es ist wirklich nicht unbedingt der sauberste Code, den MySQL da verarbeiten soll. Aber immerhin. 

Also, danke erst einmal für deine Hilfe. Es hat sich tatsächlich rausgestellt, dass das funktioniert, und das so gut, dass deine zweite Weissagung, dass ich meinen Code umstellen müsste, bewahrheitet hätte.

Nun hab ich mir den Kosten/Nutzen mal angeschaut. Eigentlich sollte ja die Sortierform noch änderbar sein, etc. Das kann ich an dieser Stelle aber mal spontan vergessen. Der bisherige Code ist vollkommen ungeeignet für die von mir angestrebten Ziele. Wenn ich jetzt mal überlege, was schlimmer wäre (code umschreiben oder ein extra query), habe ich mich für den zusätzlichen Query entschieden und werde nun die Abfarge von Post und Post-Content trennen, aus Post Content ein PlugIn machen und ansonsten die Texte in den Posts speichern. 

Nützlich war deine Hilfe allerdings trotzdem, nämlich in der Form, dass ich das komplett für ein anderes Projekt verwenden kann. Herzlichen Dank...  Von mir 5 Sterne und ein Bienchen ins Muttiheft...


----------

