Gå til innhold

Mange-til-mange-relasjon og loop inne i en annen loop


Anbefalte innlegg

Hei!

 

Nå har jeg lenge lurt på hvordan jeg skal få dette til, så jeg prøver meg i dette forumet og håper at noen kloke hoder kan hjelpe meg, og kanskje til og med skrive ned noen koder. Jeg har laget en illustrasjon med et eksempel på hva jeg mener:

php_mysql_hjelp.png

 

Dette er altså ikke utseende på tabellen jeg skal lage, men skal illustrere hva jeg mener. Php-kodene trenger jeg bare i en enkel html-tabell:

 

<?php
// En query som joiner disse fem tabellene.
?>
<table>
<?php 
	// loop 1 starter
{	
?>
<tr>
	<td>
		<?php 
			// Filmtittel her
		?>
	</td>
	<td>
		<?php 
		{
			// loop 2 (verdier skal separeres med: ", ")
		}
		?>
	</td>
	<td>
		<?php 
		{
			// loop 3 (her også: ", ")
		}
		?>
	</td>
</tr>

<?php
} // Loop 1 avslutter
?>
</table>

 

La oss si at dette skal være en tabelloversikt hos f.eks en videosjappe. Én film kan inneholde flere språk og passe under flere sjangerdefinisjoner. Dette blir en mange-til-mange-relasjon. Loop to og tre skal utføres der filmid i linktabellene stemmer overens med filmid i filmtabellen.

 

Resultatet i illustrasjonen skal sånn ca stemme overens med disse dataene: eksempel.txt

Endret av augustinus
Lenke til kommentar
Videoannonse
Annonse

Måtte nesten sette meg ned å tenke litt på denne.

 

Hva har du brukt for å tegne tabellene? De så veldig fin ut :-)

 

Correct me if I'm wrong, men ville det ikke være bedre å ha:

 

Filmer

FILMID

* link1id

* sjangerid

* link2_id

 

For en film kan kun ha en linkid, en sjangerid og en link2id. Løser det ikke absolutt alt hvis du har dem som fremmednøkler under filmer?

 

Hvordan blir normalformen på tabellen da?

 

Da når du gjør en spørring på databasen din, feks "Select from Filmer where filmnavn = "Excorsisten" and sjangerID = 'grøsser', vil du få opp kun eksorsisten?

 

Hvis du har en mange-til-mange-relasjon må du splitte den opp i en 1-til-mange relasjon i begge ender.

 

Hvis jeg bommer kraftig, så er det kun fordi det er årevis siden jeg satt med denne problematikken, og har glemt alt jeg noensinne har kunnet om SQL, normalformer og databaser generelt :-)

 

database.png

 

Hvis du har filmsjangerid, språkfilmerid som fremmednøkler i filmer, vil du da ikke få en 1-til-mange-relasjon som igjen vil medføre at en film kan tilhøre mange sjangre?

En film kan ha mange språk?

Endret av Trikrin
Lenke til kommentar

Takker for forslag, Trikrin!:) Hvis du har mulighet, så hadde jeg vært meget takknemlig for eksempel på query og array. Jeg trenger nok litt tid for å skjønne hvordan din versjon skal fungere. Jeg er veldig amatør på dette, så jeg håper du unnskylder meg.

 

Jeg legger ut en skisse på hvordan jeg så for meg min versjon i action:

php_mysql_hjelp2.png

Jeg tenkte at det ikke var noen "database-problematiske" ting med denne, men det kan hende jeg tar feil. Det var i utgangspunktet php-en jeg lurte mest på.

Lenke til kommentar

Hva er du egentlig ute etter? Filmdata.php -bildet ditt gav mening for meg, men du vil altså ha noe annet, som du ikke forklarer på noen god måte?

 

Har et par innspill til innlegget ditt:

 

#1 - Loop inne i en annen loop?

 

Unngå å kjøre spørringer i noen form for løkke. Spørringer i en nøstet løkke er galskap.

 

Riktig måte å bruke en database på er å trekke ut alle data du er interessert i gjennom en enkelt, eller maks 2-3 spørringer. Cluet er å tenke i sett-operasjoner, ikke på individuelle rader.

 

Du bør også skille tydelig mellom spørringene dine og evt. applikasjonskode. Hvis du vil ha et brukbart svar på database-spørsmål bør du skrive sql-koden din som ren tekst, evt. en parametrisert spørring. Altså helt fritt for php og lignende..

 

#2 - Filmer, språk, sjanger. Bestem deg; enten flertall eller entall, slutt å blande.

 

