webForumDet fria alternativet

SQL SUM() i WHERE kriteria

6 svar · 974 visningar · startad av Blixtsystems

BlixtsystemsMedlem sedan maj 2005704 inlägg
#1

Har ett litet MySQL problem.

Jag behöver summan av ett fält i en tabell för att använda i mina WHERE kriteria.

Har testat följande:

SELECT DISTINCT hand.id
FROM handdata_hand AS hand, 
	 handdata_players AS players, 
	 handdata_forced AS forced 
WHERE players.hand_id=hand.id  
AND forced.hand_id=hand.id
AND ((players.player_stack / (SELECT SUM(amount) 
   FROM forced 
   WHERE hand_id = hand.id )) BETWEEN 0 AND 5)

Uppenbarligen kan jag inte använda alias i en subquery och får:
Table 'handdata.forced' doesn't exist

Det är egentligen en mycket längre fråga och använder jag inte alias i min subquery så relaterar inte resultatet till rätt "hand.id".

Kör jag innan "FROM" så vet jag inte hur jag skall kunna använda värdet under "WHERE", t.ex.:

SELECT DISTINCT hand.id, SUM(forced.amount) AS forcedamount
FROM handdata_hand AS hand, 
	 handdata_players AS players, 
	 handdata_forced AS forced 
WHERE players.hand_id=hand.id  
AND forced.hand_id=hand.id
AND ((players.player_stack / forcedamount) BETWEEN 0 AND 5)

Det ger mig: Unknown column 'forcedamount' in 'where clause'

Någon som har en idé?

PeddaMedlem sedan juni 20006 032 inlägg
#2

Flyttas från PHP

aasahMedlem sedan mars 20034 471 inlägg
#3

Blixtsystems skrev:

Har ett litet MySQL problem.

Jag behöver summan av ett fält i en tabell för att använda i mina WHERE kriteria.

Enligt syntaxen i SQL kan man aldrig ha aggregerande funktioner i WHERE. I WHERE jämför man värden som finns (eller inte) i kolumner, inte med beräknade värden.

Det finns tre olika lösningar lite beroende på vad du är ute efter.
* Temporär tabell/vy där du mellanlagrar uträkningen och joinar ihop med resten för att kunna jämföra.
* Stoppa in en delfråga (subquery) där du räknar ut resultatet och jämför detta med något värde i WHERE.
ELLER använd HAVING. HAVING används för att jämföra med aggregerade funktioner. Med subfråga...

Om du väljer subfrågan måste du föra in en kopia av tabellen igen:

SELECT DISTINCT hand.id
FROM handdata_hand AS hand, 
	 handdata_players AS players, 
	 handdata_forced AS forced 
WHERE players.hand_id=hand.id  
AND forced.hand_id=hand.id
AND players.player_stack / (SELECT SUM(amount) 
   FROM handdata_forced  -- Annan än den utanför
   WHERE hand_id = hand.id ) BETWEEN 0 AND 5
BlixtsystemsMedlem sedan maj 2005704 inlägg
#4

Hoppsan...jag tyckte det var konstigt att det inte fanns något SQL forum då jag tittade i webbrelaterade forum, men det var bara jag som tittade i fel subforum :r

Jag har testat med att ange handdata_forced som du föreslår men problemet är då hur jag skall relatera till rätt hand_id.

Det verkar som HAVING borde funka, men SQL kratta som jag är så får jag inte riktigt till det.
Denna frågan kör ok:

SELECT DISTINCT hand.id, SUM( forced.amount ), players.player_stack
FROM handdata_hand AS hand, handdata_players AS players, handdata_forced AS forced

WHERE players.hand_id = hand.id
AND forced.hand_id = hand.id
GROUP BY hand.id
HAVING (
(
players.player_stack /
SUM( forced.amount )
)
BETWEEN 0
AND 5
)

Dock så måste jag sätta den snutten i sitt sammanhang för att kunna testa om resultatet är korrekt...och det är det inte.
Följande är hela frågan som den ser ut nu:

SELECT DISTINCT hand.id, SUM( forced.amount ) as amount, players.player_stack as stack
FROM handdata_hand AS hand, 
	 handdata_card AS card1, 
	 handdata_card AS card2, 
	 handdata_players AS players, 
	 handdata_forced AS forced, 
	 handdata_position AS position
WHERE card1.hand_id=hand.id
AND card2.hand_id=hand.id
AND players.hand_id=hand.id 
AND position.hand_id=hand.id 
AND forced.hand_id=hand.id
AND card1.player_id=players.player_id
AND card2.player_id=players.player_id
AND ((card1.value LIKE 'A_' AND card2.value LIKE 'Q_')
	AND (card1.type = 'showdown' OR card1.type = 'deal')
	AND (card2.type = 'showdown' OR card2.type = 'deal')) 
AND (position.seatcount BETWEEN 1 AND 10) 
AND (players.player_seat BETWEEN position.SB AND position.UTG)
GROUP BY hand.id
HAVING (
(
stack /
SUM( amount )
) BETWEEN 0 AND 5)

HAVING verkar fungera, men "amount" värdet är fel.

Kollar jag resultatet så jag ser "hand_id" samt "amount" för varje rad.
T.ex. har jag en rad med id 3914 och amount 900, men kör jag
"SELECT amount FROM handdata_forced WHERE hand_id = 3914"
så får jag två rader, en med 75.00 och en med 150.00.

Hur kan det komma sig att amount inte är 225 då?

