Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Dwie sumy, dwóch tabel w jednym zapytaniu, Co robię źle?
dawnthief
post
Post #1





Grupa: Zarejestrowani
Postów: 6
Pomógł: 0
Dołączył: 6.10.2014

Ostrzeżenie: (0%)
-----


Witajcie, jestem tu nowy i mam pewien problem.
Dane są dwie tabele o tej samej strukturze:

fm_expenses i fm_income
w expenses przechowywane są dane o wydatkach a w income o dochodach

ID int(11)
SUMA float(10,2)
DATA timestamp
CATEGORY int(3)
USERID int(11)


Chcę zliczyć sumę fm_income jako dochody a fm_expenses jako wydatki
robię to tak:
  1. SELECT SUM(fm_expenses.SUMA) AS wydatki, SUM(fm_income.SUMA) AS dochody FROM fm_expenses LEFT JOIN fm_income ON fm_expenses.USERID = fm_income.USERID WHERE fm_expenses.USERID=1 AND fm_income.USERID=1

i wychodzą bzdury. Kosmiczne cyfry, zdaję sobie sprawę że skaszaniona relacja tu jest, ale za to zwraca to wszystko w ładnym formacie (dwa pola, wydatki i dochody).
Wykombinowałem jescze jeden sposób:
  1. SELECT SUM(SUMA) AS dochody FROM fm_income WHERE USERID=1 UNION SELECT SUM(SUMA) AS wydatki FROM fm_expenses WHERE USERID=1

Zwraca prawidłowe liczby ale wszystko w polu dochody i jako dwa rekordy.

Jak to ugryźć?
Go to the top of the page
+Quote Post
mmmmmmm
post
Post #2





Grupa: Zarejestrowani
Postów: 1 421
Pomógł: 310
Dołączył: 18.04.2012

Ostrzeżenie: (0%)
-----


Tak to jest jak te dane się trzyma w dwóch różnych tabelach... Bez sensu.
  1. SELECT w.USERID, dochody, wydatki FROM (SELECT USERID, Sum(SUMA) AS wydatki FROM fm_expenses GROUP BY USERID) w LEFT JOIN (SELECT USERID, Sum(SUMA) AS dochody FROM fm_income GROUP BY USERID) d ON d.USERID=w.USERID WHERE w.USERID=1
Go to the top of the page
+Quote Post
trueblue
post
Post #3





Grupa: Zarejestrowani
Postów: 6 806
Pomógł: 1828
Dołączył: 11.03.2014

Ostrzeżenie: (0%)
-----


mmmmmmm,
Twoje pytanie zwróci błędny wynik jeśli użytkownik będzie dochód bez wydatku.


  1. SELECT userid,SUM(suma*(1-ABS(SIGN(typ-1)))) AS wydatek,SUM(suma*(1-ABS(SIGN(typ-2)))) AS dochod FROM
  2. (SELECT w.USERID, w.SUMA, 1 AS typ FROM fm_expenses AS w LEFT JOIN fm_income ON fm_income.USERID=w.USERID
  3. UNION ALL
  4. SELECT d.USERID,d.SUMA,2 AS typ FROM fm_income AS d LEFT JOIN fm_expenses ON fm_expenses.USERID=d.USERID
  5. ) AS tmp GROUP BY userid


Ten post edytował trueblue 6.10.2014, 17:01:52


--------------------
Go to the top of the page
+Quote Post
dawnthief
post
Post #4





Grupa: Zarejestrowani
Postów: 6
Pomógł: 0
Dołączył: 6.10.2014

Ostrzeżenie: (0%)
-----


Rozwiązanie które podał mmmmmmm podaje jak najbardziej prawidłowe wyniki, ma tylko jeden mankament, nie zwraca nic jeżeli dla danego usera (USERID) nie ma żadnego rekordu w wydatkach.
Rozwiązanie trueblue działa nawet jeśli nie ma rekordów w wydatkach lub dochodach ale niestety podaje nieprawidłowe sumy sad.gif


SQL wyrzucił mi takie sumy , pierwsze to rozwiązanie mmmmmmm, drugie to rozwiązanie trueblue
wydatek dochod
2600.47 3316.95
1814.06999796629 1996.94998836517
Go to the top of the page
+Quote Post
trueblue
post
Post #5





Grupa: Zarejestrowani
Postów: 6 806
Pomógł: 1828
Dołączył: 11.03.2014

Ostrzeżenie: (0%)
-----


Podałem zapytanie dla wszystkich userów.
Spróbuj tak:
  1. SELECT userid,SUM(suma*(1-ABS(SIGN(typ-1)))) AS wydatek,SUM(suma*(1-ABS(SIGN(typ-2)))) AS dochod FROM
  2. (SELECT w.USERID, w.SUMA, 1 AS typ FROM fm_expenses AS w LEFT JOIN fm_income ON fm_income.USERID=w.USERID WHERE w.userid=1
  3. UNION ALL
  4. SELECT d.USERID,d.SUMA,2 AS typ FROM fm_income AS d LEFT JOIN fm_expenses ON fm_expenses.USERID=d.USERID WHERE d.userid=1
  5. ) AS tmp


Ten post edytował trueblue 6.10.2014, 17:00:58


--------------------
Go to the top of the page
+Quote Post
dawnthief
post
Post #6





Grupa: Zarejestrowani
Postów: 6
Pomógł: 0
Dołączył: 6.10.2014

Ostrzeżenie: (0%)
-----