#3 - link1 og link2 er ekstremt dårlige navn. Finn på noe beskrivende for koblingstabellene dine. Evt. kan du bare kombinere navnene til tabellene du kobler sammen.

Lenke til kommentar
Hva er du egentlig ute etter? Filmdata.php -bildet ditt gav mening for meg, men du vil altså ha noe annet, som du ikke forklarer på noen god måte?

Jeg trenger eksempel på php-koder som syr dette sammen. Jeg har jo bare illustrert slik jeg vil at dataene skal komme ut.

 

#2 - Filmer, språk, sjanger. Bestem deg; enten flertall eller entall, slutt å blande.

Enig. De burde hete filmer, språk og sjangere. Ikke sjanger

 

#3 - link1 og link2 er ekstremt dårlige navn. Finn på noe beskrivende for koblingstabellene dine. Evt. kan du bare kombinere navnene til tabellene du kobler sammen.

Veldig enig. link_film_sjangere / link_film_spraak hadde vært mer forklarende.

 

Du har herved avslørt at jeg er ganske kunnskapsløs når det gjelder disse tingene. Desto mer takknemlig skal jeg være for hjelp.

Lenke til kommentar
Ble litt nysgjerrig på denne. Må installere de programmene jeg behøver for å se nærmere på PHP når jeg kommer hjem.

 

Hvilke programmer brukes i dag? For PHP-utvikling tenker jeg på.

 

Jeg er spent på hva du kommer fram til, Trikrin!

 

Det nærmeste jeg har kommet er dette:

<html>

<head>
	<title>filmdata, test1</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<style type="text/css">

		p {
			font: 0.85em helvetica,arial,sans-serif;
		}

		table tr td p {
			color: #4D4D4D;
		}

		table th p {
			color: #fff;
		}

		table {
			width: 320px;
			margin: 40px auto auto;
			text-align: left;
			border-collapse: collapse;
		}

		table td, table th {
			border: 1px solid #ccc;
			padding: 4px 0 4px 8px;
		}

		table th#filmtittel {
			background-color: #3A7921;
		}

		table th#sjanger {
			background-color: #B34C3D;
		}

		table th#spraak {
			background-color: #3A6595;
		}

	</style>
</head>

<?php

include 'connect_and_select_db.php';

