Почему у SELECT DISTINCT * FROM tableвас не работает?
ypercubeᵀᴹ
19
Если в вашей таблице есть PK, все строки должны быть distinctпо определению. Если вы пытаетесь просто выбрать, DISTINCT field1но каким-то образом вернуть все другие столбцы, что должно произойти для тех столбцов, которые имеют более одного значения для определенного field1значения? Вы должны будете использовать GROUP BYи некоторые виды агрегации для других столбцов, например.
Мартин Смит
1
Если вам нужны повторяющиеся строки, а не только отдельные строки, удалите ключевое слово.
Гиперборей
2
Не могли бы вы привести пример того, как вы ожидаете, что результаты будут выглядеть? Пока что я не могу понять смысл вашего желаемого запроса.
Которые иногда могут быть написаны с внятным выражением:
selectdistincton field1 *fromtable
Однако на большинстве платформ ни один из вышеперечисленных не будет работать, поскольку поведение других столбцов не определено. (Первый работает в MySQL, если это то, что вы используете.)
Вы можете выбрать отдельные поля и каждый раз выбирать одну произвольную строку.
На некоторых платформах (например, PostgreSQL, Oracle, T-SQL) это можно сделать напрямую с помощью оконных функций:
На других (MySQL, SQLite) вам нужно написать подзапросы, которые заставят вас объединить всю таблицу с самим собой ( пример ), поэтому не рекомендуется.
Запрос не будет разбирать для меня и выдает ошибку: The ranking function "row_number" must have an ORDER BY clause. Нам нужно добавить порядок по предложению после разделения по полю1. Так что правильный запрос будет 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
Спасибо! Я был в той же проблеме, и решение было GROUP BY
Хоакин Иурчук
2
Также в Oracle (Oracle SQL Developer) вы не можете указать select *, row_number() over (partition by field1 order by field2) as row_number from table. Вы должны явно использовать имя таблицы / псевдоним в запросе выбораselect **table**.*, row_number() over (partition by field1 order by field2) as row_number from table
meta4
1
@jarlh: Может быть ... сегодня. Как вы можете заметить, этому ответу почти 7 лет, момент, когда этого не произошло, насколько я могу вспомнить из прошлого, когда я был активным. Вы можете пометить и / или изменить ответ, если считаете, что это необходимо.
Дени де Бернарди
2
select distinct on (field1) * from table; работает также в PostgreSQL
Чилиану Богдан
61
Из формулировки вашего вопроса я понимаю, что вы хотите выбрать отдельные значения для данного поля и для каждого такого значения, чтобы все остальные значения столбцов в той же строке были перечислены. Большинство СУБД не допустит этого ни с DISTINCTни GROUP BY, потому что результат не определен.
Подумайте об этом так: если ваше field1происходит более одного раза, какое значение field2будет указано в списке (учитывая, что у вас есть одно и то же значение field1в двух строках, но два разных значения field2в этих двух строках).
Однако вы можете использовать агрегатные функции (явно для каждого поля, которое вы хотите показать) и использовать GROUP BYвместо DISTINCT:
+1 за это решение. Таким образом , мы можем сделать SELECT field1, MIN(field2), MIN(field3), MIN(field4), .... FROM table GROUP BY field1, и field2, 3, 4 ,,, не должны быть целыми числами (или другие цифры), они могут быть символьные поля, а
ножке
Работал хорошо, пока я не застрял в логической колонке. Значения столбца MIN (динамические) изменяются на false, даже если это было истиной. Любая другая агрегатная функция, доступная для обращения к логическому - signonsridhar 6 минут назад. Сумма (динамическая) изменена с ложного на 1
signonsridhar
1
Отличное предложение привело меня к моему решению, которое я считаю более универсальным - взгляните!
Гаррет Симпсон
@signonsridhar приведите ваш логический тип к int и используйте сумму; напримерsum(cast(COL as int)) > 0
Дрю
26
Если я правильно понял вашу проблему, она похожа на ту, что у меня была. Вы хотите иметь возможность ограничить удобство использования DISTINCT указанным полем, а не применять его ко всем данным.
Если вы используете GROUP BY без агрегатной функции, то в любом поле, которое вы указали в поле GROUP BY, будет указано ваше поле DISTINCT.
Если вы делаете свой запрос:
SELECT*fromtableGROUPBY field1;
Он покажет все ваши результаты на основе одного экземпляра field1.
Например, если у вас есть таблица с именем, адресом и городом. У одного человека записано несколько адресов, но вы просто хотите один адрес для человека, вы можете сделать запрос следующим образом:
SELECT*FROM persons GROUPBY name;
В результате будет отображаться только один экземпляр этого имени с его адресом, а другой будет исключен из результирующей таблицы. Внимание: если ваши поля имеют атомарные значения, такие как firstName, lastName, вы хотите сгруппировать по обоим.
SELECT*FROM persons GROUPBY lastName, firstName;
потому что если два человека имеют одинаковую фамилию и вы группируете только по фамилии, один из этих людей будет исключен из результатов. Вы должны держать эти вещи во внимание. Надеюсь это поможет.
Почему есть, Caliasкогда он может работать без него? в очередиFROM dbo.TABLE AS C
Талха
2
Я считаю, что это связано с моим использованием RedGate SQLPrompt. Как я настроил, он всегда добавляет псевдонимы - даже если они не нужны. Это там «на всякий случай»
Stormy
Это выглядело многообещающе для меня, но все равно вернуло все строки, а не отдельное поле1. :(
Майкл Лихорадка
13
Это действительно хороший вопрос. Я уже прочитал некоторые полезные ответы здесь, но, вероятно, я могу добавить более точное объяснение.
Сократить количество результатов запроса с помощью оператора GROUP BY легко, если вы не запрашиваете дополнительную информацию. Давайте предположим, что вы получили следующую таблицу 'location'.
--country-- --city--
France Lyon
Poland Krakow
France Paris
France Marseille
Italy Milano
Теперь запрос
SELECT country FROM locations
GROUPBY country
приведет к:
--country--
France
Poland
Italy
Тем не менее, следующий запрос
SELECT country, city FROM locations
GROUPBY country
... выдает ошибку в MS SQL, потому что как ваш компьютер может узнать, какой из трех французских городов "Лион", "Париж" или "Марсель" вы хотите прочитать в поле справа от "Франция"?
Чтобы исправить второй запрос, необходимо добавить эту информацию. Один из способов сделать это - использовать функции MAX () или MIN (), выбирая наибольшее или наименьшее значение среди всех кандидатов. MAX () и MIN () не только применимы к числовым значениям, но также сравнивают алфавитный порядок строковых значений.
SELECT country, MAX(city)FROM locations
GROUPBY country
приведет к:
--country-- --city--
France Paris
Poland Krakow
Italy Milano
или:
SELECT country, MIN(city)FROM locations
GROUPBY country
приведет к:
--country-- --city--
France Lyon
Poland Krakow
Italy Milano
Эти функции являются хорошим решением, если вы хорошо выбираете значение в любом конце алфавитного (или числового) порядка. Но что, если это не так? Предположим, вам нужно значение с определенной характеристикой, например, начинающееся с буквы «М». Теперь все усложняется.
Единственное решение, которое я смог найти, - это поместить весь ваш запрос в подзапрос и создать дополнительный столбец вне него руками:
SELECT
countrylist.*,(SELECTTOP1 city
FROM locations
WHERE
country = countrylist.country
AND city like'M%')FROM(SELECT country FROM locations
GROUPBY country) countrylist
приведет к:
--country-- --city--
France Marseille
Poland NULL
Italy Milano
Отличный вопрос @aryaxt - вы можете сказать, что это был отличный вопрос, потому что вы задавали его 5 лет назад, и я наткнулся на него сегодня, пытаясь найти ответ!
Я только попытался отредактировать принятый ответ, чтобы включить это, но в случае, если мое редактирование не делает это в:
Если ваша таблица была не такой большой, и предполагая, что ваш первичный ключ представляет собой целое число с автоинкрементом, вы можете сделать что-то вроде этого:
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
Для SQL Server вы можете использовать diff_rank и дополнительные функции управления окнами, чтобы получить все строки И столбцы с дублированными значениями в указанных столбцах. Вот пример ...
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
При этом учитывается количество строк для каждой отдельной комбинации col1, col2 и col3.
Это сработало для меня! Стоит отметить, что если вы используете fetch_array (), то вам нужно будет вызывать каждую строку с помощью индексной метки, а не неявно вызывать имя строки. Для этого недостаточно символов, чтобы написать пример, который у меня есть: X извините !!
Как уже упоминалось в принятом ответе, будет работать для большинства воплощений SQL - только для MYSQL
Гаррет Симпсон
0
Нашел это в другом месте здесь, но это простое решение, которое работает:
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
Предложение GROUP BY должно соответствовать выбранным полям. иначе это выдаст ошибку какfiled2 must appear in the GROUP BY clause or be used in an aggregate function
Viuu -a
-2
Просто включите все свои поля в предложение GROUP BY.
Это не сделает работу. Вы выбрали отдельный столбец в подзапросе, но предложение where получает все эти столбцы с этим значением. Таким образом, запрос так же хорош, как запись «select * from table», если столбец «field» не является уникальным столбцом, и в этом случае различное значение для этого столбца не требуется вообще.
Анкур-м
-3
SELECT DISTINCT FIELD1, FIELD2, FIELD3 FROM TABLE1 работает, если значения всех трех столбцов являются уникальными в таблице.
Если, например, у вас есть несколько одинаковых значений для имени, но фамилия и другая информация в выбранных столбцах отличаются, запись будет включена в набор результатов.
SELECT DISTINCT * FROM table
вас не работает?distinct
по определению. Если вы пытаетесь просто выбрать,DISTINCT field1
но каким-то образом вернуть все другие столбцы, что должно произойти для тех столбцов, которые имеют более одного значения для определенногоfield1
значения? Вы должны будете использоватьGROUP BY
и некоторые виды агрегации для других столбцов, например.Ответы:
Вы ищете группу по:
Которые иногда могут быть написаны с внятным выражением:
Однако на большинстве платформ ни один из вышеперечисленных не будет работать, поскольку поведение других столбцов не определено. (Первый работает в MySQL, если это то, что вы используете.)
Вы можете выбрать отдельные поля и каждый раз выбирать одну произвольную строку.
На некоторых платформах (например, PostgreSQL, Oracle, T-SQL) это можно сделать напрямую с помощью оконных функций:
На других (MySQL, SQLite) вам нужно написать подзапросы, которые заставят вас объединить всю таблицу с самим собой ( пример ), поэтому не рекомендуется.
источник
The ranking function "row_number" must have an ORDER BY clause
. Нам нужно добавить порядок по предложению после разделения по полю1. Так что правильный запрос будетselect * 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
. Вы должны явно использовать имя таблицы / псевдоним в запросе выбораselect **table**.*, row_number() over (partition by field1 order by field2) as row_number from table
select distinct on (field1) * from table
; работает также в PostgreSQLИз формулировки вашего вопроса я понимаю, что вы хотите выбрать отдельные значения для данного поля и для каждого такого значения, чтобы все остальные значения столбцов в той же строке были перечислены. Большинство СУБД не допустит этого ни с
DISTINCT
ниGROUP BY
, потому что результат не определен.Подумайте об этом так: если ваше
field1
происходит более одного раза, какое значениеfield2
будет указано в списке (учитывая, что у вас есть одно и то же значениеfield1
в двух строках, но два разных значенияfield2
в этих двух строках).Однако вы можете использовать агрегатные функции (явно для каждого поля, которое вы хотите показать) и использовать
GROUP BY
вместоDISTINCT
:источник
SELECT field1, MIN(field2), MIN(field3), MIN(field4), .... FROM table GROUP BY field1
, и field2, 3, 4 ,,, не должны быть целыми числами (или другие цифры), они могут быть символьные поля, аsum(cast(COL as int)) > 0
Если я правильно понял вашу проблему, она похожа на ту, что у меня была. Вы хотите иметь возможность ограничить удобство использования DISTINCT указанным полем, а не применять его ко всем данным.
Если вы используете GROUP BY без агрегатной функции, то в любом поле, которое вы указали в поле GROUP BY, будет указано ваше поле DISTINCT.
Если вы делаете свой запрос:
Он покажет все ваши результаты на основе одного экземпляра field1.
Например, если у вас есть таблица с именем, адресом и городом. У одного человека записано несколько адресов, но вы просто хотите один адрес для человека, вы можете сделать запрос следующим образом:
В результате будет отображаться только один экземпляр этого имени с его адресом, а другой будет исключен из результирующей таблицы. Внимание: если ваши поля имеют атомарные значения, такие как firstName, lastName, вы хотите сгруппировать по обоим.
потому что если два человека имеют одинаковую фамилию и вы группируете только по фамилии, один из этих людей будет исключен из результатов. Вы должны держать эти вещи во внимание. Надеюсь это поможет.
источник
источник
C
alias
когда он может работать без него? в очередиFROM dbo.TABLE AS C
Это действительно хороший вопрос. Я уже прочитал некоторые полезные ответы здесь, но, вероятно, я могу добавить более точное объяснение.
Сократить количество результатов запроса с помощью оператора GROUP BY легко, если вы не запрашиваете дополнительную информацию. Давайте предположим, что вы получили следующую таблицу 'location'.
Теперь запрос
приведет к:
Тем не менее, следующий запрос
... выдает ошибку в MS SQL, потому что как ваш компьютер может узнать, какой из трех французских городов "Лион", "Париж" или "Марсель" вы хотите прочитать в поле справа от "Франция"?
Чтобы исправить второй запрос, необходимо добавить эту информацию. Один из способов сделать это - использовать функции MAX () или MIN (), выбирая наибольшее или наименьшее значение среди всех кандидатов. MAX () и MIN () не только применимы к числовым значениям, но также сравнивают алфавитный порядок строковых значений.
приведет к:
или:
приведет к:
Эти функции являются хорошим решением, если вы хорошо выбираете значение в любом конце алфавитного (или числового) порядка. Но что, если это не так? Предположим, вам нужно значение с определенной характеристикой, например, начинающееся с буквы «М». Теперь все усложняется.
Единственное решение, которое я смог найти, - это поместить весь ваш запрос в подзапрос и создать дополнительный столбец вне него руками:
приведет к:
источник
Отличный вопрос @aryaxt - вы можете сказать, что это был отличный вопрос, потому что вы задавали его 5 лет назад, и я наткнулся на него сегодня, пытаясь найти ответ!
Я только попытался отредактировать принятый ответ, чтобы включить это, но в случае, если мое редактирование не делает это в:
Если ваша таблица была не такой большой, и предполагая, что ваш первичный ключ представляет собой целое число с автоинкрементом, вы можете сделать что-то вроде этого:
источник
Пытаться
источник
Вы можете сделать это с
WITH
оговоркой.Например:
Это также позволяет вам выбирать только строки, выбранные в
WITH
запросе предложений.источник
Для SQL Server вы можете использовать diff_rank и дополнительные функции управления окнами, чтобы получить все строки И столбцы с дублированными значениями в указанных столбцах. Вот пример ...
При этом учитывается количество строк для каждой отдельной комбинации col1, col2 и col3.
источник
источник
в
ORDER BY
я только что привел пример здесь, вы также можете добавить поле идентификатора в этомисточник
Нашел это в другом месте здесь, но это простое решение, которое работает:
источник
Добавьте GROUP BY в поле, которое вы хотите проверить на дубликаты, ваш запрос может выглядеть
field1 будет проверен, чтобы исключить повторяющиеся записи
или вы можете запросить как
дубликаты записей field1 исключаются из SELECT
источник
filed2 must appear in the GROUP BY clause or be used in an aggregate function
Просто включите все свои поля в предложение GROUP BY.
источник
Это можно сделать внутренним запросом
источник
источник
SELECT DISTINCT FIELD1, FIELD2, FIELD3 FROM TABLE1 работает, если значения всех трех столбцов являются уникальными в таблице.
Если, например, у вас есть несколько одинаковых значений для имени, но фамилия и другая информация в выбранных столбцах отличаются, запись будет включена в набор результатов.
источник
Я бы предложил использовать
таким образом, если у вас есть одно и то же значение в field1 в нескольких строках, будут возвращены все записи.
источник
SELECT * FROM table;
. Еще медленнее.