|
| Hjælp til SELECT med GROUP BY fra 2 tabell~ Fra : Flemming |
Dato : 22-01-07 20:28 |
|
Hej,
Har ledt efter en gruppe, der kan hjælpe med dette - har prøvet på
alt.comp.databases.sql, men endnu uden det rigtige tip. Og så falder jeg
pludselig over denne gruppe, hvor der ser ud til at sidde nogle SQL-hajer.
Så jeg prøver igen:
Jeg har 2 tabeller:
pictures:
PictureId | Title | PaintDate
001 | Flowers | 2003-11-01
002 | Sunset | 2004-07-08
003 | Fish | 2004-12-08
004 | More flowers | 2005-01-31
sales:
SalesId | PictureId | SalesDate | SalesPrice
001 | 002 | 2005-01-08 | 400
002 | 003 | 2005-01-08 | 500
003 | 004 | 2005-01-08 | 600
Jeg vil gerne lave en forespørgsel, der viser hvor mange billeder er er malt
og hvor mange der er solgt per år, dvs. nogen i stil med:
Year | Painted | Sold
2005 | 1 | 3
2004 | 2 | 0
2003 | 1 | 0
Jeg kan lave det på en tabel ad gangen:
SELECT YEAR(PaintDate) AS Year, COUNT(*) AS Painted GROUP BY YEAR(PaintDate)
ORDER BY YEAR(PaintDate) DESC;
Men i så fald skal jeg "merge" resultaterne fra de forespørgsler, og det er
jo ikke så elegant.
På alt.comp.databases.sql fik jeg forslaget:
SELECT
YEAR(pictures.PaintDate) as Year,
COUNT(pictures.PictureId) as Painted,
COUNT(sales.SalesId) as Sold
FROM pictures
LEFT JOIN sales
ON YEAR(sales.SalesDate) = YEAR(pictures.PaintDate)
GROUP BY YEAR(pictures.PaintDate)
ORDER BY YEAR(pictures.PaintDate)
men den fungerer ikke.
Hvordan så?
Mvh
Flemming
| |
Jens Gyldenkærne Cla~ (22-01-2007)
| Kommentar Fra : Jens Gyldenkærne Cla~ |
Dato : 22-01-07 20:54 |
|
Flemming skrev:
> Jeg kan lave det på en tabel ad gangen:
>
> SELECT YEAR(PaintDate) AS Year, COUNT(*) AS Painted GROUP BY
> YEAR(PaintDate) ORDER BY YEAR(PaintDate) DESC;
>
> Men i så fald skal jeg "merge" resultaterne fra de
> forespørgsler, og det er jo ikke så elegant.
Hvis du med "merge" mener et join, kan jeg ikke se det uelegante:
SELECT p.theYear, p.Painted, s.Sold
FROM
(
SELECT YEAR(PaintDate) As theYear,
COUNT(*) AS Painted
FROM pictures
GROUP BY Year(PaintDate)
) p
INNER JOIN
(
SELECT YEAR(SalesDate) As theYear,
COUNT(*) AS Sold
FROM sales
GROUP BY Year(SalesDate)
) s
ON p.theYear = s.theYear
ORDER BY p.theYear
--
Jens Gyldenkærne Clausen
»Diplomatiet består netop i, at de gamle kommatister kan få lov til
at tro, at de har vundet. Men i virkeligheden har de tabt.«
Ole Togeby i Information
| |
Flemming (22-01-2007)
| Kommentar Fra : Flemming |
Dato : 22-01-07 22:12 |
|
>
> Hvis du med "merge" mener et join, kan jeg ikke se det uelegante:
>
Det jeg mente med "det uelegante" var at lave 2 separate forespørgsler, og
så flette dem sammen med noget PHP-kode. Din løsning derimod ser meget
elegant ud, og mit spm. afslører jo også, at jeg bestemt ikke er en haj til
SQL. Men så læret jeg det: En forespøgrsel i forespørgslen.
> SELECT p.theYear, p.Painted, s.Sold
> FROM
> (
> SELECT YEAR(PaintDate) As theYear,
> COUNT(*) AS Painted
> FROM pictures
> GROUP BY Year(PaintDate)
> ) p
> INNER JOIN
> (
> SELECT YEAR(SalesDate) As theYear,
> COUNT(*) AS Sold
> FROM sales
> GROUP BY Year(SalesDate)
> ) s
> ON p.theYear = s.theYear
> ORDER BY p.theYear
>
Jeg prøver den fluks, og vender tilbage...
Mvh
Flemming
| |
Flemming (22-01-2007)
| Kommentar Fra : Flemming |
Dato : 22-01-07 22:35 |
|
> SELECT p.theYear, p.Painted, s.Sold
> FROM
> (
> SELECT YEAR(PaintDate) As theYear,
> COUNT(*) AS Painted
> FROM pictures
> GROUP BY Year(PaintDate)
> ) p
> INNER JOIN
> (
> SELECT YEAR(SalesDate) As theYear,
> COUNT(*) AS Sold
> FROM sales
> GROUP BY Year(SalesDate)
> ) s
> ON p.theYear = s.theYear
> ORDER BY p.theYear
Så vidt jeg kan se virker ovenstående kun på år, hvor der BÅDE er malede og
solgte billeder. Hvis INNER JOIN erstattes af LEFT JOIN virker den kun på
år, hvor der er malede billeder, men ikke på år, hvor der kun er solgte
billeder.
Er der en udvej? Eller har jeg missed noget?
Mvh
Flemming
| |
Jens Gyldenkærne Cla~ (23-01-2007)
| Kommentar Fra : Jens Gyldenkærne Cla~ |
Dato : 23-01-07 01:10 |
|
Flemming skrev:
> Så vidt jeg kan se virker ovenstående kun på år, hvor der BÅDE
> er malede og solgte billeder.
Det er korrekt (og uhensigtsmæssigt)
> Er der en udvej? Eller har jeg missed noget?
Du kan lave full outer join - det svarer til left + right. Kan ikke
huske om alle databaser understøtter det.
Alternativt kan du benytte følgende til at finde samtlige år, og så
lave 2 x left join til dine grupperingsforespørgsler:
SELECT * FROM
(
SELECT DISTINCT YEAR(PaintDate) as theYear
FROM pictures
UNION
SELECT DISTINCT YEAR(SalesDate) as theYear
FROM sales
) x
LEFT JOIN
( ... ) p ON x.theYear = p.theYear
LEFT JOIN
( ... ) s ON x.theYear = s.theYear
Men med tre indlejrede forespørgsler bliver den måske tung i røven.
Prøv at se om full outer join (evt. bare skrevet "outer join")
fungerer.
--
Jens Gyldenkærne Clausen
Svar venligst under det du citerer, og citer kun det der er
nødvendigt for at forstå dit svar i sammenhængen. Se hvorfor og
hvordan på http://usenet.dk/netikette/citatteknik.html
| |
Flemming Jensen (23-01-2007)
| Kommentar Fra : Flemming Jensen |
Dato : 23-01-07 09:01 |
|
> > Så vidt jeg kan se virker ovenstående kun på år, hvor der BÅDE
> > er malede og solgte billeder.
>
> Det er korrekt (og uhensigtsmæssigt)
>
> > Er der en udvej? Eller har jeg missed noget?
>
> Du kan lave full outer join - det svarer til left + right. Kan ikke
> huske om alle databaser understøtter det.
>
Jeg prøver det på mit web-hoteel snarest. På Access (som jeg bruger til
små-øvelser, da det er lige ved hånden), var det ikke supporteret.
> Alternativt kan du benytte følgende til at finde samtlige år, og så
> lave 2 x left join til dine grupperingsforespørgsler:
>
> SELECT * FROM
> (
> SELECT DISTINCT YEAR(PaintDate) as theYear
> FROM pictures
> UNION
> SELECT DISTINCT YEAR(SalesDate) as theYear
> FROM sales
> ) x
> LEFT JOIN
> ( ... ) p ON x.theYear = p.theYear
> LEFT JOIN
> ( ... ) s ON x.theYear = s.theYear
>
> Men med tre indlejrede forespørgsler bliver den måske tung i røven.
Princippet er forstået - det skal forsøges. Nu er problemet med "tung i
røven" nok ikke så stort, for det er en lille database, som kører på et
web-hotel, og bruges til at hente web-sider. Der er max. et par hundrede
records i hver af de 2 tabeller. Og tilmed skal dette kun brugs så ejeren
(og hendes mand = mig) kan få lidt statistik.
Mange tak for hjælpen
Flemming
| |
Jens Gyldenkærne Cla~ (23-01-2007)
| Kommentar Fra : Jens Gyldenkærne Cla~ |
Dato : 23-01-07 12:58 |
|
Flemming Jensen skrev:
> Jeg prøver det på mit web-hoteel snarest. På Access (som jeg
> bruger til små-øvelser, da det er lige ved hånden), var det
> ikke supporteret.
Hvilken base bruger du på webhotellet?
Jeg har lige afprøvet det på MSSQL 2005 - her virker det fint.
Her er en fuld forespørgsel (med andre tabel/feltnavne - det kan du
selv rette til):
SELECT ISNULL(b.theyear, p.theyear) as theYear,
b.antal as bAntal,
p.antal as pAntal
FROM
(
select year(oprettet) as theYear, count(*) as antal
from banner
where year(oprettet) < 2006
group by year(oprettet)
) b
FULL OUTER JOIN
(
select year(oprettet) as theYear, count(*) as antal
from partnerlink
group by year(oprettet)
) p
ON b.theYear = p.theYear
Where-delen i b er kun medtaget fordi jeg skulle tjekke hvordan det
virkede når begge tabeller havde år der ikke fandtes i den anden.
--
Bolig søges. Andel eller leje i Emdrup, Nordvest, Nørrebro, Søborg
eller Brønshøj, max 6000 pr. måned.
Kontakt pr. mail - nospam(at)gyros.dk
Jens Gyldenkærne Clausen
| |
Flemming (23-01-2007)
| Kommentar Fra : Flemming |
Dato : 23-01-07 20:28 |
|
>> Jeg prøver det på mit web-hoteel snarest. På Access (som jeg
>> bruger til små-øvelser, da det er lige ved hånden), var det
>> ikke supporteret.
>
> Hvilken base bruger du på webhotellet?
Jeg bruger mySQL 5.0 (på www.one.com). Den har tilsyneladende en anden
syntax, end MSSQL, men du ved - jo mindre haj, jo mindre abstraktionsevne,
og jo mindre skridt i afprøvningen.
> SELECT ISNULL(b.theyear, p.theyear) as theYear,
> b.antal as bAntal,
> p.antal as pAntal
> FROM
> (
> select year(oprettet) as theYear, count(*) as antal
> from banner
> where year(oprettet) < 2006
> group by year(oprettet)
> ) b
> FULL OUTER JOIN
> (
> select year(oprettet) as theYear, count(*) as antal
> from partnerlink
> group by year(oprettet)
> ) p
> ON b.theYear = p.theYear
>
Som - behørigt (?) tilrettet - ikke kører - ubestemmelig syntax-fejl. Synes
at kunne se på dokumentationen, at FULL OUTER JOIN ikke er supporteret.
Derfor er jeg gået til dit forslag:
SELECT * FROM
(
SELECT DISTINCT YEAR(PaintDate) as theYear
FROM pictures
UNION
SELECT DISTINCT YEAR(SalesDate) as theYear
FROM sales
) x
LEFT JOIN
( ... ) p ON x.theYear = p.theYear
LEFT JOIN
( ... ) s ON x.theYear = s.theYear
Er nået til, at
SELECT DISTINCT YEAR(PaintDate) as theYear
FROM pictures
UNION
SELECT DISTINCT YEAR(SalesDate) as theYear
FROM sales
fungerer, og giver årstallene, men
SELECT * FROM
(
SELECT DISTINCT YEAR(PaintDate) as theYear
FROM pictures
UNION
SELECT DISTINCT YEAR(SalesDate) as theYear
FROM sales
) x
giver syntax-fejl. Arbejder videre...
Tak for hjælpen - hver gang når jeg længere og forstår mere.
Flemming
| |
Jens Gyldenkærne Cla~ (23-01-2007)
| Kommentar Fra : Jens Gyldenkærne Cla~ |
Dato : 23-01-07 22:13 |
|
Flemming skrev:
> Jeg bruger mySQL 5.0 (på www.one.com).
O.k.
> SELECT * FROM
> (
> SELECT DISTINCT YEAR(PaintDate) as theYear
> FROM pictures
> UNION
> SELECT DISTINCT YEAR(SalesDate) as theYear
> FROM sales
> ) x
>
> giver syntax-fejl. Arbejder videre...
Hm - det ser ud til at fungere på min lokale mysql5-installation.
Prøv evt. at skrive aliaserne med AS:
SELECT * FROM
(....) AS x
LEFT JOIN (....) AS s
....
--
Jens Gyldenkærne Clausen
Svar venligst under det du citerer, og citer kun det der er
nødvendigt for at forstå dit svar i sammenhængen. Se hvorfor og
hvordan på http://usenet.dk/netikette/citatteknik.html
| |
Flemming (20-03-2007)
| Kommentar Fra : Flemming |
Dato : 20-03-07 20:46 |
|
>> SELECT * FROM
>> (
>> SELECT DISTINCT YEAR(PaintDate) as theYear
>> FROM pictures
>> UNION
>> SELECT DISTINCT YEAR(SalesDate) as theYear
>> FROM sales
>> ) x
>>
>> giver syntax-fejl. Arbejder videre...
>
> Hm - det ser ud til at fungere på min lokale mysql5-installation.
>
> Prøv evt. at skrive aliaserne med AS:
>
> SELECT * FROM
> (....) AS x
> LEFT JOIN (....) AS s
> ...
Bare lige for at lukke denne tråd af med en tak til Jens: Efter noget
besvær, og en del skriveri med deres helpdesk, fandt jeg endelig ud af, at
one.com endnu ikke kører version 4.1 på server-siden. Men de har lovet, at
de er ved at opgradere. Så får vi at se om ikke det kører.
Flemming
| |
|
|