Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MySQL] Złączenia tabel
Forum PHP.pl > Forum > Przedszkole
Gepetto
Są sobie trzy tabele

sprz_pa - tabela ze sprzedażą.

potrzebuję zebrać wartość sprzedaży z tej tabeli co robię tak:

  1. SELECT SUM(sprz_pa.WART) AS SumWart FROM sprz_pa

Działa.

Ponieważ chce wiedzieć co to za towar nazwa itd, a w tabeli sprz_pa mam tylko uniklany symbol towaru, dodaję do zapytania drugą tabelę.

dbf_MT - która zawiera większość danych o towarze

  1. SELECT SUM(sprz_pa.WART) AS SumWart FROM sprz_pa INNER JOIN dbf_MT ON sprz_pa.SYM = dbf_MT.SYM


działa.

Ponieważ chcę też wiedzieć jaka jest cecha danego towaru dołączam kolejną tabelę

symbolcecha - która zawiera symbol towaru zgodny z symbolem z tabel dbf_MT i sprz_pa oraz nr ID danej cechy.
I tutaj zaczynają się schody. Kolejny LEFT JOIN, zmienia wynik sumy sprzedaży.

  1. SELECT SUM(sprz_pa.WART) AS SumWart FROM sprz_pa
  2. LEFT JOIN dbf_MT ON sprz_pa.SYM = dbf_MT.SYM
  3. LEFT JOIN symbolcecha ON sprz_pa.SYM = symbolcecha.SYM


Pomimo, że jeszcze nie wybrałem ( WHERE ) danej cechy. Czy robię coś źle ?

Dla czytelności zapytania pominąłem nazwy poszczególnych kolumn w SELECT ograniczając się tylko do SUM(sprz_pa.WART)

aniolekx
Chyba nie do końca sam rozumiesz jakie wyniki osiągasz.

Sprawdź dwa pojęcia:
- GROUP BY
- DISTINCT

albo obliczasz sumę całkowitej sprzedaży (dla wszystkich produktów, wiec nie sprawdzisz jaki to produkt), albo dla poszczególnych produktów (wtedy np GROUP BY produkt_id).

Aby znaleźć odpowiedz na pytanie trzecie proponuje ci usunąć SUM(), daj porostu gwiazdkę z zapytania i sprawdzić ile rekordów generuje każde zapytanie i dlaczego tak się dzieje?
Analizuj wyniki jakie otrzymujesz, to nie jest czarna magia.
Gepetto
Dzięki za podpowiedzi.
Sprawdzanie sumy i listowanie odbywa się za pomocą dwóch zapytań, ale oba mają identyczne WHERE dlatego FROM wygląda jak wygląda.
Z DISTINCT i GROUB BY troche kombinowałem, ale bez efektu... może przez późną godzinę. Chociaż prawdopodobniejsza jest moja niewiedza wink.gif

Może od początku jak wygląda cały główny kod.

Na samym początku znajdują się filtry w postaci


  1. if (isset($_REQUEST["fldCechaTw"]) && is_numeric($_REQUEST["fldCechaTw"]) && $_REQUEST["fldCechaTw"] > 0)
  2. {
  3. $arrFiltr["CechaTw"] = $_REQUEST["fldCechaTw"];
  4. $arrFiltr["All"] .= "&fldCechaTw=".$arrFiltr["CechaTw"];
  5. }
  6. else
  7. $arrFiltr["CechaTw"] = 0;



