webForumDet fria alternativet

Mellanlagringstabell, hur få ut rätt information?

Databaser & SQL

17 svar · 452 visningar · startad av K@llen

Medlem sedan mars 20032 667 inlägg
Frågan#1

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)
Medlem sedan dec. 200012 464 inlägg
#2
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.

Medlem sedan mars 20032 667 inlägg
#3

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

Medlem sedan dec. 200012 464 inlägg
#4

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";
Medlem sedan mars 20032 667 inlägg
#5

Det fungerade mycket bättre. :D

Man lär sig något nytt av LarsG dagligen. Bugar och bockar!

Medlem sedan mars 20032 667 inlägg
#6

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? :)

Medlem sedan mars 20034 471 inlägg
#7

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";
Medlem sedan mars 20032 667 inlägg
#8

Jo, det kvittar ifall jag sätter villkoret på tabellen bal eller ba.

Medlem sedan mars 20032 667 inlägg
#9

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.

Medlem sedan mars 20034 471 inlägg
#10

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";
Medlem sedan dec. 200012 464 inlägg
#11

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.

Medlem sedan mars 20032 667 inlägg
#12

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å ;)

Medlem sedan dec. 200012 464 inlägg
#13

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]

Medlem sedan mars 20032 667 inlägg
#14

Tackar för den lektionen LarsG, ska testa mysql:s sätt att hantera saken. :D

Medlem sedan mars 20034 471 inlägg
#15

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

Medlem sedan dec. 200012 464 inlägg
#16

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.

Medlem sedan mars 20034 471 inlägg
#17

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?

Medlem sedan dec. 200012 464 inlägg
#18

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.

267 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e
123 ms — deklarationer (db)
0 ms — hämta statistik (cache)
137 ms — hämta tråd, inlägg och bilagor (db)
127 ms — ändringar (db)