Oskar Oleszkiewicz

Oskar Oleszkiewicz Programista z pasją

Temat: Problem z wyświetleniem danych - duplikują się!

Witam,

Mam problem z zapytaniem do bazy danych. Otóż posiadam trzy tabele, które nie są ze sobą w żaden sposób powiązane ale potrzebuje stworzyć na ich bazie widok, poniżej zamieszczam bardzo skrócony opis problemu:

1. Mam tabelę "Date_Table" w której przechowuję Lata(Year_) oraz Miesiące(Month_) - tabela ta pełni swego rodzaju "słownik" lub szkielet pod całe zapytanie
2. Posiadam też tabele dla umów "Contract_Table", z której pobieram nr umowy (Contract_Id) oraz date podpisania umowy (rozbijam na rok oraz miesiąc), następnie łączę left joinem i porównuje daty z tabeli z kontraktem do tabeli z datami - > wyświetlam i jest OK, wyświetla mio liste wszystkich lat oraz miesięcy a w następnej kolumnie wyświetla numery umów :)

Problem pojawia się gdy w ten sam sposób dodaję następną (niepowiązaną żadnymi relacjami) tabelę w której przechowywane są informacje dotyczące przeznaczonego budżetu na dany miesiąc i rok (Budget_Table), kiedy wstawiam ta tabele do zapytania (left join) zapytanie wykonuję się lecz zwraca astronomiczna ilość wyników (ok 0,5 mln) gdzie przewiduje że powinien zwrócić max 100 tys, rekordy w kolumnach z umowami oraz budżetem dupikują sie po klika razy.

Nie wiem jak rozwiązać ten problem. Poniżej przedstawiam moje zapytanie



select
Year_, Month_, tmp_contract.Contract, tmp_budget.Budget
from Date_Table

left join
(
select
Year(Contract_Signature_Date) as Rok,
Month(Contract_Signature_Date) as Miesiac,
Contract_Id as Contract
from Contract_Table
where Type = '1'
)
tmp_contract
on
tmp_contract.Rok = Year_ and tmp_contract.Miesiac = Month_

left join
(
select
Year_ as Rok,
Month_ as Miesiac,
Budget_Id as Budget
from Budget_Table
where Year(Convert (date, sysdatetime())) <= Year_
)
tmp_budget
on
tmp_budget.Rok = Year_ and tmp_budget.Miesiac = Month_

order by Year_, Month_



Wyników zapytanie niestety nie mogę przedstawić ponieważ generuje prawie milion wierszy :D

Pozdrawiam
Oskar
Maciej T.

Maciej T.
====================
============

Temat: Problem z wyświetleniem danych - duplikują się!

to może mały przykład
załóżmy, że masz jedną tabelę, z dwoma atrybutami i 4 rekordami.
rok, miesiąc
2012 01
2012 01
2012 02
2012 02

z poniższego zapytania ile dostaniesz rekordów ?

SELECT tab1.rok, tab1.miesiąc
FROM tabela1 tab1
LEFT JOIN tabela1 tab2 ON tab1.rok=tab2.rok AND tab1.miesiac = tab2.miesiac
Grzegorz K.

Grzegorz K. Data & Analytics
Engineer

Temat: Problem z wyświetleniem danych - duplikują się!

Rok i miesiąc nie są unikalne w podzapytaniach.

NIe rozumiem, po co Ci tabela Data_Table skoro i tak nie agregujesz nic względem roku i miesiąca.

Można zrobić np. :

select
distinct
Year(c.Contract_Signature_Date) as Rok,
Month(c.Contract_Signature_Date) as Miesiac,
c.Contract_Id as Contract,
b.Budget_Id as Budget
from Contract_Table as c
left join Budget_Table as b
on (
Year(c.Contract_Signature_Date) = b.Year_
and Month(c.Contract_Signature_Date) = b.Month_
and Year(Convert (c.date, sysdatetime())) <= Year_
)
where c.Type = '1'
Order by 1,2


NIe jest to zapewne specjalnie optymalne zapytanie z punktu widzenia wydajności ,
ale rekordy będą unikalne.Grzegorz K. edytował(a) ten post dnia 20.11.12 o godzinie 17:13
Krzysztof Fiutek

Krzysztof Fiutek menadżer projektu,
Asseco Bussines
Solutions

Temat: Problem z wyświetleniem danych - duplikują się!


NIe rozumiem, po co Ci tabela Data_Table skoro i tak nie agregujesz nic względem roku i miesiąca.

W Twojej propozycji dostaniesz jako rezultat tylko miesiące i lata w których wystąpił kontrakt lub budżet. Jeśli te dane miały by mieć pewną postać graficzną (np. coś na przykładzie pivot table gdzie na odciętych masz oś czasu a na rzędnych budżet i kontrakt) to wtedy najlepiej wyjść od tabelki zawierającej wszystkie daty (rok, miesiąc). Wtedy osoba przeglądając takie dane od razu widzi że np. w danym okresie czasu nie było wcale budżetu i kontraktu. W dodatku nie masz „dziury w czasie”.
Co do meritum sprawy to ja bym pogrupował dane (wydaje mi się ze grupowanie działa szybciej niż distinct). A jeśli chcesz sprawdzić to czy dane faktycznie się dublują to napisz zapytanie z klauzulą having:
select
Year_, Month_, tmp_contract.Contract, tmp_budget.Budget, count(1) as licznik
from Date_Table

left join
(
select
Year(Contract_Signature_Date) as Rok,
Month(Contract_Signature_Date) as Miesiac,
Contract_Id as Contract
from Contract_Table
where Type = '1'
)
tmp_contract
on
tmp_contract.Rok = Year_ and tmp_contract.Miesiac = Month_

left join
(
select
Year_ as Rok,
Month_ as Miesiac,
Budget_Id as Budget
from Budget_Table
where Year(Convert (date, sysdatetime())) <= Year_
)
tmp_budget
on
tmp_budget.Rok = Year_ and tmp_budget.Miesiac = Month_
group by Year_, Month_, tmp_contract.Contract, tmp_budget.Budget
having count(1)>1
order by Year_, Month_
Oskar Oleszkiewicz

Oskar Oleszkiewicz Programista z pasją

Temat: Problem z wyświetleniem danych - duplikują się!

Witam,

dziękuje za ciekawe wypowiedzi, Krzysztof rozszyfrował dokładnie moje potrzeby, potrzebuje "pustych" kolumn z uwagi na wyciąganie z tej tabeli danych do raportu, który uwzględnia także te okresy czasu gdzie takiej sprzedaży lub budżetu nie było, dbając za razem o to aby podczas przeglądania raportu (z wybieranym zakresem dat) nie wystąpiła wspomniana dziura "w czasie".

Poradziłem sobie z tym problemem, używając "distinct", z racji tego ze głównym zadaniem jest stworzenie szkieletu raportu, na razie nie optymalizuje tego zapytania, niemniej jak znajde chwilę to sprawdzę działanie "having"

Pozdrawiam i jeszcze raz dziękuje za wypowiedzi.
Oskar
Grzegorz K.

Grzegorz K. Data & Analytics
Engineer

Temat: Problem z wyświetleniem danych - duplikują się!

ok, w pytaniu nie było napisane jakie jest przeznaczenie wyciąganych danych - zasugerowałem się kodem SQL.

Jeśli na danych ma być postawione jakieś zestawienie, to czemu służy ładowanie danych per kontrakt ? Czy nie prezentujesz np. ile kontraktów było w danym roku podpisanych(o ile były) i jaki był w tym roku budżet (tej pozycji nie jestem pewien po jest tu jakieś "id budżetu")? Jeśli tak wtedy wystarczy wstawić count(*) w podzapytaniu o kontraktach
oraz sum(budzet) lub count(id budzetu) (niepotrzebne skreślić).

Dlatego pisałem o tej agregacji, bo przy budowaniu takiego zestawienia uzupełnienie luk w datach ma sens - z tym się zgadzam. Jednak patrząc na kod nie sądziłem , że chodzi tu o taki raport.

Wrzucanie danych per kontrakt, po to aby po stronie Excela zbudować pivot'a i zrobić tam count'y czy sumy jest nieefektywne.
Lepiej jest zrobić agregaty po stronie serwera , wrzucając je póżniej do obrabiania w tabeli przestawnej/ wykresie przestawnym, niż wrzucać do Excela dane per kontrakt , być może obciążając wagę pliku, a z pewnością obciążając pamięć stacjonarnego komputera , którym raport chodzi (przy dużych tabelach , otwartych wielu plikach i aplikacjach przez użytkownika - zawieszka gotowa).

Przy zastosowaniu grupowania w podzapytaniach, ani distinct ani grupowanie w głównym zapytaniu nie będą potrzebne (choc zagadkowe jest dla mnie pole Budget_Id - nie wiem jak ma być analizowane). Czyli np:



select
Year_, Month_, tmp_contract.[Number of contracts], tmp_budget.Budget
from Date_Table

left join
(
select
Year(Contract_Signature_Date) as Rok,
Month(Contract_Signature_Date) as Miesiac,
count(Contract_Id) as [Number of contracts]
from Contract_Table
where Type = '1'
Group by Year(Contract_Signature_Date), Month(Contract_Signature_Date)
)
tmp_contract
on
tmp_contract.Rok = Year_ and tmp_contract.Miesiac = Month_

left join
(
select
Year_ as Rok,
Month_ as Miesiac,
count(Budget_Id) as Budget
from Budget_Table
where Year(Convert (date, sysdatetime())) <= Year_
Group by Year_ , Month_
)
tmp_budget
on
tmp_budget.Rok = Year_ and tmp_budget.Miesiac = Month_
order by Year_, Month_



Zakładam , że Contract_Id jest uniklane w Contract_Table, zaś Budget_Id w Budget_Table.

pozdrawiamGrzegorz K. edytował(a) ten post dnia 22.11.12 o godzinie 00:45



Wyślij zaproszenie do