2012-07-06 13 views
8

BiorącSkutecznie m.in. Kolumna nie w grupie przez SQL Query

Tabela A

Id INTEGER 
Name VARCHAR(50) 

Tabela B

Id INTEGER 
FkId INTEGER ; Foreign key to Table A 

Chciałbym policzyć occurrances każdej wartości FkId :

SELECT FkId, COUNT(FkId) 
FROM B 
GROUP BY FkId 

Teraz po prostu chcę również wypisać nazwę od Table A.

To nie zadziała:

SELECT FkId, COUNT(FkId), a.Name 
FROM B b 
INNER JOIN A a ON a.Id=b.FkId 
GROUP BY FkId 

ponieważ a.Name nie jest zawarta w klauzuli GROUP BY (produkuje is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause błąd).

Chodzi o to, aby przenieść z wyjścia jak ten

FkId Count 
1  42 
2  25 

do wyjścia tak

FkId Count Name 
1  42  Ronald 
2  22  John 

Istnieje sporo mecze na SO dla tego komunikatu o błędzie, ale niektóre np https://stackoverflow.com/a/6456944/141172 mają komentarze typu "wygeneruje 3 skany na stole, zamiast 1, więc nie będzie skali".

Jak ja skutecznie zawierać pole z połączonych Table B (który ma 1: 1 stosunek do FkId) wyjścia zapytania?

+0

Czy możesz pokazać przykładowe dane i pożądane wyniki? Mam trudności ze zrozumieniem, czy może istnieć więcej niż jedna unikalna nazwa dla FkId. –

+0

Dla każdej FkId będzie tylko jedna unikalna nazwa. Chodzi o to, aby pokazać nazwę obok FkId, więc użytkownik patrzący na wynik nie widzi "Osoba 1 pokazała się 42 razy", ale widzi "Osoba 1, której nazwisko nazywa się Ronald, pojawiła się 42 razy". –

+1

Dlaczego więc nie dodać po prostu nazwy do grupy? –

Odpowiedz

12

Można spróbować czegoś takiego:

;WITH GroupedData AS 
    (
     SELECT FkId, COUNT(FkId) As FkCount 
     FROM B 
     GROUP BY FkId 
    ) 
    SELECT gd.*, a.Name 
    FROM GroupedData gd 
    INNER JOIN dbo.A ON gd.FkId = A.FkId 

Tworzenie CTE (Common Expression tabeli) do obsługi grupy/licząc na swojej Table B, a następnie dołączyć do tego wyniku (jeden wiersz za FkId) do Table A i pobierz kilka kolumn z Table A do ostatecznego zestawu wyników.

+0

To prawie tak samo jak rozwiązanie, z którym się łączyłem, które miało komentarz "I wygeneruje 3 skany na stole, a nie 1, więc nie będzie skalować". Czy to rozwiązanie rzeczywiście wykona 3 skany tabel, jak sugeruje ten komentarz? –

+5

@EricJ .: Cóż - skopiuj zapytanie, uruchom je w SQL Server Mgmt Studio i włącz "Real Execution Plan", a zobaczysz, że ** NO ** to ** NIE ** wykona trzy skany tabel .....komentarz w odpowiedzi, z którą się łączyłeś jest poprawny, ponieważ zapytanie tam ma ** dwa dodatkowe ** podkategorie ** (SELECT ....) - ** te ** dodadzą jeden skan tabeli każdy (** NIE ** CTE użyte do grupowania!) –

+1

+1 za wykorzystanie rzeczywistego planu wykonania do zdiagnozowania wydajności. :-) –

3

Czy próbowałeś dodać pole do grupy przez?

SELECT FkId, COUNT(FkId), a.Name 
FROM B b 
INNER JOIN A a ON a.Id=b.FkId 
GROUP BY FkId,a.Name 
0
select t3.Name, t3.FkId, t3.countedFkId from (a t1 
    join (select t2.FkId, count(FkId) as countedFkId from b t2 group by t2.FkId) 
    on t1.Id = t2.FkId) t3; 
+1

Proszę użyć '{}' not' do wyróżnij bloki kodu. I nie bójcie się powrotów powozów. Ponadto nie sądzę, aby to zapytanie było przetwarzane (wyprowadzona tabela wymaga aliasu). –

+0

Oh, dzięki za radę. Wciąż nowa składnia tutaj :) I domyślam się, że masz rację, jeśli potrzebujesz aliasu dla tabeli pochodnej. – germi