$query=("SELECT filmer.fiid, filmer.filmtittel, sjanger.sjid, sjanger.sjanger, spraak.spid, spraak.spraak 
FROM filmer LEFT JOIN link1 ON filmer.fiid = link1.li1_fiid 
LEFT JOIN link2 ON filmer.fiid = link2.li2_fiid 
LEFT JOIN sjanger ON link1.li1_sjid = sjanger.sjid 
LEFT JOIN spraak ON link2.li2_spid = spraak.spid ORDER BY filmer.filmtittel asc");

$result = mysql_query($query) or die(mysql_error());


?>
<body>
	<table>
		<tr>
			<th id="filmtittel"><p>filmtittel</p></th>
			<th id="sjanger"><p>sjanger</p></th>
			<th id="spraak"><p>språk</p></th>
		</tr>
		<?php 
				while($row = mysql_fetch_array( $result )) {
		?>

		<tr>
			<td>
				<?php 
					echo "<p>".$row['filmtittel']."</p>"; // Her ønsker jeg filmtittel1, filmtittel 2, osv. Ikke slik det er nå
				?>
			</td>
			<td>
				<?php 
					echo "<p>".$row['sjanger']."</p>"; 
// Her ønsker å loope igjennom alle sjangere knyttet til filmid via link1 (som vi kan tenkte på som link-film-sjanger-tabell), med komma imellom
				?>
			</td>
			<td>
				<?php 
					echo "<p>".$row['spraak']."</p>";
// Og her ønsker å loope igjennom språk knyttet til filmid via link2 (link-film-språk-tabell), med komma imellom
				?>
			</td>
		</tr>
		<?php } ?>
	</table>
</body>
</html>

Resultatet blir dette: filmdata.php

 

Her repeteres filmtittel like mange ganger som filmid er å finne i linktabellene. Utfordringen blir å lage loop under sjanger- og språkkollonnen, slik at filmtittel vises bare én gang. Om dette er riktig måte å joine tabellene på, vet jeg heller ikke.

 

Dataene er hentet fra samme tabeller som før: eksempel.txt

Endret av augustinus
Lenke til kommentar

Ikke alt som er like lett å installere på en RC av Windows 7...

 

Spørsmål:

 

1: Har du sett noe på normalformene? En database-tabell må gjerne være normalisert opp til 3. normalform... Hint, et google-søk gir gjerne resultat.

 

2. bytt navnene i tabellen så det ikke er så forvirrende. F.eks :

 

FILM

SJANGER

FILMSJANGER i stedet for link1

FILMSPRAAK i stedet for link2

SPRAAK

 

Jeg ville ha hatt sjanger, og filmspraak som en fremmednøkkel i hovedtabellen min, FILM.

 

Så kan gjerne databaseekspertene der ute ( jeg er seriøst rusten, og har glemt omtrent alt), rette på meg..

 

Må se på dette i helgen hvis jeg får tid. Lykke til! Følger med denne tråden

Lenke til kommentar
...

1: Har du sett noe på normalformene? En database-tabell må gjerne være normalisert opp til 3. normalform... Hint, et google-søk gir gjerne resultat.

...

Jeg ville ha hatt sjanger, og filmspraak som en fremmednøkkel i hovedtabellen min, FILM.

...

 

Er ingen databaseekspert jeg heller, men siden det er en mange til mange relasjon mellom både film og språk og film og sjanger er det riktig å benytte en egen tabell som binder disse sammen. Tenk "en film har 1 til mange språk (Engelsk, tysk dubbing, Fransk dubbing...), et språk brukes i 1 til mange filmer (Flåklypa, olsenbanden ...)".

 

Det som er videre opp til ekspertene å vurdere er om det er lønnsomt med en ekstra join mellom språk og film, eller om du hadde vært bedre tjent med en tabell med filmID og språk (tenker da tidsmessing), når det ikke skal fylles ut mere informasjon enn navnet på språket(?).

 

eks: Språk(filmID*, Språk)

 

Vet dette fører til mange repetisjoner av de forskjellige språkene (engelsk vil stå ca like mange ganger som du har filmer), men igjen en vurdering.

 

Deretter ville jeg sett på en spørring som gir deg akkurat den tabellen du ønsker. Du kan gjøre mye rart med delspørringer..

Lenke til kommentar

Dersom du joiner sammen filmer, sjangre og språk, så vil naturligvis hver film vises ganske mange ganger. Jeg ville først kjørt en spørring for å hente ut filmer, bruk IDene til å hente ut relaterte sjangre og språk (sjekk ut IN()), for så å bruke PHP til å sette det sammen.

Lenke til kommentar

Det er snakk om mange til mange-relasjon her, så SjangerID og SpråkID kan ikke være fremmednøkkel i film-tabellen. Joiner du sammen så er det naturlig å få flere resultater av samme film. Dersom du bruker DISTINCT vil du kun få én kombinasjon av film, sjanger og språk per film. (Gitt at jeg har forstått problemstillingen rett..)

Endret av Jonas
Lenke til kommentar

Dette er kanskje galskapmetoden som Frank2004 snakker om..? Jeg kan vel se for meg at denne metoden blir krevende, når jeg tenker meg over tusen rader i hovedtabellen.

<html>
<head>
	<title>filmdata, test2</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<style type="text/css">

		p {
			font: 0.85em helvetica,arial,sans-serif;
		}

		table tr td p {
			color: #4D4D4D;
		}

		table th p {
			color: #fff;
			display: inline;
		}

		table {
			width: 520px;
			margin: 40px auto auto;
			text-align: left;
			border-collapse: collapse;
			table-layout: fixed;
		}

		table td, table th {
			border: 1px solid #ccc;
			padding: 4px 0 4px 8px;
		}

		table th#filmtittel {
			background-color: #3A7921;
		}

		table th#sjanger {
			background-color: #B34C3D;
		}

		table th#spraak {
			background-color: #3A6595;
		}

	</style>
</head>

<?php

include 'connect_and_select_db.php';

$query_filmer=("SELECT filmer.fiid, filmer.filmtittel FROM filmer ORDER BY filmer.filmtittel asc");

