KK@llenMedlem sedan mars 20032 667 inlägg Nu har jag problem, som antagligen härstammer i mysql:s begränsade selectreringsfunktioner. Jag gör en bokguide och varje bok kan ha n antal författare. Med en selectlista kan man välja en viss författare (authorId). Med hjälp av detta id ska jag lista alla böcker där vald författaren finns med. (dbms: mysql)
Jag vill ha med följande i listningen:
* Författarens/nas kompletta namn
* Boktitel
* Bokbeskrivning
* Språk
Kan jag få ut rätt information genom att joina alla tabellerna?
-- book --
bookId (integer, räknare)
title (varchar)
description (text)
languageId (integer)
listId (integer)
-- bookAuthor --
authorId (integer, räknare)
firstName (varchar)
lastName (varchar)
-- bookAuthorList --
listId (integer, räknare)
bookId (integer)
authorId (integer)
-- language --
languageId (integer, räknare)
languageName (varchar)
LLarsGMedlem sedan dec. 200012 464 inlägg select firstName , lastNamem title, description, languageName
from book join bookAuthorList using (bookid)
join bookAuthor using (authorid)
join language on book.languageid = language.languageid
order by title
Om du vill presentera författarna som en kommaseparerad lista så får du göra det i applikationen.
KK@llenMedlem sedan mars 20032 667 inlägg Hmm, jag får inte riktigt till det. De värdena inom parantes, hänvisar de till någon tabell eller en variabel?
$sql ="select ba.authorFirstName, ba.authorLastName, b.title, b.comments, l.language
from book b join bookAuthorList bal using (bookId)
join bookAuthor ba using (authorId)
join language l on b.languageId = l.languageId
order by b.title";
You have an error in your SQL syntax near 'using (bookId) join bookAuthor ba using (authorId) join language l on' at line 2
LLarsGMedlem sedan dec. 200012 464 inlägg Det som står efter using skall vara ett kolumnnamn
select * from a join b using(c)
är (nästan*) samma som
select * from a join b on a.c = b.c
Jag hade för mig att Mysql stödde join using ...
$sql ="select ba.authorFirstName, ba.authorLastName, b.title, b.comments, l.language
from book b inner join bookAuthorList bal
on b.bookId = bal.bookid
inner join bookAuthor ba
on bal.authorId = ba.authorid
inner join language l
on b.languageId = l.languageId
order by b.title";
KK@llenMedlem sedan mars 20032 667 inlägg Det fungerade mycket bättre. :D
Man lär sig något nytt av LarsG dagligen. Bugar och bockar!
KK@llenMedlem sedan mars 20032 667 inlägg Så länge man inte ställer ett krav på att en viss författare ska finnas med så fungerar detta utmärkt. Men om jag tex ställer ett krav att:
Lista alla böcker där authorId 8 finns med.
Då hittar den iofs rätt bok och rätt författare, men bara en av flera möjliga författare om boken har flera författare. Jag kan tänka mig att man får välja ut övriga författare till boken med en egen sql-fråga i loopen. Men det är kanske någon som har ett bättre förslag? :)
AaasahMedlem sedan mars 20034 471 inlägg Hur skriver du? Så här?
$sql ="select ba.authorFirstName, ba.authorLastName, b.title,
b.comments, l.language
from book b inner join bookAuthorList bal
on b.bookId = bal.bookid
inner join bookAuthor ba
on bal.authorId = ba.authorid
inner join language l
on b.languageId = l.languageId
where bal.authorId = 8
order by b.title";
KK@llenMedlem sedan mars 20032 667 inlägg Jo, det kvittar ifall jag sätter villkoret på tabellen bal eller ba.
KK@llenMedlem sedan mars 20032 667 inlägg
LarsG skrev:
Jag hade för mig att Mysql stödde join using ...
Enligt denna sida ska mysql faktiskt göra det. Men det verkar som att man måste ange vilken typ av join (inner, left, right osv) man vill använda.
http://www.mysql.com/doc/en/JOIN.html
$sql ="select ba.authorFirstName, ba.authorLastName, b.title, b.comments, l.language
from books b inner join bookAuthorList bal using (bookId)
inner join bookAuthor ba using (authorId)
inner join language l on b.languageId = l.languageId
order by b.title";
Fungerar, dock med samma problem med att man inte får ut alla författare vid ett specificerat villkor på författare.
AaasahMedlem sedan mars 20034 471 inlägg En tanke slår mig - pröva utan order by. Får du samma fel?
I så fall: Jag antar att följande inte gör någon skillnad? (Borde det inte göra.)
$sql ="select ba.authorFirstName, ba.authorLastName, b.title, b.comments, l.language
from books b, bookAuthorList bal, bookAuthor ba, language l
where b.bookId = bal.bookId and ba.authorId = bal.authorId
and b.languageId = l.languageId and ba.authorId = 8
order by b.title";
LLarsGMedlem sedan dec. 200012 464 inlägg För att få fram det du vill så behövs en subselect
$sql ="select ba.authorFirstName, ba.authorLastName, b.title, b.comments, l.language
from book b inner join bookAuthorList bal
on b.bookId = bal.bookid
inner join bookAuthor ba
on bal.authorId = ba.authorid
inner join language l
on b.languageId = l.languageId
where bal.bookid in (
sekect bookid from bookAuthorList
where authorId = 8)
order by b.title";
Utan subselect så får man använda flera frågor och temporärtabeller.
Enligt denna sida ska mysql faktiskt göra det. Men det verkar som att man måste ange vilken typ av join (inner, left, right osv) man vill använda.
Det är ju helt onödigt enligt standard att behöva ange inner i samband med join.
KK@llenMedlem sedan mars 20032 667 inlägg Tack LarsG! Det var det jag misstänkte. Eftersom jag sitter med mysql 3.xx så får jag använda flera frågor eller nöja mig med att visa en författare (vald författare) i sökningen. :)
När är det bättre att använda using join istället för en "vanlig" join?
/R
Tackar aasah också ;)
LLarsGMedlem sedan dec. 200012 464 inlägg Som jag nämnde så är using i stort sett bara en förkortning av en join med ett on-villkor. Det kan vara bekvämt vid inner join men i stort tycker jag att det är en ganska meningslös konstruktion.
[geek-info]
Det finns en liten distinktion (som Mysql har missat, (rätta mig om jag har fel)), jämfört med att använda on.
Om man skriver
select * from a join b on a.id = b.id
så blir det två kolumner som heter id i resultatet och man kan använda
select a.id as aid, b.id as bid from a join b on a.id = b.id
men däremot om man skriver
select a.id as aid, b.id as bid from a join b using(id)
så skall man få fel enligt standard eftersom resultatet i detta fall bara innehåller en förekomst av kolumnen id och tillhör inte någon tabell så det går inte att kvalificera namnet.
Om man använder inner join så är väl detta helt ok då a.id och b.id har samma värde och det finns ingen anledning att ha med båda. Däremot om man har en outer join
select * from a left join b using(id)
så blir det konstigt eftersom b.id i vissa fall kan vara null och då finns det inget sätt att referera b.id.
För att testa om Mysql gör fel så kan man utföra följande
create table t1(c1 int);
create table t2(c1 int);
insert into t1 values(2);
insert into t2 values(2);
select * from t1 inner join t2 using(c1);
[/geek-info]
KK@llenMedlem sedan mars 20032 667 inlägg Tackar för den lektionen LarsG, ska testa mysql:s sätt att hantera saken. :D
AaasahMedlem sedan mars 20034 471 inlägg
LarsG skrev:
...[geek-info]
Det finns en liten distinktion (som Mysql har missat, (rätta mig om jag har fel)), jämfört med att använda on.
... men däremot om man skriver
select a.id as aid, b.id as bid from a join b using(id)
så skall man få fel enligt standard eftersom resultatet i detta fall bara innehåller en förekomst av kolumnen id och tillhör inte någon tabell så det går inte att kvalificera namnet.
[/geek-info]
Vad är vitsen med att skriva * istället för #:
*: select id from a join b using(id)
#: select id from a natural join b
LLarsGMedlem sedan dec. 200012 464 inlägg Natural join är ju också en tveksam och försåtlig konstruktion.
select id from a natural join b
är samma som
select id from a join b using(<lista med alla kolumner vars namn finns i båda tebellerna>)
T.ex. om det inte finns några gemensamma kolumner så kommer det att fungera som en kryss-produkt.
Ett annat problem är att om man lägger till en kolumn till en tabell så kan det påverka frågan så att man får ett annat resultat. Natural join skulle jag inte rekommendera att använda.
AaasahMedlem sedan mars 20034 471 inlägg
LarsG skrev:
Natural join är ju också en tveksam och försåtlig konstruktion....
select id from a join b using(<lista med alla kolumner vars namn finns i båda tebellerna>)
T.ex. om det inte finns några gemensamma kolumner så kommer det att fungera som en kryss-produkt...
Det är nog så riktigt. Men man vet väl för höge farao hur den egna databasen ser ut? Om den är vettigt modellerad och befinner sig i minst 3NF, är det då någon risk?
LLarsGMedlem sedan dec. 200012 464 inlägg Visst, om man har en färdig datamodell så är det nog inget problem, men om jobbar lite ad-hoc så och t.ex. har kolumner med namnet description som man nog inte vill joina.
Natural join tllför ju ingen funktionalitet heller.