Następnie na podstawie powyższych filtrów ustawiam klauzulę WHERE


  1. # Konstrukcja klauzuli WHERE na podstawie filtra
  2. $arrNazwa = explode(" ",$arrFiltr["Nazwa"]);
  3. $strWhere = "";
  4. if (strlen($arrFiltr["Nazwa"])) foreach($arrNazwa as $Nazwas) { $strWhere .= "MATCH (NAZWA) AGAINST ('+".StringToMySQL($Nazwas)."*' IN BOOLEAN MODE) AND "; }
  5. if (isset($_REQUEST["fldFiltrDataOd"]))
  6. {
  7. if (strlen($arrFiltr["DataOd"])) $strWhere .= "(DAD >= '".$arrFiltr["DataOd"]."') AND ";
  8. if (strlen($arrFiltr["DataDo"])) $strWhere .= "(DAD <= '".$arrFiltr["DataDo"]."') AND ";
  9. }
  10. if (strlen($arrFiltr["GrupaTw"])) $strWhere .= "sprz_pa.GR = '".$arrFiltr["GrupaTw"]."' AND ";
  11. if ($arrFiltr["CechaTw"] > 0) $strWhere .= "(symbolcecha.cecha_id = ".$arrFiltr["CechaTw"].") AND ";
  12. if ($arrFiltr["noGroup"] == 'DEFA') $strWhere .= "sprz_pa.GR != 'DEFA' AND ";
  13.  
  14. if (isset($_REQUEST["fldFiltrStanOd"]) OR isset($_REQUEST["fldFiltrStanDo"]) )
  15. {
  16. if (strlen($arrFiltr["StanOd"])) $strWhere .= "(STAK >= ".$arrFiltr["StanOd"].") AND ";
  17. if (strlen($arrFiltr["StanDo"])) $strWhere .= "(STAK <= ".$arrFiltr["StanDo"].") AND ";
  18. }
  19.  
  20.  
  21. if (strlen($strWhere)) $strWhere = substr($strWhere, 0, strlen($strWhere) - 5);



kolejną częścią jest właśnie zapytanie o SUM(sprz_pa.WART), które obecnie wygląda tak

  1. $strSql = "SELECT DISTINCT SUM(sprz_pa.WART) AS SumWart FROM sprz_pa LEFT JOIN dbf_MT ON sprz_pa.SYM = dbf_MT.SYM
  2. LEFT JOIN symbolcecha ON sprz_pa.SYM = symbolcecha.SYM ";
  3.  
  4.  
  5. if (strlen($strWhere)) {$strSql .= "WHERE ".$strWhere." AND sprz_pa.TYPD = 'P01' ";}
  6. else { $strSql .= "WHERE (DAD = '".$wczoraj."') AND sprz_pa.TYPD = 'P01' ";}
  7.  
  8. $objRstAll = mysql_query($strSql, $conn);
  9. $arrRowAll = mysql_fetch_assoc($objRstAll);
  10. $intWartTotal = $arrRowAll["SumWart"];
  11.  
  12. //echo $intWartTotal;
  13. echo $strSql;


Pełne zapytanie dla powyższego wygląda tak:

[codel]SELECT DISTINCT SUM(sprz_pa.WART) AS SumWart FROM sprz_pa
LEFT JOIN dbf_MT ON sprz_pa.SYM = dbf_MT.SYM
LEFT JOIN symbolcecha ON sprz_pa.SYM = symbolcecha.SYM
WHERE (DAD >= '20131002') AND (DAD <= '20131002')
AND sprz_pa.TYPD = 'P01'[/code]

i nie działa poprawnie. Po odjęciu LEFT JOIN symbolcecha ON sprz_pa.SYM = symbolcecha.SYM zwraca poprawną wartość.


kiedy wybieram filtr z cechą zapytanie wygląda tak:

[codel]SELECT DISTINCT SUM(sprz_pa.WART) AS SumWart FROM sprz_pa
LEFT JOIN dbf_MT ON sprz_pa.SYM = dbf_MT.SYM
LEFT JOIN symbolcecha ON sprz_pa.SYM = symbolcecha.SYM
WHERE (DAD >= '20131002') AND (DAD <= '20131002')
AND (symbolcecha.cecha_id = 1)
AND sprz_pa.TYPD = 'P01'[/code]

i wydaje mi się, że zwraca poprawną wartość - ciężko mi to sprawdzić w tym momencie.



