Wskazówka, przy tworzeniu zapytania SQL (Postgres)

0

Mam następującą strukturę bazy

daneOsobiste(id SERIAL, imie text, nazwisko text, telefon text, pesel text)
dataUrodzenia(id int4, data date)
adresZamieszkania(id int4, ulica text, numerDomu text, numerMieszkania text, kodPocztowy text, miasto text, wojewodztwo text, kraj text)
adresZameldowania(id int4, ulica text, numerDomu text, numerMieszkania text, kodPocztowy text, miasto text, wojewodztwo text, kraj text)
adresKorespondencji(id int4, ulica text, numerDomu text, numerMieszkania text, kodPocztowy text, miasto text, wojewodztwo text, kraj text)
umowa(id int4, dataOd date, dataDo date, stanowisko text, wynagrodzenie money, idFirmyOd int2, idFirmyU int2, adnotacja text)
orzeczenie(id int4, dataOd date, dataDo date, stopien int2, symbol text)
badanie(id int4, dataOd date, dataDo date)
urlop(id int4, dataOd date, dataDo date, firmaU int2, czasUrlopu int2)
daneDoWyplaty(id int4, nip text, numerKonta text, nazwaBanku text)
informacjeDodatkowe(id int4, adnotacja text)
firma(id SERIAL, nazwaFirmy text)
firmaU(id SERIAL, nazwaFirmy text)

Mam teraz pytanie (proszę jedynie o wskazówki i odwołanie do literatury za pomocą linku).

Chcę utworzyć zapytanie, w którym wybiorę: id, nazwaFirmy Od, nazwaFirmy U, imię, nazwisko, zatrudniony od, zatrudniony do, stopień niepeł., symbol niepeł, do kiedy orzeczenie, do kiedy badanie

Napisałem takie zapytanie. Nie wiem co źle napisałem, choć zdaję sobie sprawę, że mam małą wiedzę i brak umiejętności, jeżeli chodzi o tworzenie zapytań.

SELECT daneosobiste.id, od.nazwaFirmy, u.nazwaFirmy, daneosobiste.imie, daneosobiste.nazwisko, zatrudnionyod.dataOd, zatrudnionydo.dataDo, orzeczenie.stopien, orzeczenie.symbol, orz.dataDo, bad.dataDo 
FROM daneosobiste 
LEFT JOIN umowa AS od ON od.id = firma.id 
LEFT JOIN umowa AS u ON u.id = firma.id, 
umowa As zatrudnionyod, umowa AS zatrudnionydo, orzeczenie, orzeczenie AS orz, badanie AS bad 
WHERE zatrudnionyod.id = daneosobiste.id AND zatrudnionydo.id = daneosobiste.id AND orzeczenie.id = daneosobiste.id AND orz.id = daneosobiste.id AND bad.id = daneosobiste.id

Pytanie dotyczy PostgreSQL

Proszę o wskazówki, dzięki

PS.
Ok, napisałem zapytanie, ale zwraca mi dwa wyniki, dla każdego nazwiska, dlaczego?

SELECT daneosobiste.id, od.nazwaFirmy, u.nazwaFirmy, daneosobiste.imie, daneosobiste.nazwisko, zatrudnionyod.dataOd, zatrudnionydo.dataDo, orzeczenie.stopien, orzeczenie.symbol, orz.dataDo, bad.dataDo FROM daneosobiste, umowa LEFT JOIN firma AS od ON od.id = umowa.idFirmyOd LEFT JOIN firmaU AS u ON u.id = umowa.idFirmyU, umowa As zatrudnionyod, umowa AS zatrudnionydo, orzeczenie, orzeczenie AS orz, badanie AS bad WHERE zatrudnionyod.id = daneosobiste.id AND zatrudnionydo.id = daneosobiste.id AND orzeczenie.id = daneosobiste.id AND orz.id = daneosobiste.id AND bad.id = daneosobiste.id

title

1

masakra ...
Na wstępie jeśli już chcesz pomocy to wrzuć całego ddl tabel bo nie widać relacji jednoznacznie dopiero czytając zapytanie wywnioskowałem, że id w tabeli umowa jest fk do pola id w tabeli daneOsobiste
w zasadzie to jeszcze bardziej elegancko byłoby gdybyś tabele utworzył na http://sqlfiddle.com/
teraz co do samego zapytania ...
skoro łączysz 1 do 1 po ID z tabelą daneosobiste to po kiego tyle razy ta sama tabela w zapytaniu? Mówię tu o tabeli umowa czy też orzeczenie ...

Jeśli natomiast chodzi o sam wynik zapytania to łącząc daneosobowe z umową może okazać się, że w tabeli umowa są dwie umowy dla danego operatora stąd dwa rekordy.
Zdublowane rekordy możesz usunąć używając DISTINCT jednak uważam, że całe to zapytanie to jedna wielka masakra
wtf

0

Ale masz kiche...
Już ci raz mówiłem, byś na adresy zrobił jedną tabelę z polem "typ".
Naprawdę musisz mieć osobne tabele na: dataUrodzenia, daneDodatkowe daneDoWyplaty?
Co to "firma" i "firmaU" ? pewnie też da się wcisnąć do jednej tabeli...
I w tyn sposob zamiast 13 tabel dostajesz:
-dane
-firmy
-badania
-adresy
-umowy
-orzeczenia
-urlopy

0

Dzięki za odpowiedzi.

@Marcin.Miga Faktycznie, mógłbym połączyć dataUrodzenia i daneDodatkowe i daneDoWypłaty. Jednak firma i firmaU to już tak średnio, gdyż tam przechowuję firmy osób rekrutujących i firmy, u których te osoby faktycznie pracują. Ich id wykorzystywane są w rekordach z tabeli umowa. Nie mogę ich połączyć, gdyż zaczytuję do kontrolki wyboru nazwy firm z jednej tabeli do jednej kontrolki i z drugiej tabeli do drugiej kontrolki. Musiałbym wtedy dodać kolejne pole rozróżniające, czy ma być to firma rekrutująca, czy pracująca. To prawda, jest to koszmarnie napisane, ale nie wynika to ze złej woli tylko z braku wiedzy, umiejętności i ogólnego braku biegłości. To pierwsza aplikacja bazodanowa, jaką piszę, a bazy miałem na studiach 8-9 lat temu. Dzięki za uwagi.

@woolfik jak sugerowałbyś aby zapisać to zapytanie? (nie chodzi mi o gotowe rozwiązanie) Jak dodałem kolejną firmę do bazy i powiązałem ją z danym pracownikiem, to już "masakra" się zrobiła, i teraz, zamiast 3 rekordów mam chyba 12. Nie jestem bazodanowcem, a samych baz uczę się w praktyce dopiero teraz.

Dzięki

0

Wyszedłbym od umowy i do niej dołączał poszczególne tabele, z których chcesz wyciągnąć dane oraz użył distinct aby zniwelować te co się zdublowały

0

Przepraszam, wiem, że miałem zredukować tabele i napisać zapytania od nowa, ale jakoś nie czuję tego jeszcze. Ale mam pytanie:

Zmodyfikowałem zapytanie, pobierające wybrane, szczegółowe dane z tabel. Mam tylko jeden problem. Zapytanie pobiera globalnie najniższą datę rozpoczęcia pracy, dla danego pracownika. Ja chciałbym, aby pobierał datę najniższą, ale dla danego pracodawcy, a nie dla wszystkich umów danego pracownika. Mam takie coś:

SELECT DISTINCT daneosobiste.id, od.nazwaFirmy, u.nazwaFirmy, daneosobiste.imie, daneosobiste.nazwisko, MIN(zatrudnionyod.dataOd), MAX(zatrudnionydo.dataDo), orzeczenie.stopien, orzeczenie.symbol, MAX(orz.dataDo), MAX(bad.dataDo) 
FROM daneosobiste, umowa 
LEFT JOIN firma AS od 
	ON od.id = umowa.idFirmyOd 
LEFT JOIN firmaU AS u 
	ON u.id = umowa.idFirmyU, umowa AS zatrudnionyod, 
umowa AS zatrudnionydo, orzeczenie, orzeczenie AS orz, badanie AS bad 
WHERE zatrudnionyod.id = daneosobiste.id AND zatrudnionydo.id = daneosobiste.id AND umowa.id = daneosobiste.id AND orzeczenie.id = daneosobiste.id AND orz.id = daneosobiste.id AND bad.id = daneosobiste.id AND length(orzeczenie.symbol) = (SELECT MAX(length(orzeczenie.symbol)) FROM orzeczenie WHERE id = daneosobiste.id) 
GROUP BY daneosobiste.id, od.nazwaFirmy, u.nazwaFirmy, daneosobiste.imie, daneosobiste.nazwisko, orzeczenie.stopien, orzeczenie.symbol

To co jest dobre, to że nie ma zdublowanych wyników. Jedyny mankament rezultatu, to pobieranie MIN i MAX dat umów dla danego pracownika, bez uwzględnienia informacji o tych samych pracodawcach. Nie wiem czy dobrze to wytłumaczyłem.
title

Po prostu, jak umowa jest na tego samego pracodawcę i zleceniodawcę, to chciałbym, aby zapytanie wybierało datę MIN i MAX dla tych pracodawców, a nie dla wszystkich umów danego pracownika.

PS.

Oto wykaz umów, zapisanych temu pracownikowi:
title

0

Przerób zapytania po ludzku na JOINy, sformatuj i wklej.
A najlepiej to stwórz kopię danych na sqlfiddle i opisz problem - to ci pomogę w wolnej

1

@mpaw: trudno się czyta zapytanie w ktorym wiekszość warunku where to warunki złączeń, formatowanie też ma znaczenie, bazując na Twoim ostatnim zapytaniu i przedstawieniu go w takie formie:

SELECT DISTINCT 
	daneosobiste.id
	,od.nazwaFirmy
	,u.nazwaFirmy
	,daneosobiste.imie
	,daneosobiste.nazwisko
	,MIN(zatrudnionyod.dataOd)
	,MAX(zatrudnionydo.dataDo)
	,orzeczenie.stopien
	,orzeczenie.symbol
	,MAX(orz.dataDo)
	,MAX(bad.dataDo) 
FROM 
	daneosobiste
	LEFT JOIN umowa ON umowa.id = daneosobiste.id
	LEFT JOIN firma AS od ON od.id = umowa.idFirmyOd 
	LEFT JOIN firmaU AS u ON u.id = umowa.idFirmyU
	LEFT JOIN umowa AS zatrudnionyod ON zatrudnionyod.id = daneosobiste.id 
	LEFT JOIN umowa AS zatrudnionydo ON zatrudnionydo.id = daneosobiste.id
	LEFT JOIN orzeczenie ON orzeczenie.id = daneosobiste.id
	LEFT JOIN orzeczenie AS orz ON orz.id = daneosobiste.id
	LEFT JOIN badanie AS bad ON bad.id = daneosobiste.id
WHERE  
	LENGTH(orzeczenie.symbol) = (SELECT MAX(LENGTH(orzeczenie.symbol)) FROM orzeczenie WHERE id = daneosobiste.id) 
GROUP BY 
	daneosobiste.id
	,od.nazwaFirmy
	,u.nazwaFirmy
	,daneosobiste.imie
	,daneosobiste.nazwisko
	,orzeczenie.stopien
	,orzeczenie.symbol

jest dużo czytelniej i widzisz pierwsze logiczne błędy

  • @Marcin.Miga informował, że DISTINCT przy group by to WTF
  • 3 razy łączysz się z tabelą umowa
  • 2 razy łączysz się z tabelą orzeczenie

Czyli eliminując je upraszczasz samo zapytanie:

SELECT 
	daneosobiste.id
	,od.nazwaFirmy
	,u.nazwaFirmy
	,daneosobiste.imie
	,daneosobiste.nazwisko
	,MIN(umowa.dataOd)
	,MAX(umowa.dataDo)
	,orzeczenie.stopien
	,orzeczenie.symbol
	,MAX(orzeczenie.dataDo)
	,MAX(bad.dataDo) 
FROM 
	daneosobiste
	LEFT JOIN umowa ON umowa.id = daneosobiste.id
	LEFT JOIN firma AS od ON od.id = umowa.idFirmyOd 
	LEFT JOIN firmaU AS u ON u.id = umowa.idFirmyU
	LEFT JOIN orzeczenie ON orzeczenie.id = daneosobiste.id
	LEFT JOIN badanie AS bad ON bad.id = daneosobiste.id
WHERE  
	LENGTH(orzeczenie.symbol) = (SELECT MAX(LENGTH(orzeczenie.symbol)) FROM orzeczenie WHERE id = daneosobiste.id) 
GROUP BY 
	daneosobiste.id
	,od.nazwaFirmy
	,u.nazwaFirmy
	,daneosobiste.imie
	,daneosobiste.nazwisko
	,orzeczenie.stopien
	,orzeczenie.symbol

Pisząc zapytania w tak chaotyczny sposób gubisz kontekst i tworzysz niepotrzebne powiązania...

0

Bardzo dziękuję, działa!, ale dlaczego Twój kod, @Panczo pobiera MIN i MAX datę dla danego rodzaju umowy, skoro nie umieszczasz warunku, sprawdzającego jaka firma zatrudnia i u jakiej firmy dany pracownik pracuje?

1

@mpaw ja tylko skorygowałem Twoje zapytanie, nie zastanawiałem się nad poprawnością, jedyne "sprawdzenie" to warunek joina: umowa.id = daneosobiste.id

1 użytkowników online, w tym zalogowanych: 0, gości: 1