BlixtsystemsMedlem sedan maj 2005704 inlägg
#5

Äsch...tydligen så går det inte att referera till ett tabellnamn med alias i en subquery om det faktiskt används som referens till en tabell, men om det refererar till ett värde i en tabell så går det bra.


(SELECT SUM(amount) FROM forced WHERE hand_id = hand.id )
ger "Table 'handdata.forced' doesn't exist"

Men
(SELECT SUM(handdata_forced.amount) FROM handdata_forced WHERE hand_id=hand.id)
klagar inte på referensen till "hand.id" och fungerar!??

Speciellt snabbt verkar det inte bli och HAVING verkar snabbare men jag lyckas inte få korrekta resultat med den metoden :(

aasahMedlem sedan mars 20034 471 inlägg
#6

Blixtsystems skrev:

Kollar jag resultatet så jag ser "hand_id" samt "amount" för varje rad.
T.ex. har jag en rad med id 3914 och amount 900, men kör jag
"SELECT amount FROM handdata_forced WHERE hand_id = 3914"
så får jag två rader, en med 75.00 och en med 150.00.

Hur kan det komma sig att amount inte är 225 då?

Min gissning är att det är någon vajsing/alternativt korrekt sidoresultat av att du joinar ihop så mycket. Dvs om

SELECT amount FROM handdata_forced WHERE hand_id = 3914

ger två rader enligt ovan, så ger

SELECT hand_id, sum(amount) FROM handdata_forced GROUP BY hand_id HAVING sum(amount) > 0

bl. a. raden 3914, 225.

Jag tror att ett problem med din HAVING är att du tar ut stack (i SELECT) vilken inte är beräknad och inte står i GROUP BY. En annan kan vara att du skriver aliaset stack istället för players.player_stack i HAVING. Dock bör du kolla hur resultatet egentligen ser ut om du inte gör uträkningen och jämföra det med beräknat värde, snarare än att jämföra med hur det ser ut utan de i frågan ingående joinerna. Du kanske får en massa dubblettrader till följd av konstiga join-villkor?

Det går inte att avgöra om joinen är rätt gjord när man inte vet vad du vill åstadkomma och hur tabellerna ser ut.


(SELECT SUM(amount) FROM forced WHERE hand_id = hand.id )
ger "Table 'handdata.forced' doesn't exist"

Men
(SELECT SUM(handdata_forced.amount) FROM handdata_forced WHERE hand_id=hand.id)
klagar inte på referensen till "hand.id" och fungerar!??

Skälet till att den översta inte funkar är att det inte finns någon tabell som heter forced (i databasen). Varje gång du använder ett FROM så hämtar du ut "nya" tabeller.

Alltså, du kan skriva:

SELECT * FROM A WHERE b in (SELECT c FROM A)

om A är en tabell i databasen. Men de två A:na blir (i någon mening) två olika kopior av A. När radläsaren är på rad 10 i första A kan en annan radläsare vara på rad 212 i den senare. Om du däremot försöker skriva:

SELECT * FROM A AS B WHERE b in (SELECT c FROM B)

så försöker du titta på samma kopia av A (den kopia som heter B) på två oberoende ställen och det går inte. Varje rad i den yttre frågan ska jämföras med resultatet av att vi rasslat igenom alla rader i den inre och fått ut ett visst resultat. Det förutsätter att de två radläsarna i de två uttrycken kan röra sig oberoende av varann, och alltså behöver du två olika kopior av tabellen A (med varsin radläsare).

BlixtsystemsMedlem sedan maj 2005704 inlägg
#7

Tack för din förklaring....jag förstår väl lite bättre nu även om jag är lite förvirrad om hur själva flödet i frågan ser ut.
Resultat jag får från amount är alltid en multipel av den korrekta summan..ibland korrekt, ibland dubbla och ibland fyrdubbla.
Jag har testat en mängd olika grupperings varianter och köra tex. players.player_stack istället för med alias, men lyckas inte få fram pålitliga resultat.

Dock så har jag lyckats lösa problemet tillfredsställande genom att köra min subquery
under FROM istället, vilket snabbade upp frågan avsevärt:

SELECT DISTINCT hand.id as handid
FROM handdata_hand AS hand, 
	 handdata_card AS card1, 
	 handdata_card AS card2, 
	 handdata_players AS players, 
	 handdata_forced AS forced, 
	 handdata_position AS position,
	(SELECT SUM(amount) AS sum, hand_id FROM handdata_forced GROUP BY hand_id) AS amount
WHERE card1.hand_id=hand.id
AND card2.hand_id=hand.id
AND players.hand_id=hand.id 
AND position.hand_id=hand.id 
AND forced.hand_id=hand.id
AND card1.player_id=players.player_id
AND card2.player_id=players.player_id
AND card1.player_id=card2.player_id
AND amount.hand_id=hand.id
AND ((card1.value LIKE 'A_' AND card2.value LIKE 'K_')
	AND (card1.type = 'showdown' OR card1.type = 'deal')
	AND (card2.type = 'showdown' OR card2.type = 'deal')) 
AND (position.seatcount BETWEEN 1 AND 10) 
AND (players.player_seat BETWEEN position.SB AND position.UTG)
AND (
players.player_stack /
amount.sum
) BETWEEN 10 AND 11
133 ms totalt · 3 externa anrop · v20260731065814-full.1211964f
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
130 ms — hämta tråd, inlägg och bilagor (db)