Następnie listuję te pozycje za pomocą kolejnego zapytania, które obecnie wygląda tak:

  1. $strSql = "SELECT dbf_MT.EAN, dbf_MT.STAK, dbf_MT.NAZWA, dbf_MT.CEDET, sprz_pa.SYM, SUM(sprz_pa.ILOSC) AS ILOSC, SUM(sprz_pa.WART) AS WART, sprz_pa.DAD, sprz_pa.TYPD, sprz_pa.GR
  2. FROM sprz_pa INNER JOIN symbolcecha ON sprz_pa.SYM = symbolcecha.SYM
  3. INNER JOIN dbf_MT ON sprz_pa.SYM = dbf_MT.SYM ";
  4.  
  5.  
  6. if (strlen($strWhere)) {$strSql .= "WHERE ".$strWhere." AND sprz_pa.TYPD = 'P01' ";}
  7. else { $strSql .= "WHERE (DAD = '".$wczoraj."') AND sprz_pa.TYPD = 'P01' ";}
  8. $strSql .= "GROUP BY sprz_pa.SYM ";
  9. $strSql .= "ORDER BY ".$arrSortCols[$intParamSortCol]." ".$arrSortDirs[$intParamSortDir]." ";
  10.  
  11.  


i zakładając, że pierwsze zapytanie działa błędnie to i to nie będzie poprawne.
Jeszcze się nim nie zajmowałem stąd różnice.

Z ważnych informacji.
Tabela
  1. symbolcecha


id | SYM | cecha_id

jest tabelą wiele do wielu zatem symbole towaru się powielają ( oczywiście w takiej sytuacji z innym cecha_id )
warto wspomnieć że nie zawiera też wszystkich symboli z tabeli sprz_pa czy tabeli dbf_MT zawierającej wszystkie możliwe symbole
(jest w trakcie uzupełniania więc docelowo będą wszystkie)

Na razie tyle, muszę iść do pracy.
Może coś mi wpadnie do głowy do wieczora.
Dzięki.



mmmmmmm
  1. SELECT DISTINCT SUM(sprz_pa.WART) AS SumWart FROM sprz_pa
  2. LEFT JOIN dbf_MT ON sprz_pa.SYM = dbf_MT.SYM
  3. LEFT JOIN symbolcecha ON sprz_pa.SYM = symbolcecha.SYM
  4. WHERE (DAD >= '20131002') AND (DAD <= '20131002')
  5. AND sprz_pa.TYPD = 'P01'

gospodin, pamiłuj, kto to pisał...
DISTINCT + SUM questionmark.gif? co to za głupota?
Sumujesz z tabeli głównej (do niej wiążesz resztę), więc po co ci LEFT JOINy? Zwykłe JOINy wystarczą.
Zresztą nie wiem, po co w ogóle te dodatkowe tabele ciągniesz, skoro sumujesz tylko z głównej... Wytłumaczeniem mogły by być warunki na nich, ale chyba tak nie jest - jeden warunek jest na główną, drugi (ten z DAD) nie wiadomo na co. A tabele są 3, więc przynajmniej jedna niepotrzebna.
Gepetto
gospodin, pamiłuj, kto to pisał...
DISTINCT + SUM questionmark.gif? co to za głupota?
Sumujesz z tabeli głównej (do niej wiążesz resztę), więc po co ci LEFT JOINy? Zwykłe JOINy wystarczą.
Zresztą nie wiem, po co w ogóle te dodatkowe tabele ciągniesz, skoro sumujesz tylko z głównej... Wytłumaczeniem mogły by być warunki na nich, ale chyba tak nie jest - jeden warunek jest na główną, drugi (ten z DAD) nie wiadomo na co. A tabele są 3, więc przynajmniej jedna niepotrzebna.