$query_linkfilmsjangere=("SELECT linkfilmsjangere.linkfilmsjangere_sjid, 
linkfilmsjangere.linkfilmsjangere_fiid, sjangere.sjid, sjangere.sjanger 
FROM linkfilmsjangere LEFT JOIN sjangere 
ON linkfilmsjangere.linkfilmsjangere_sjid = sjangere.sjid 
ORDER BY linkfilmsjangere.linkfilmsjangere_fiid asc");

$query_linkfilmspraak=("SELECT linkfilmspraak.linkfilmspraak_spid, 
linkfilmspraak.linkfilmspraak_fiid, spraak.spid, spraak.spraak 
FROM linkfilmspraak LEFT JOIN spraak 
ON linkfilmspraak.linkfilmspraak_spid = spraak.spid 
ORDER BY linkfilmspraak.linkfilmspraak_fiid asc");

$result_filmer = mysql_query($query_filmer) or die(mysql_error());
$result_linkfilmsjangere = mysql_query($query_linkfilmsjangere) or die(mysql_error());
$result_linkfilmspraak = mysql_query($query_linkfilmspraak) or die(mysql_error());


?>
<body>
	<table>
		<tr>
			<th id="filmtittel"><p>filmtittel</p></th>
			<th id="sjanger"><p>sjangere</p></th>
			<th id="spraak"><p>språk</p></th>
		</tr>
		<?php while($row_filmer = mysql_fetch_array( $result_filmer )) { ?>

		<tr>
			<td>
				<?php echo "<p>".$row_filmer['filmtittel']."</p>"; ?>
			</td>
			<td>
				<p>
					<?php

						while($row_sjangere = mysql_fetch_array( $result_linkfilmsjangere )) {

							if ($row_sjangere['linkfilmsjangere_fiid'] == $row_filmer['fiid']) { 

								$sjangere .= $row_sjangere['sjanger'].", ";

							}	
						}

						$sjangere=substr($sjangere, 0, -2);
						echo $sjangere;
						unset($sjangere);
						mysql_data_seek($result_linkfilmsjangere, 0);

					?>
				</p>
			</td>
			<td>
				<p>
					<?php

						while($row_spraak = mysql_fetch_array( $result_linkfilmspraak )) {

							if ($row_spraak['linkfilmspraak_fiid'] == $row_filmer['fiid']) { 

								$spraak .= $row_spraak['spraak'].", ";

							}	
						}

						$spraak=substr($spraak, 0, -2);
						echo $spraak;
						unset($spraak);
						mysql_data_seek($result_linkfilmspraak, 0);

					?>
				</p>
			</td>
		</tr>
		<?php } // Avslutter Filmtittel-loop ?>
	</table>
	<br>
</body>
</html>

Dette er altså med tre spørringer.

 

Mysql:

eksempel_v2.txt

 

Resultat:

filmdata_v2.php

Endret av augustinus
Lenke til kommentar
  • 4 uker senere...
augustinus

 

Brukte DB'en din og css'en =)

 

Resultat

Source

 

strippet vekk html\css i code tagsa

<?php
//henter db connection
include_once('config.php');

$query = "SELECT * FROM filmer ORDER BY filmer.filmtittel ASC";
$q = mysql_query($query) or die(mysql_error());

echo '<table>
<tr>
<td id="filmtittel">Tittel</td>
<td id="sjanger">Sjangere</td>
<td id="spraak">Språk</td>
</tr>'."\r\n";

while($res = mysql_fetch_object($q))
{
echo '<tr>'."\r\n";
echo '<td>'.$res->filmtittel.'</td>'."\r\n";

//hent sjangere---------------------------------
echo '<td>';

$count = 0;
$query = "SELECT sjangere.sjanger FROM linkfilmsjangere LEFT JOIN sjangere ON linkfilmsjangere_sjid = sjangere.sjid WHERE linkfilmsjangere_fiid = $res->fiid ORDER BY sjangere.sjanger ASC";
$sjangereQ = mysql_query($query) or die(mysql_error());
while($sjangereRes = mysql_fetch_object($sjangereQ))
{
	$count++;
	if($count == mysql_num_rows($sjangereQ))
	{
		echo $sjangereRes->sjanger;
	}
	else
	{
		echo $sjangereRes->sjanger.', ';
	}
}
echo '</td>'."\r\n";
//hent sjangere ferdig-----------------------------------

//hent språk---------------------------------------------
echo '<td>';

$count = 0;
$query = "SELECT spraak.spraak FROM linkfilmspraak LEFT JOIN spraak ON linkfilmspraak_spid = spraak.spid WHERE linkfilmspraak_fiid = $res->fiid ORDER BY spraak.spraak ASC";
$langQ = mysql_query($query) or die(mysql_error());
while($langRes = mysql_fetch_object($langQ))
{
	$count++;
	if($count == mysql_num_rows($langQ))
	{
		echo $langRes->spraak;
	}
	else
	{
		echo $langRes->spraak.', ';
	}
}
echo '</td>'."\r\n";
//hent språk ferdig------------------------------------------

echo '</tr>'."\r\n";
}

echo '</table>'."\r\n";
?>

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...