Avatar billede sanne Nybegynder
28. august 2005 - 20:45 Der er 25 kommentarer

sql - gange med værdi fra anden tabel

Hvordan laver man sin sql sætning hvis man skal gange en sum fra en tabel med en værdi fra en anden tabel.
Her kommer lige lidt en beskrivelse:

SELECT SUM(beløb * (SELECT valuta FROM tabel2)) as værdi

Nogen der kan hjælpe?
Avatar billede nielle Nybegynder
28. august 2005 - 21:10 #1
Jeg ville ikke gøre det som en samlet SQL idet det ikke ville være specielt effektivt. I stedet ville jeg splitte det over to:

SQL1 = "SELECT SUM(beløb) AS total FROM dinTabel1"
Set rs1 = Conn.Execute(SQL1)

total = rs1("total")

SQL2 = "SELECT valuta * " & total " FROM dinTabel2"
Set rs2 = Conn.Execute(SQL2)

Do While Nor rs2.Eof
    ' ...
    rs2.MoveNext
Loop
Avatar billede softspot Forsker
28. august 2005 - 22:07 #2
Jeg er en anelse uenig med nielle (for en gang skyld :)) - jeg ville da gøre som du lægger op til, da jeg er at den holdning at hvis databasen kan få lov til at lave alt arbejdet i et kald, så er det i de fleste tilfælde hurtigere end at skulle omkring fortolket script-kode og kalde databasen i to omgange. Derfor til jeg tro at flg. ville løse din udfordring:

SELECT SUM([beløb]) * (SELECT valuta FROM tabel2 WHERE iso='DKK') AS [valutabeløb]
FROM ordre

...eller hvad dine tabeller og kolonner nu hedder :)
Avatar billede kjulius Novice
28. august 2005 - 22:12 #3
Jeg er ligeledes uenig, men ville til gengæld nok snarere lave den som en alm. inner join:

SELECT SUM(T1.beløb) * T2.kurs AS værdi
FROM tabel1 T1 INNER JOIN tabel2 T2
  ON T1.ValutaKode = T2.ValutaKode
Avatar billede softspot Forsker
28. august 2005 - 22:30 #4
Ja, hvis der rent faktisk er en relation mellem de to tabeller, så kunne en join også være en mulighed, men du skal så nok overveje din WHERE-clause, ellers ville du vel ende med flere summer (en pr. valutakode)...
Avatar billede nielle Nybegynder
28. august 2005 - 22:50 #5
Så vidt jeg har forstået opgaven så drejer det sig om at vi har en ordre i den ene tabel, og nogle vekselkurser i den anden tabel. Det er så meningen at ordren tælles sammen som en total, og at denne derefter præsenteres i beløb svarende til de forskellige mulige valuta.

Hvis dette er korrekt, er der altså ikke nogen direkte forbindelse med posterne i den ene og posterne i den anden tabel. Derfor lægger løsningen heller ikke op til en join (INNER eller andet) i dette tilfælde.

Hvad angår udtrykket:

SELECT SUM([beløb]) * (SELECT valuta FROM tabel2 WHERE iso='DKK') AS [valutabeløb] FROM ordre

- så går min betænkelighed her på om hvorvidt sub-select'en:

(SELECT valuta FROM tabel2 WHERE iso='DKK')

- men denne løsning bliver udført en gang for hver række i tabellen ”ordre” eller om den bliver udført én gang i alt og værdien så bliver genbrugt for hver række i ”ordre”. Jeg tør ikke gætte på om det er det ene eller det andet som gælder (jeg er for resten ikke en gang helt sikker på om det overhovedet kan køre).

Mht. ideen om hvor at beregningerne skal gennemføres, så vil jeg bare påpege at det vist afhænger af så mange forskellige faktorer til at man kan sige noget generelt. Normalt er en database ikke specielt optimeret til at lave beregninger, men mere på at hive data ud, og man kan sagtens forestille sig at ASP-scriptet ville bruge færre ressourcer end SQL-databasen på en given opgave.
Avatar billede softspot Forsker
28. august 2005 - 23:12 #6
Jeg har testet denne (eller i det mindste en nær ved magen til)

SELECT SUM([beløb]) * (SELECT valuta FROM tabel2 WHERE iso='DKK') AS [valutabeløb] FROM ordre

i en Access 2000 db med querybuilder og den kører skam godt nok.
Hvad angår databasens evne til at regne, så tror jeg ikke det er der den bruger flest resurser, det er (iflg. min overbevisning) klart at få linet data op så de er klar til at arbejde med (herunder regne).

Hvis jeg kort skulle skitsere hvordan jeg tror database-motoren vil håndtere denne forspørgsel, så ville det være noget med at

1. finde alle beløb mens de akkumuleres
2. finde den valuta som har iso DKK
3. gange summen fra pkt. 1 med værdien af feltet fra pkt. 2