Wyrzuca błąd
  1. #1140 - Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause


a co robi te
  1. suma*(1-ABS(SIGN(typ-1)))

?


Właśnie sobie uświadomiłem jak mało wiem o SQLu...
Go to the top of the page
+Quote Post
trueblue
post
Post #7





Grupa: Zarejestrowani
Postów: 6 806
Pomógł: 1828
Dołączył: 11.03.2014

Ostrzeżenie: (0%)
-----


Dodaj na końcu całości GROUP BY userid.

  1. suma*(1-ABS(SIGN(typ-1)))

Umożliwia emulację tabeli przestawnej.


--------------------
Go to the top of the page
+Quote Post
dawnthief
post
Post #8





Grupa: Zarejestrowani
Postów: 6
Pomógł: 0
Dołączył: 6.10.2014

Ostrzeżenie: (0%)
-----


Tak teraz błędem nie rzuca, ale wciąż podaje niewłaściwe sumy.
Go to the top of the page
+Quote Post
trueblue
post
Post #9





Grupa: Zarejestrowani
Postów: 6 806
Pomógł: 1828
Dołączył: 11.03.2014

Ostrzeżenie: (0%)
-----


Na 100% jesteś pewien, że wynik nie jest poprawny?
Ja testuję na, co prawda, paru rekordach, ale jest ok.

EDIT: Powinno być UNION ALL, choć nie wiem czy to jest przyczyną wyniku, który uznajesz za błędny.

Ten post edytował trueblue 6.10.2014, 17:04:18


--------------------
Go to the top of the page
+Quote Post
dawnthief
post
Post #10





Grupa: Zarejestrowani
Postów: 6
Pomógł: 0
Dołączył: 6.10.2014

Ostrzeżenie: (0%)
-----


Teraz już kompletnie odwaliło
  1. SELECT userid,SUM(suma*(1-ABS(SIGN(typ-1)))) AS wydatek,SUM(suma*(1-ABS(SIGN(typ-2)))) AS dochod FROM
  2. (SELECT w.USERID, w.SUMA, 1 AS typ FROM fm_expenses AS w LEFT JOIN fm_income ON fm_income.USERID=w.USERID WHERE w.userid=2
  3. UNION ALL
  4. SELECT d.USERID,d.SUMA,2 AS typ FROM fm_income AS d LEFT JOIN fm_expenses ON fm_expenses.USERID=d.USERID WHERE d.userid=2
  5. ) AS tmp GROUP BY USERID


Wrzucam takie zapytanie (zmieniłem userid z 1 na 2 , bo chciałem sprawdzić na małej ilości danych)
mam w dochodach dwa rekordy SUMA=3.00 co powinno dawać 6
a w wydatkach jeden rekord SUMA=2.00 a drugi SUMA=2.50 co powinno dawać 4.50

Otrzymuję taki wynik:
wydatek: 9
dochod: 12
Go to the top of the page
+Quote Post
trueblue
post
Post #11





Grupa: Zarejestrowani
Postów: 6 806
Pomógł: 1828
Dołączył: 11.03.2014

Ostrzeżenie: (0%)
-----


Niepotrzebne te LEFT JOIN.

Dla USERID=1
  1. SELECT userid,SUM(suma*(1-ABS(SIGN(typ-1)))) AS wydatek,SUM(suma*(1-ABS(SIGN(typ-2)))) AS dochod FROM
  2. (SELECT USERID,SUMA, 1 AS typ FROM fm_expenses
  3. UNION ALL
  4. SELECT USERID,SUMA,2 AS typ FROM fm_income
  5. ) AS tmp WHERE userid=1 GROUP BY userid


--------------------
Go to the top of the page
+Quote Post
dawnthief
post
Post #12





Grupa: Zarejestrowani
Postów: 6
Pomógł: 0
Dołączył: 6.10.2014

Ostrzeżenie: (0%)
-----


Działa! wszystko cacy, punkcik powędrował.
Teraz jescze pare pytań żebym bezmyślnie nie kopiował i wklejał
  1. SELECT userid,SUM(suma*(1-ABS(SIGN(typ-1)))) AS wydatek,SUM(suma*(1-ABS(SIGN(typ-2)))) AS dochod FROM
  2. (SELECT USERID,SUMA, 1 AS typ FROM fm_expenses
  3. UNION ALL
  4. SELECT USERID,SUMA,2 AS typ FROM fm_income
  5. ) AS tmp WHERE userid=1 GROUP BY userid


- Skąd się bierze te 1 i 2 w tych Selectach po sumie ?
- SUM(suma*(1-ABS(SIGN(typ-1)))) - jak to dokładnie działa, po co i dlaczego?
Go to the top of the page
+Quote Post
trueblue
post
Post #13





Grupa: Zarejestrowani
Postów: 6 806
Pomógł: 1828
Dołączył: 11.03.2014

Ostrzeżenie: (0%)
-----


Wydatek ma typ=1, dochód=2.

Dla typ=1 jeśli rekord ma typ=1, będzie suma*1, inaczej suma*0, analogicznie dla typ=2.
Można to zastąpić taką konstrukcją:
  1. SUM(suma*(IF(typ=1,1,0))) AS wydatek,SUM(suma*(IF(typ=2,1,0)))

Krótko: wartość suma wpada do sumowania wydatku jeśli jest wydatkiem, jeśli nie jest, nie wpada. Analogicznie dla dochodu.


--------------------
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 20.08.2025 - 18:14