Tabela główna bazy, to dbf_MT która zawiera takie kolumny jak
SYMBOL | NAZWA | CENA | STAN | GRUPA | VAT itd itp -- NIE ZAWIERA CECHY, która jest elementem filtru

Tabela dodatkowa to tabela ze sprzedażą sprz_pa, która zawiera
SYMBOL | GRUPA | NR DOKUMENTU | DAD ( DATA SPRZEDAŻY ) | CENA ( SPRZEDAŻY ) | ILOŚĆ (sprzedanych tutułów) | WARTOŚĆ |


Trzecia tabela to tabela zawierająca
ID | SYMBOL | CECHA_ID

i - twoja racja - o ile do sprawdzenia wartości nie potrzebuję tabeli dbf_MT ( co chyba rozwiązuje problem pierwszego zapytania )
o tyle tabeli symbolcecha już tak, gdyż są kiedy wybiorę jako warunek CHECHĘ TOWARU ( CECHA_ID ) to w przypadku jej braku ( tabeli ) nie będe się miał do czego odwołać.

Pozostaje zatem kwestia drugiego zapytania, które listuje sprzedaż i korzysta z wszystkich trzech tabel.
DISTINCT SUM() powstało metodą prób i błędów i nie twierdze ze jest poprawne i ostateczne wink.gif

Sprawdzę nowe pomysły po pracy wink.gif






-Gepetto-
ŹLE.
USUNIĘCIE tabeli dbf_MT nie rozwiązuje problemu, gdyż WARUNEK też korzysta z tej tabeli w przypadku filtru

NAZWA
  1. if (strlen($arrFiltr["Nazwa"])) foreach($arrNazwa as $Nazwas) { $strWhere .= "MATCH (NAZWA) AGAINST ('+".StringToMySQL($Nazwas)."*' IN BOOLEAN MODE) AND "; }


oraz STAN
  1. if (isset($_REQUEST["fldFiltrStanOd"]) OR isset($_REQUEST["fldFiltrStanDo"]) )
  2. {
  3. if (strlen($arrFiltr["StanOd"])) $strWhere .= "(STAK >= ".$arrFiltr["StanOd"].") AND ";
  4. if (strlen($arrFiltr["StanDo"])) $strWhere .= "(STAK <= ".$arrFiltr["StanDo"].") AND ";
  5. }


te dane istnieją tylko w dbf_MT zatem muszę mieć trzy tabele.


Gepetto
ok, doszedłem do wniosku, że zapytanie w postaci
  1. SELECT * FROM sprz_pa LEFT JOIN dbf_MT ON sprz_pa.SYM = dbf_MT.SYM WHERE (DAD = '20131002') AND sprz_pa.TYPD = 'P01'

nie wprowadza żadnego zamieszania i tabele łączą się tak jak tego chcę.

natomiast w przypadku
  1. SELECT * FROM sprz_pa LEFT JOIN symbolcecha ON sprz_pa.SYM = symbolcecha.SYM WHERE (DAD = '20131002') AND sprz_pa.TYPD = 'P01'

pojawiają się dodatkowe rekordy które chciałbym pominąć.

tabela symbolcecha zawiera kilka tych samych symboli z inną cechą

ID | SYM | CECHA_ID

1 | 11111 | 1
2 | 11111 | 2
3 | 22222 | 1
4 | 22222 | 2
...

jeśli dobrze rozumiem z tego powodu po złączeniu tabel sprz_pa i symbolcecha
otrzymuję tabelę powiększoną o te zduplikowane symbole z tabeli symbolcecha tak ?

zatem pytanie brzmi jak wybrać z tabeli symbolcecha złączony? symbol.. da się tak?

chyba że rozwiązałbym to za pomocą warunku:
Kod
IF ( filtr korzysta z tabeli SYMBOLCECHA ) { dołącz do zapoytania LEFT JOIN SYMBOLCECHA.. itd }

wtedy z tabeli symbolcecha zostałyby wybrane tylko pozycje o danym cecha_id




To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.