og returnere et recordset som indeholder dette resultat...
Avatar billede kjulius Novice
28. august 2005 - 23:21 #7
Okay, vi er så åbenbart lidt uenige om hvad opgaven består i. :-)

Mit udgangspunkt er, at vi har en ordre, hvor der er tilknyttet en valutakode (kunden befinder sig i et bestemt land). Det er så opgaven at opsummere linieværdierne (som er i DKK) og så omregne dette til et beløb i modtagerens valuta. Mest realistisk situation ville jo nok være, hvis der var en tabel med et ordrehoved, en med ordrelinierne og en med valutakurserne:

SELECT SUM(T1.beløb) * T2.kurs AS værdi
FROM Ordrehoved H
INNER JOIN Ordrelinier L
  ON H.ordrenr = L.ordrenr
INNER JOIN Valutaer V
  ON V.ValutaKode = H.ValutaKode
WHERE H.ordrenr = 225


Men hvis det var som du formoder, at værdien skal angives i forskellige valutaer, ville det stadig være mest indlysende med en inner join (sort of), dog uden sammenknyttende værdi og med en temp tabel:

SELECT V.ValutaKode, O.Tbeløb * V.ValutaKurs AS værdi
FROM (SELECT SUM(beløb) AS Tbeløb FROM Ordrelinier WHERE ordrenr = 225 ) O, Valutaer V
Avatar billede softspot Forsker
28. august 2005 - 23:27 #8
Det er godt nok meget fortolkning på det oprindelige grundlag... ;)
Avatar billede kjulius Novice
28. august 2005 - 23:28 #9
Og igen var jeg for hurtig (okay, så for sløset da!) :-(

SELECT SUM(L.beløb) * V.kurs AS værdi
FROM Ordrehoved H
INNER JOIN Ordrelinier L
  ON H.ordrenr = L.ordrenr
INNER JOIN Valutaer V
  ON V.ValutaKode = H.ValutaKode
WHERE H.ordrenr = 225
Avatar billede nielle Nybegynder
28. august 2005 - 23:31 #10
Det må vi da vist se i øjnene - måske sanne ville være så venlig at uddybe lidt? :^)
Avatar billede kjulius Novice
28. august 2005 - 23:32 #11
Helt rigtigt! LOL
Lidt abebrøl er der jo over det. Måske skulle vi bare vente på spørgerens reaktion, før vi kommer for langt ud på overdrevet.
Avatar billede sanne Nybegynder
28. august 2005 - 23:38 #12
Undskyld - men jeg jeg sidder og afprøver alle jeres svar (tak for dem) men har ikke fundet løsningen endnu.
Det er lidt kringlet:
Jeg har en tabel hvor der står beløb i et felt (beloeb), i et andet felt i samme tabel er der angivet hvilken valuta beløbet er angivet i (valuta).
Så har jeg en anden tabel med valutakurser(Exchange_rate) i den er der et felt for hver valuta (from) og en kurs (exchange).
Nu skal jeg så have lagt nogle beløb sammen og have det ud i den rigtige kurs.
Avatar billede softspot Forsker
28. august 2005 - 23:43 #13
Men er det alle beløbene i den ene tabel der skal lægges sammen, eller er det alle beløb med en bestemt værdi i et andet felt...?

Anyway! Så lyder det umiddelbart som om kjulius har den foretrukne løsning...
Avatar billede sanne Nybegynder
28. august 2005 - 23:44 #14
I får lige den rigtige sql her:

SELECT DISTINCT A.BUKRS as kode, COUNT(A.EQUNR) AS antal, B.DESCRIPTION as navn, SUM(A.ANSWT) * C.ECXHANGE AS vaerdi
FROM dbo.EQUIPMENT AS A
INNER JOIN dbo.COMPANY_CODE AS B ON A.BUKRS = B.BUKRS
INNER JOIN dbo.EXCHANGE_RATE AS C ON A.WAERS = C.[FROM]
WHERE (A.STATUS NOT LIKE '*DLFL*' AND A.STATUS NOT LIKE '*INAK*')
GROUP BY A.BUKRS,B.DESCRIPTION,C.ECXHANGE
ORDER BY A.BUKRS

Der kommer nogle helt vanvittige tal ud
Avatar billede softspot Forsker
28. august 2005 - 23:49 #15
Kan du knytte en kort kommentar til de relevante felter og tabeller...?
Avatar billede kjulius Novice
28. august 2005 - 23:49 #16
Ville det ikke være mere logisk udelade DISTINCT og skrive sådan:

SELECT A.BUKRS as kode, COUNT(A.EQUNR) AS antal, B.DESCRIPTION as navn, SUM(A.ANSWT * C.ECXHANGE) AS vaerdi
FROM dbo.EQUIPMENT AS A
INNER JOIN dbo.COMPANY_CODE AS B ON A.BUKRS = B.BUKRS
INNER JOIN dbo.EXCHANGE_RATE AS C ON A.WAERS = C.[FROM]
WHERE (A.STATUS NOT LIKE '*DLFL*' AND A.STATUS NOT LIKE '*INAK*')
GROUP BY A.BUKRS,B.DESCRIPTION,C.ECXHANGE
ORDER BY A.BUKRS
Avatar billede kjulius Novice
28. august 2005 - 23:51 #17
Eller hvis det ikke virker (ved ikke rigtigt om man bør foretage en multiplikation inden i en SUM:

SELECT A.BUKRS as kode, COUNT(A.EQUNR) AS antal, B.DESCRIPTION as navn, SUM(A.ANSWT) * AVG(C.ECXHANGE) AS vaerdi
FROM dbo.EQUIPMENT AS A
INNER JOIN dbo.COMPANY_CODE AS B ON A.BUKRS = B.BUKRS
INNER JOIN dbo.EXCHANGE_RATE AS C ON A.WAERS = C.[FROM]
WHERE (A.STATUS NOT LIKE '*DLFL*' AND A.STATUS NOT LIKE '*INAK*')
GROUP BY A.BUKRS,B.DESCRIPTION,C.ECXHANGE
ORDER BY A.BUKRS
Avatar billede kjulius Novice
28. august 2005 - 23:54 #18
Oops, jeg er virkelig for hurtig på tasterne. Da EXCHANGE feltet er en del af GROUP BY, kan det naturligvis ikke være en del af en aggregat funktion. Burde altså være:

SELECT A.BUKRS as kode, COUNT(A.EQUNR) AS antal, B.DESCRIPTION as navn, SUM(A.ANSWT) * C.ECXHANGE AS vaerdi
FROM dbo.EQUIPMENT AS A
INNER JOIN dbo.COMPANY_CODE AS B ON A.BUKRS = B.BUKRS
INNER JOIN dbo.EXCHANGE_RATE AS C ON A.WAERS = C.[FROM]
WHERE (A.STATUS NOT LIKE '*DLFL*' AND A.STATUS NOT LIKE '*INAK*')
GROUP BY A.BUKRS,B.DESCRIPTION,C.ECXHANGE
ORDER BY A.BUKRS
Avatar billede kjulius Novice
28. august 2005 - 23:56 #19
... og så er vi tilbage ved den oprindelige SQL, som du siger ikke virker. :-(
Avatar billede softspot Forsker
28. august 2005 - 23:59 #20
Næh, du har fået barberet DISTINCT væk :)
Avatar billede kjulius Novice
29. august 2005 - 00:04 #21
Ja, man bør vel være glad for de små ting her i livet... :-)
Avatar billede sanne Nybegynder
29. august 2005 - 00:08 #22
har forsøgt uden distinct - virker heller ikke
Avatar billede kjulius Novice
29. august 2005 - 00:19 #23
Er de enkelte værdier i A.ANSWT i orden?

SELECT A.ANSWT
FROM dbo.EQUIPMENT AS A
WHERE (A.STATUS NOT LIKE '*DLFL*' AND A.STATUS NOT LIKE '*INAK*')

eller evt. bare summerne:

SELECT A.BUKRS, SUM(A.ANSWT)
FROM dbo.EQUIPMENT AS A
WHERE (A.STATUS NOT LIKE '*DLFL*' AND A.STATUS NOT LIKE '*INAK*')
GROUP BY A.BUKRS

Det kan næsten kun være her problemet ligger (hvis den SQL ikke er skudt helt forbi)
Avatar billede softspot Forsker
29. august 2005 - 00:29 #24
Prøv lige at se bort fra firmanavnet i første omgang (mindre kompleksitet = bedre overskuelighed :)):


SELECT DISTINCT A.BUKRS as kode, COUNT(A.EQUNR) AS antal, SUM(A.ANSWT) * C.ECXHANGE AS vaerdi
FROM dbo.EQUIPMENT AS A
INNER JOIN dbo.EXCHANGE_RATE AS C ON A.WAERS = C.[FROM]
WHERE (A.STATUS NOT LIKE '*DLFL*' AND A.STATUS NOT LIKE '*INAK*')
GROUP BY A.BUKRS,C.ECXHANGE
ORDER BY A.BUKRS


Hvad giver det?

Og er der i øvrigt ikke redundans i fremmednøglerne...? Hvis jeg forstår dit database-design korrekt, så er der en reference fra hver af EQUIPMENT-rækkerne over i EXCHANGE og er de så alle ens for de grupperinger du laver. Hvis ikke, så kan det jo godt give nogle sære resultater (hvis man blander pund sterling og burmesiske ringit)...
Avatar billede nielle Nybegynder
09. september 2005 - 19:57 #25
sanne> Har du fået løst dit problem?
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester