Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: zapytanie
Forum PHP.pl > Forum > Bazy danych
kirkor0
mam dwie tebele polaczone ze soba polem pole_id. Chce pobrac dane z tabeli_1, ale tylko te wiersze o polu_id, korego wartosc nie znajduje sie w tabeli_2.

Czyli jezeli mamy pole_id o wartosci 2 w obu tabelach, to aby nie zwracal mi tego pola. Natomiast jezeli wartosc pola_id znajduje sie tylko w tabeli_1, aby pobral ta wartosc.
kszychu
  1. SELECT tabela_1.*
  2. FROM tabela_1, tabela_2 WHERE tabela_1.pole_id = tabela_2.pole_id


Tak ciężko zajrzeć do manuala i poczytać o złączeniach? Radzę to zrobić, bo to które pokazałem, jest akurat najprostrzym ze złączeń, a bez nich ani rusz.
adasoft
  1. SELECT t1.nazwa, t1.DATA
  2. FROM tabela_1 AS t1
  3. JOIN tabela_2 AS t2 ON t1.pole_id=t2.pole_id
  4. WHERE t1.pole_id<>t2.pole_id


Oczy 'nazwa' i 'data' to są pola przykładowe pobierane z tabeli_1 biggrin.gif
kirkor0
a po co uzywac tutaj aliasow? koniecznie?
nazwy tabel sa krotkie
nospor
aliasy nie są tu niezbedne, ale są krotrze nawet o tych twoich "krótkich" tabel.
Jabol
  1. SELECT tabela_1.*
  2. FROM tabela_1, tabela_2 EXCEPT SELECT tabela_1.*
  3. FROM tabela_1, tabela_2 WHERE tabela_1.pole = tabela_2.pole;
FiDO
Ja bym zrobil tak:

  1. SELECT t1.*
  2. FROM tabela_1 t1
  3. LEFT JOIN tabela_2 t2 USING(pole_id)
  4. WHERE t2.pole_id IS NULL
Jabol
  1. SELECT *
  2. FROM table_1 WHERE pole_id NOT IN (SELECT pole_id
  3. FROM table_2);
Hehe, ależ ten sql wypasiony winksmiley.jpg.
FiDO
Sposobow jest wiele, to fakt.. ale trzeba sie tez liczyc z optymalizacja zapytan.
Ostatnio robilem dosc skomplikowane zapytanie, najpierw za pomoca subquery, ale bylo nieludzko powolne (kilka zapytan prawie takich samych wykonywalo sie kilka sekund) mimo indexow na wszystkich polach, na ktorych byly jakies warunki.
Potem udalo mi sie po dlugich bojach zmienic to na joina (zostalo tylko jedno proste subquery) i czas wykonania spadl ok dziesieciokrotnie.
Jabol
@FiDo: Zaciekawiło mnie jeszcze jakby zrobić takie zapytanie, gdyby pola nie nazywały się tak samo (nie używając USING). Bo jeżeli użyjesz ON to przecież nie będzie złączeń z NULL. Czy może LEFT JOIN ... ON .. zwraca pola nawet te, które nie mają swoich odpowiedników?
kirkor0
Spoko, juz sobie poradzilem, juz popbralem, ale teraz trzeba mi je usunac.
Te wyniki ktore dostalem (zarowno z jednej jak i z drugiej tabeli) chce usunac.

Moze cos w stylu
  1. DELETE
  2. FROM tabela_1, tabela_2 WHERE pole_id IN(SELECT....)

to select to by bylo to co wyzej

a moze inaczej?
FiDO
@Jabol: jesli jest LEFT JOIN to juz niewazne jak zapisujesz zlaczenie.. i tak zwraca wszystkie rekordy z tabeli z lewej strony zlaczenia. USING w tym przypadku tylko skraca zapis.

@kirkor0: moze byc tak.
kirkor0
Ten kod, który podałem nie działa - spodziewałem się tego. To był tylko punkt mojego widzenia.

Co jest źle, a może inaczej?
FiDO
Podaj cale zapytanie jakie wykonales i najlepiej od razu komunikat bledu.
kirkor0
Moje zapytanie jest duzo bardziej rozbudowane. Musze uzyc 3 tabel.
  1. DELETE
  2. FROM table_1, table_2, table_3 WHERE id_poleIN (SELECT table_1.id_pole
  3. FROM table_1 LEFT JOIN table_3 USING(id_pole) LEFT JOIN table_2 USING(id_pole) WHERE (NOW() > DATE_ADD(table_1.pole_1, INTERVAL 1 day) OR NOW() > DATE_ADD(table_2.pole_2, INTERVAL 1 day)) AND (table_1.id_pole=table_2.id_pole OR table_2.id_poleIS NULL) AND table_3.id_pole IS NULL)


I Nr błędu: 1064. Treść błędu: "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE id_pole IN (SELECT table_1.id_pole FROM table_1 LEFT JOIN ta".
FiDO
Jesli chcesz z kazdej tabeli usunac wiersze, ktore nie maja swoich odpowiednikow w pozostalych tabelach to obawiam, ze za jednym zamachem sie tego nie da zrobic tak jak probujesz. Sprobuj to rozbic na osobne zapytania usuwajace z kazdej tabeli.
kirkor0
wszystkie pola sa polaczone polem pole_id.
ale mniejsza z tym, bo teraz bylby problem, bo jakbym usunal z jednej tabeli, to SELECT juz nie zwrocilby tych samych rekordow.
Wiec moze usunalbym z tabela_1, a potem usunal z innych tabeli te, które nie maja swojego odpowiednika w tabela_1. Tylko jak to zrobic?
SongoQ
@FiDO
Cytat
Potem udalo mi sie po dlugich bojach zmienic to na joina (zostalo tylko jedno proste subquery) i czas wykonania spadl ok dziesieciokrotnie.


Oczywiscie left join jest szybszy od podzapytan typu in ale nalezy uwazac na pewne rzeczy.
1 to wystrzegac sie zeby bylo jak najminejsza liczba zlaczen. Teoretycznie max powinno byc 5, kolejna rzeczy podzapytanie z IN sa strasznie wolne, gdzie IN zwraca wiele rekordow. Wiec trudno nieraz dopasowac zeby bylo ok. Ja mniej wiecej robie to w ten sposob ze laduje miliony rekordow w tabele i na zasadzie prob i bledow sprawdzam wszystkie warianty ale trzeba sie liczyc z czasem.
kirkor0
Nikt nie wie jak?
Mam dwie tabele połączone polem pole_id. Chodzi mi o usunięcie rekordów z jednej tabeli, tych które nie mają swojego odpowiednika w drugiej tabeli.

Inaczej mowiac jeżeli w tabeli_2 znajduje sie rekord o polu_id np. 4 i nie istnieje rekord o polu pole_id w tabeli_2, to niech zostanie usunięty.
Jabol
Ja bym to zrobił poprzez
  1. DELETE
  2. FROM tabela_1 USING tabela_2 WHERE tabela_1.pole_id = tabela_2.pole_id;
Ale USING jest rozszeżeniem SQL'a dodawanym w postgresie. Nie wiem, jak jest w innych bazach. Musisz poszukać analogicznego sposobu albo zrobić rzeczywiście z subquery.
kirkor0
Nie zrozumiales mnie.
- Jezeli w obu tabelach sa rekordy z polem_id o takiej samej wartosci, to nie chce nic usuwac.
- Jezeli w tabeli_1 jest rekord o danym id, a w tabeli_2 nie ma tego id, to nie chce nic usuwac
- Jezeli w tabeli_1 nie ma pola_id, a dane id znajduje sie w tabeli_2, to chce ten rekord usunac

Inaczej mowiac usun rekordy z tabeli_2, ktore nie maja swojego odpowiednika w tabeli_1.

===

Jeszcze inaczej. Mam tabele userzy i tabele posty. Chcialem usunac uzytkownika z tabeli userzy i tabeli posty. Niestety nie wiem jak to zrobic w jednym zapytaniu. Wiec najpierw usuwam dane o uzytkowniku z tabeli userzy, a potem z tabeli posty.
Czyli chce usunac te posty, kore sa bezpanskie - nie maja swojego uzytkownika.

OT. Oczywiscie, ze wolalbym za jednym razem usunac wszystkie dane o uzytkowniku za jednym zamachem - tak byloby najlepiej, ale nie wiedzieliscie jak.
Synaps
Wyglada mi na to ,że kolega zapomniał o więzach integralności i baza mu się rozspójniła cool.gif Nauczka na przyszłość...dobry projekt.

  1. DELETE
  2. FROM tabela_1 WHERE NOT EXISTS ( SELECT 'X'
  3. FROM tabela_2 WHERE tabela_2.id = tabela_1.id )


To powinno rozwiązać Twój problem.
kirkor0
Dzieki o to mi chodzilo.

Zadna baza mi sie nie rozspujnila.

Chodzi mi o usuniecie nieaktywnych uzytkownikow - ktorzy np nie logowali sie przez ostatni miesiac. Dane o uzytkownikach sa przechowywane w kilku tabelach, a te tabele sa polaczone jednym polem id.

Nadal nie wiem jak usunac ich za jednym zapytaniem, wiec wpadlem na pomysl aby usunac dane z tabeli users, a potem usunac dane z innych tabel, ktore nie maja swoich odpowiednik w tabeli users.

Ale jak ktoś zna sposób na zrobienie tego w jednym zapytaniu, to niech się pochwali! biggrin.gif
SongoQ
Mozesz np po przez relacje caskadowa.
kirkor0
... może jaśniej?
nospor
moze poczytaj se cos o relacjach i o kaskadowym usuwaniu.
Tabele maja byc typu innodb, zakladasz klucz obcy w jednej tabeli i okreslasz jak ma sie zachowywyac w przypadku kasowania glownego rekordu.

tutaj tez cos bylo
http://forum.php.pl/index.php?showtopic=7816
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.