Dlaczego SELECT DISTINCT * FROM tablenie działa dla ciebie?
ypercubeᵀᴹ
19
Jeśli twoja tabela ma PK, wszystkie wiersze powinny być distinctz definicji. Jeśli próbujesz tylko wybrać, DISTINCT field1ale jakoś zwrócić wszystkie inne kolumny, co powinno się stać dla tych kolumn, które mają więcej niż jedną wartość dla określonej field1wartości? Na przykład musisz użyć GROUP BYi pewnego rodzaju agregacji w innych kolumnach.
Martin Smith
1
Jeśli chcesz powtarzać wiersze, a nie tylko różne wiersze, usuń wyraźne słowo kluczowe.
Hyperboreus
2
Czy możesz podać przykład, w jaki sposób będą wyglądać wyniki? Jak dotąd nie mogę zrozumieć Twojego żądanego zapytania.
Które czasami można napisać z wyraźnym oświadczeniem:
selectdistincton field1 *fromtable
Jednak na większości platform żadna z powyższych opcji nie będzie działać, ponieważ zachowanie innych kolumn nie jest określone. (Pierwszy działa w MySQL, jeśli tego używasz.)
Możesz pobrać odrębne pola i za każdym razem trzymać się wybierania jednego dowolnego wiersza.
Na niektórych platformach (np. PostgreSQL, Oracle, T-SQL) można to zrobić bezpośrednio za pomocą funkcji okna:
Zapytanie nie będzie analizować dla mnie i daje błąd: The ranking function "row_number" must have an ORDER BY clause. Musimy dodać kolejność według klauzuli po podziale według pola1. Tak więc prawidłowe zapytanie będzie select * from ( select *, row_number() over (partition by field1 order by orderbyFieldName) as row_number from table ) as rows where row_number = 1
Ankur-m
1
Dzięki! Miałem ten sam problem i rozwiązaniem było GROUP BY
Joaquin Iurchuk
2
Również w Oracle (Oracle SQL Developer) nie można określić select *, row_number() over (partition by field1 order by field2) as row_number from table. Musisz jawnie użyć nazwy tabeli / aliasu w wybranym zapytaniuselect **table**.*, row_number() over (partition by field1 order by field2) as row_number from table
meta4
1
@jarlh: Może być ... dzisiaj. Jak można zauważyć, ta odpowiedź ma prawie 7 lat, moment, w którym tak nie było, o ile mogę przypomnieć sobie, kiedy byłem aktywny. Możesz ponownie oznaczyć i / lub edytować odpowiedź, jeśli uważasz, że jest to konieczne.
Denis de Bernardy
2
select distinct on (field1) * from table; działa również w PostgreSQL
Chilianu Bogdan
61
Z frazowania twojego pytania rozumiem, że chcesz wybrać odrębne wartości dla danego pola i dla każdej takiej wartości mieć wszystkie pozostałe wartości kolumn w tym samym wierszu na liście. Większość DBMS nie pozwoli na to ani DISTINCTani GROUP BY, ponieważ wynik nie jest określony.
Pomyśl o tym w ten sposób: jeśli field1wystąpi więcej niż jeden raz, jaka wartość field2zostanie wyświetlona (biorąc pod uwagę, że masz taką samą wartość field1w dwóch wierszach, ale dwie różne wartości field2w tych dwóch wierszach).
Możesz jednak użyć funkcji agregujących (jawnie dla każdego pola, które chcesz wyświetlić) i użyć GROUP BYzamiast DISTINCT:
+1 za to rozwiązanie. Więc możemy to zrobić SELECT field1, MIN(field2), MIN(field3), MIN(field4), .... FROM table GROUP BY field1, a pola 2, 3, 4 ,,, nie muszą być liczbami całkowitymi (lub innymi cyframi), mogą to być również pola znakowe
prześledzić
Działał ładnie, dopóki nie utknąłem w kolumnie boolowskiej. Wartości kolumny MIN (dynamiczne) zostają zmienione na false, nawet jeśli to prawda. Każda inna funkcja agregująca dostępna do adresowania wartości logicznych - signonsridhar 6 minut temu. Suma (dynamiczna) zmieniono false na 1
signonsridhar
1
Świetna sugestia, doprowadziła mnie do mojego rozwiązania, które moim zdaniem jest bardziej uniwersalne - spójrz!
Garrett Simpson
@signonsridhar rzucił boolean na int i użył sumy; np.sum(cast(COL as int)) > 0
Drew
26
Jeśli dobrze zrozumiałem twój problem, jest podobny do tego, który właśnie miałem. Chcesz móc ograniczyć użyteczność DISTINCT do określonego pola, zamiast stosować go do wszystkich danych.
Jeśli użyjesz GROUP BY bez funkcji agregującej, w którymkolwiek polu GROUP GROUP będzie twoje DISTINCT.
Jeśli wykonasz zapytanie:
SELECT*fromtableGROUPBY field1;
Wyświetli wszystkie wyniki oparte na pojedynczej instancji field1.
Na przykład, jeśli masz tabelę z nazwą, adresem i miastem. Pojedyncza osoba ma zarejestrowanych wiele adresów, ale potrzebujesz tylko jednego adresu dla tej osoby, możesz zapytać w następujący sposób:
SELECT*FROM persons GROUPBY name;
Rezultat będzie taki, że tylko jedna instancja tej nazwy pojawi się z jej adresem, a druga zostanie pominięta w wynikowej tabeli. Uwaga: jeśli twoje pola mają wartości atomowe, takie jak imię, nazwisko, które chcesz pogrupować według obu.
SELECT*FROM persons GROUPBY lastName, firstName;
ponieważ jeśli dwie osoby mają to samo nazwisko, a ty grupujesz tylko według nazwiska, jedna z tych osób zostanie pominięta w wynikach. Musisz wziąć to pod uwagę. Mam nadzieję że to pomoże.
Dlaczego jest czas, Caliaskiedy może działać bez niego? w kolejceFROM dbo.TABLE AS C
Talha,
2
Wierzę, że jest to spowodowane moim użyciem RedGate SQLPrompt. Sposób, w jaki go skonfigurowałem, zawsze dodaje aliasy - nawet jeśli nie jest to konieczne. Jest tam „na wszelki wypadek”
Stormy
Wyglądało to obiecująco, ale wciąż przywracało wszystkie wiersze, a nie wyraźne pole1. :(
Michael Fever
13
To naprawdę dobre pytanie. Przeczytałem już kilka przydatnych odpowiedzi tutaj, ale prawdopodobnie mogę dodać bardziej precyzyjne wyjaśnienie.
Zmniejszenie liczby wyników zapytań za pomocą instrukcji GROUP BY jest łatwe, o ile nie zapytasz o dodatkowe informacje. Załóżmy, że masz następującą tabelę „lokalizacje”.
--country-- --city--
France Lyon
Poland Krakow
France Paris
France Marseille
Italy Milano
Teraz zapytanie
SELECT country FROM locations
GROUPBY country
spowoduje:
--country--
France
Poland
Italy
Jednak następujące zapytanie
SELECT country, city FROM locations
GROUPBY country
... zgłasza błąd w MS SQL, ponieważ skąd twój komputer może wiedzieć, które z trzech francuskich miast „Lyon”, „Paryż” lub „Marsylia” chcesz przeczytać w polu po prawej stronie „Francja”?
Aby poprawić drugie zapytanie, musisz dodać tę informację. Jednym ze sposobów jest skorzystanie z funkcji MAX () lub MIN (), wybierając największą lub najmniejszą wartość spośród wszystkich kandydatów. MAX () i MIN () mają zastosowanie nie tylko do wartości liczbowych, ale także porównują kolejność alfabetyczną wartości ciągów.
SELECT country, MAX(city)FROM locations
GROUPBY country
spowoduje:
--country-- --city--
France Paris
Poland Krakow
Italy Milano
lub:
SELECT country, MIN(city)FROM locations
GROUPBY country
spowoduje:
--country-- --city--
France Lyon
Poland Krakow
Italy Milano
Te funkcje są dobrym rozwiązaniem, o ile nie przeszkadza ci wybranie wartości z obu końców kolejności alfabetycznej (lub numerycznej). Ale co, jeśli tak nie jest? Załóżmy, że potrzebujesz wartości o określonej charakterystyce, np. Zaczynającej się na literę „M”. Teraz sprawy się komplikują.
Jedynym rozwiązaniem, jakie do tej pory mogłem znaleźć, jest umieszczenie całego zapytania w podzapytaniu i zbudowanie dodatkowej kolumny poza nim ręcznie:
SELECT
countrylist.*,(SELECTTOP1 city
FROM locations
WHERE
country = countrylist.country
AND city like'M%')FROM(SELECT country FROM locations
GROUPBY country) countrylist
spowoduje:
--country-- --city--
France Marseille
Poland NULL
Italy Milano
Świetne pytanie @aryaxt - można powiedzieć, że było to świetne pytanie, ponieważ zadałeś je 5 lat temu, a ja natknąłem się na to dzisiaj, próbując znaleźć odpowiedź!
Właśnie próbowałem edytować zaakceptowaną odpowiedź, aby uwzględnić to, ale w przypadku, gdy moja edycja nie zawiera:
Jeśli tabela nie była tak duża i zakładając, że klucz podstawowy jest liczbą całkowitą z automatyczną inkrementacją, możesz zrobić coś takiego:
SELECTtable.*FROMtable--be able to take out dupes laterLEFTJOIN(SELECT field, MAX(id)as id
FROMtableGROUPBY field
)as noDupes on noDupes.id =table.id
WHERE//this will result in only the last instance being seen
noDupes.id isnotNULL
W przypadku SQL Server można użyć dense_rank i dodatkowych funkcji okienkowania, aby uzyskać wszystkie wiersze ORAZ kolumny ze zduplikowanymi wartościami w określonych kolumnach. Oto przykład...
with t as(select col1 ='a', col2 ='b', col3 ='c', other ='r1'unionallselect col1 ='c', col2 ='b', col3 ='a', other ='r2'unionallselect col1 ='a', col2 ='b', col3 ='c', other ='r3'unionallselect col1 ='a', col2 ='b', col3 ='c', other ='r4'unionallselect col1 ='c', col2 ='b', col3 ='a', other ='r5'unionallselect col1 ='a', col2 ='a', col3 ='a', other ='r6'), tdr as(select*,
total_dr_rows = count(*)over(partitionby dr)from(select*,
dr = dense_rank()over(orderby col1, col2, col3),
dr_rn = row_number()over(partitionby col1, col2, col3 orderby other)from
t
) x
)select*from tdr where total_dr_rows >1
Pobiera to liczbę wierszy dla każdej odrębnej kombinacji col1, col2 i col3.
To zadziałało dla mnie !! Warto zauważyć, że jeśli używasz fetch_array (), będziesz musiał wywoływać każdy wiersz za pomocą etykiety indeksu zamiast domyślnie wywoływać nazwę wiersza. Nie ma w tym wystarczająco dużo znaków, aby napisać przykład, który mam: X przepraszam !!
Jak wspomniano w zaakceptowanej odpowiedzi, działałby dla większości wcieleń SQL - tylko dla MYSQL
Garrett Simpson
0
Znalazłem to gdzie indziej tutaj, ale jest to proste rozwiązanie, które działa:
WITH cte AS/* Declaring a new table named 'cte' to be a clone of your table */(SELECT*, ROW_NUMBER()OVER(PARTITIONBY id ORDERBY val1 DESC)AS rn
FROM MyTable /* Selecting only unique values based on the "id" field */)SELECT*/* Here you can specify several columns to retrieve */FROM cte
WHERE rn =1
To nie zadziała. Wybrano odrębną kolumnę w podzapytaniu, ale klauzula where pobiera wszystkie kolumny o tej wartości. Tak więc zapytanie jest tak dobre, jak napisanie „wybierz * z tabeli”, chyba że kolumna „pole” jest unikalną kolumną, w którym to przypadku wyróżnienie w tej kolumnie nie jest wcale wymagane.
Ankur-m
-3
WYBIERZ POLE ODLEGŁOŚCI 1, FIELD2, FIELD3 Z TABELI 1 działa, jeśli wartości wszystkich trzech kolumn są unikalne w tabeli.
Jeśli na przykład masz wiele identycznych wartości dla imienia, ale nazwisko i inne informacje w wybranych kolumnach są różne, rekord zostanie uwzględniony w zestawie wyników.
SELECT DISTINCT * FROM table
nie działa dla ciebie?distinct
z definicji. Jeśli próbujesz tylko wybrać,DISTINCT field1
ale jakoś zwrócić wszystkie inne kolumny, co powinno się stać dla tych kolumn, które mają więcej niż jedną wartość dla określonejfield1
wartości? Na przykład musisz użyćGROUP BY
i pewnego rodzaju agregacji w innych kolumnach.Odpowiedzi:
Szukasz grupy według:
Które czasami można napisać z wyraźnym oświadczeniem:
Jednak na większości platform żadna z powyższych opcji nie będzie działać, ponieważ zachowanie innych kolumn nie jest określone. (Pierwszy działa w MySQL, jeśli tego używasz.)
Możesz pobrać odrębne pola i za każdym razem trzymać się wybierania jednego dowolnego wiersza.
Na niektórych platformach (np. PostgreSQL, Oracle, T-SQL) można to zrobić bezpośrednio za pomocą funkcji okna:
W innych (MySQL, SQLite) musisz napisać podkwerendy, dzięki którym dołączysz do całej tabeli ze sobą ( przykład ), więc nie jest to zalecane.
źródło
The ranking function "row_number" must have an ORDER BY clause
. Musimy dodać kolejność według klauzuli po podziale według pola1. Tak więc prawidłowe zapytanie będzieselect * from ( select *, row_number() over (partition by field1 order by orderbyFieldName) as row_number from table ) as rows where row_number = 1
GROUP BY
select *, row_number() over (partition by field1 order by field2) as row_number from table
. Musisz jawnie użyć nazwy tabeli / aliasu w wybranym zapytaniuselect **table**.*, row_number() over (partition by field1 order by field2) as row_number from table
select distinct on (field1) * from table
; działa również w PostgreSQLZ frazowania twojego pytania rozumiem, że chcesz wybrać odrębne wartości dla danego pola i dla każdej takiej wartości mieć wszystkie pozostałe wartości kolumn w tym samym wierszu na liście. Większość DBMS nie pozwoli na to ani
DISTINCT
aniGROUP BY
, ponieważ wynik nie jest określony.Pomyśl o tym w ten sposób: jeśli
field1
wystąpi więcej niż jeden raz, jaka wartośćfield2
zostanie wyświetlona (biorąc pod uwagę, że masz taką samą wartośćfield1
w dwóch wierszach, ale dwie różne wartościfield2
w tych dwóch wierszach).Możesz jednak użyć funkcji agregujących (jawnie dla każdego pola, które chcesz wyświetlić) i użyć
GROUP BY
zamiastDISTINCT
:źródło
SELECT field1, MIN(field2), MIN(field3), MIN(field4), .... FROM table GROUP BY field1
, a pola 2, 3, 4 ,,, nie muszą być liczbami całkowitymi (lub innymi cyframi), mogą to być również pola znakowesum(cast(COL as int)) > 0
Jeśli dobrze zrozumiałem twój problem, jest podobny do tego, który właśnie miałem. Chcesz móc ograniczyć użyteczność DISTINCT do określonego pola, zamiast stosować go do wszystkich danych.
Jeśli użyjesz GROUP BY bez funkcji agregującej, w którymkolwiek polu GROUP GROUP będzie twoje DISTINCT.
Jeśli wykonasz zapytanie:
Wyświetli wszystkie wyniki oparte na pojedynczej instancji field1.
Na przykład, jeśli masz tabelę z nazwą, adresem i miastem. Pojedyncza osoba ma zarejestrowanych wiele adresów, ale potrzebujesz tylko jednego adresu dla tej osoby, możesz zapytać w następujący sposób:
Rezultat będzie taki, że tylko jedna instancja tej nazwy pojawi się z jej adresem, a druga zostanie pominięta w wynikowej tabeli. Uwaga: jeśli twoje pola mają wartości atomowe, takie jak imię, nazwisko, które chcesz pogrupować według obu.
ponieważ jeśli dwie osoby mają to samo nazwisko, a ty grupujesz tylko według nazwiska, jedna z tych osób zostanie pominięta w wynikach. Musisz wziąć to pod uwagę. Mam nadzieję że to pomoże.
źródło
źródło
C
alias
kiedy może działać bez niego? w kolejceFROM dbo.TABLE AS C
To naprawdę dobre pytanie. Przeczytałem już kilka przydatnych odpowiedzi tutaj, ale prawdopodobnie mogę dodać bardziej precyzyjne wyjaśnienie.
Zmniejszenie liczby wyników zapytań za pomocą instrukcji GROUP BY jest łatwe, o ile nie zapytasz o dodatkowe informacje. Załóżmy, że masz następującą tabelę „lokalizacje”.
Teraz zapytanie
spowoduje:
Jednak następujące zapytanie
... zgłasza błąd w MS SQL, ponieważ skąd twój komputer może wiedzieć, które z trzech francuskich miast „Lyon”, „Paryż” lub „Marsylia” chcesz przeczytać w polu po prawej stronie „Francja”?
Aby poprawić drugie zapytanie, musisz dodać tę informację. Jednym ze sposobów jest skorzystanie z funkcji MAX () lub MIN (), wybierając największą lub najmniejszą wartość spośród wszystkich kandydatów. MAX () i MIN () mają zastosowanie nie tylko do wartości liczbowych, ale także porównują kolejność alfabetyczną wartości ciągów.
spowoduje:
lub:
spowoduje:
Te funkcje są dobrym rozwiązaniem, o ile nie przeszkadza ci wybranie wartości z obu końców kolejności alfabetycznej (lub numerycznej). Ale co, jeśli tak nie jest? Załóżmy, że potrzebujesz wartości o określonej charakterystyce, np. Zaczynającej się na literę „M”. Teraz sprawy się komplikują.
Jedynym rozwiązaniem, jakie do tej pory mogłem znaleźć, jest umieszczenie całego zapytania w podzapytaniu i zbudowanie dodatkowej kolumny poza nim ręcznie:
spowoduje:
źródło
Świetne pytanie @aryaxt - można powiedzieć, że było to świetne pytanie, ponieważ zadałeś je 5 lat temu, a ja natknąłem się na to dzisiaj, próbując znaleźć odpowiedź!
Właśnie próbowałem edytować zaakceptowaną odpowiedź, aby uwzględnić to, ale w przypadku, gdy moja edycja nie zawiera:
Jeśli tabela nie była tak duża i zakładając, że klucz podstawowy jest liczbą całkowitą z automatyczną inkrementacją, możesz zrobić coś takiego:
źródło
Próbować
źródło
Możesz to zrobić za pomocą
WITH
klauzuli.Na przykład:
Pozwala to również wybrać tylko wiersze wybrane w
WITH
zapytaniu dotyczącym klauzul.źródło
W przypadku SQL Server można użyć dense_rank i dodatkowych funkcji okienkowania, aby uzyskać wszystkie wiersze ORAZ kolumny ze zduplikowanymi wartościami w określonych kolumnach. Oto przykład...
Pobiera to liczbę wierszy dla każdej odrębnej kombinacji col1, col2 i col3.
źródło
źródło
W
ORDER BY
właśnie podałem tutaj przykład, możesz również dodać pole ID w tymźródło
Znalazłem to gdzie indziej tutaj, ale jest to proste rozwiązanie, które działa:
źródło
Dodaj GROUP BY do pola, w którym chcesz sprawdzić, czy duplikaty mogą wyglądać Twoje zapytanie
pole1 zostanie zaznaczone, aby wykluczyć zduplikowane rekordy
lub możesz zapytać jak
zduplikowane rekordy pola 1 są wykluczone z SELECT
źródło
filed2 must appear in the GROUP BY clause or be used in an aggregate function
Wystarczy dołączyć wszystkie pola do klauzuli GROUP BY.
źródło
Można to zrobić za pomocą wewnętrznego zapytania
źródło
źródło
WYBIERZ POLE ODLEGŁOŚCI 1, FIELD2, FIELD3 Z TABELI 1 działa, jeśli wartości wszystkich trzech kolumn są unikalne w tabeli.
Jeśli na przykład masz wiele identycznych wartości dla imienia, ale nazwisko i inne informacje w wybranych kolumnach są różne, rekord zostanie uwzględniony w zestawie wyników.
źródło
Sugerowałbym użycie
w ten sposób, jeśli masz tę samą wartość w polu 1 w wielu wierszach, wszystkie rekordy zostaną zwrócone.
źródło
SELECT * FROM table;
. Co więcej, jest wolny.