SQL / mysql - выбрать отдельный / уникальный, но вернуть все столбцы? - PullRequest
336 голосов
/ 25 мая 2011
SELECT DISTINCT field1, field2, field3, ......   FROM table

Я пытаюсь выполнить следующую инструкцию sql, но хочу, чтобы она возвращала все столбцы, возможно ли это?Что-то вроде:

SELECT DISTINCT field1, * from table

Ответы [ 16 ]

373 голосов
/ 25 мая 2011

Вы ищете группу по:

select *
from table
group by field1

Которому иногда можно написать с отдельным оператором on:

select distinct on field1 *
from table

На большинстве платформ, однако, ни одна извыше будет работать, потому что поведение в других столбцах не определено.(Первый работает в MySQL, если это то, что вы используете.)

Вы можете выбрать отдельные поля и каждый раз выбирать одну произвольную строку.

На некоторых платформах (например,PostgreSQL, Oracle, T-SQL) это можно сделать напрямую с помощью оконных функций:

select *
from (
   select *,
          row_number() over (partition by field1 order by field2) as row_number
   from table
   ) as rows
where row_number = 1

В других (MySQL, SQLite) вам нужно написать подзапросы, которые позволят вам объединить всю таблицу ссам ( пример ), поэтому не рекомендуется.

55 голосов
/ 25 мая 2011

Исходя из формулировки вашего вопроса, я понимаю, что вы хотите выбрать отдельные значения для данного поля и для каждого такого значения иметь все остальные значения столбца в той же строке в списке.Большинство СУБД не допустят этого ни с DISTINCT, ни с GROUP BY, поскольку результат не определен.

Думайте об этом так: если ваш field1 встречается более одного раза, какое значение field2 будут перечислены (учитывая, что у вас есть одинаковое значение для field1 в двух строках, но два разных значения field2 в этих двух строках).

Однако вы можете использовать агрегатные функции (явно для каждого полякоторый вы хотите показать) и использовать GROUP BY вместо DISTINCT:

SELECT field1, MAX(field2), COUNT(field3), SUM(field4), .... FROM table GROUP BY field1
20 голосов
/ 14 мая 2013

Если я правильно понял вашу проблему, она похожа на ту, что у меня была. Вы хотите иметь возможность ограничить удобство использования DISTINCT указанным полем, а не применять его ко всем данным.

Если вы используете GROUP BY без агрегатной функции, то в любом поле, которое вы указали в поле GROUP BY, будет указано ваше поле DISTINCT.

Если вы сделаете свой запрос:

SELECT * from table GROUP BY field1;

Он покажет все ваши результаты на основе одного экземпляра field1.

Например, если у вас есть таблица с именем, адресом и городом. У одного человека записано несколько адресов, но вам нужен только один адрес для человека, вы можете запросить его следующим образом:

SELECT * FROM persons GROUP BY name;

В результате будет отображаться только один экземпляр этого имени с его адресом, а другой будет исключен из результирующей таблицы. Внимание: если ваши поля имеют атомарные значения, такие как firstName, lastName, вы хотите сгруппировать по обоим.

SELECT * FROM persons GROUP BY lastName, firstName;

потому что если два человека имеют одинаковую фамилию и вы группируете только по фамилии, один из этих людей будет исключен из результатов. Вы должны держать эти вещи во внимание. Надеюсь это поможет.

12 голосов
/ 25 мая 2011
SELECT  c2.field1 ,
        field2
FROM    (SELECT DISTINCT
                field1
         FROM   dbo.TABLE AS C
        ) AS c1
        JOIN dbo.TABLE AS c2 ON c1.field1 = c2.field1
7 голосов
/ 24 октября 2017

Это действительно хороший вопрос.Я уже прочитал некоторые полезные ответы здесь, но, вероятно, я могу добавить более точное объяснение.

Сократить число результатов запроса с помощью оператора GROUP BY легко, если вы не запрашиваете дополнительную информацию.Предположим, вы получили следующую таблицу 'location'.

--country-- --city--
 France      Lyon
 Poland      Krakow
 France      Paris
 France      Marseille
 Italy       Milano

Теперь запрос

SELECT country FROM locations
GROUP BY country

приведет к:

--country--
 France
 Poland
 Italy

Однако следующий запрос

SELECT country, city FROM locations
GROUP BY country

... выдает ошибку в MS SQL, потому что как ваш компьютер может узнать, какой из трех французских городов "Лион", "Париж" или "Марсель" вы хотите прочитать в поле, чтобыправо «Франция»?

Чтобы исправить второй запрос, необходимо добавить эту информацию.Один из способов сделать это - использовать функции MAX () или MIN (), выбирая наибольшее или наименьшее значение среди всех кандидатов.MAX () и MIN () не только применимы к числовым значениям, но также сравнивают алфавитный порядок строковых значений.

SELECT country, MAX(city) FROM locations
GROUP BY country

приведет к:

--country-- --city--
 France      Paris
 Poland      Krakow
 Italy       Milano

или:

SELECT country, MIN(city) FROM locations
GROUP BY country

приведет к:

--country-- --city--
 France      Lyon
 Poland      Krakow
 Italy       Milano

Эти функции являются хорошим решением, если вы можете выбрать значение в любом из концов алфавитного (или числового) порядка.Но что, если это не так?Предположим, вам нужно значение с определенной характеристикой, например, начинающееся с буквы «М».Теперь все становится сложнее.

Единственное решение, которое я смог найти до сих пор, - это поместить весь ваш запрос в подзапрос и создать дополнительный столбец вне него руками:

SELECT
     countrylist.*,
     (SELECT TOP 1 city
     FROM locations
     WHERE
          country = countrylist.country
          AND city like 'M%'
     )
FROM
(SELECT country FROM locations
GROUP BY country) countrylist

приведет к:

--country-- --city--
 France      Marseille
 Poland      NULL
 Italy       Milano
3 голосов
/ 17 декабря 2016

Отличный вопрос @aryaxt - вы можете сказать, что это был отличный вопрос, потому что вы задавали его 5 лет назад, а я наткнулся на него сегодня, пытаясь найти ответ!

Я только что попытался отредактировать принятый ответ, чтобы включить это, но в случае, если мое редактирование не делает это в:

Если ваша таблица была не такой большой, и предполагая, что ваш первичный ключ представлял собой автоинкрементное целое число, вы могли бы сделать что-то вроде этого:

SELECT 
  table.*
FROM table
--be able to take out dupes later
LEFT JOIN (
  SELECT field, MAX(id) as id
  FROM table
  GROUP BY field
) as noDupes on noDupes.id = table.id
WHERE
  //this will result in only the last instance being seen
  noDupes.id is not NULL
2 голосов
/ 31 января 2019

Попробуйте

SELECT table.* FROM table 
WHERE otherField = 'otherValue'
GROUP BY table.fieldWantedToBeDistinct
limit x
2 голосов
/ 29 марта 2013

Вы можете сделать это с помощью предложения WITH.

Например:

WITH c AS (SELECT DISTINCT a, b, c FROM tableName)
SELECT * FROM tableName r, c WHERE c.rowid=r.rowid AND c.a=r.a AND c.b=r.b AND c.c=r.c

Это также позволяет выбирать только строки, выбранные в запросе WITH.

1 голос
/ 02 апреля 2015

Для SQL Server вы можете использовать dens_rank и дополнительные оконные функции, чтобы получить все строки И столбцы с дублированными значениями в указанных столбцах. Вот пример ...

with t as (
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r1' union all
    select col1 = 'c', col2 = 'b', col3 = 'a', other = 'r2' union all
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r3' union all
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r4' union all
    select col1 = 'c', col2 = 'b', col3 = 'a', other = 'r5' union all
    select col1 = 'a', col2 = 'a', col3 = 'a', other = 'r6'
), tdr as (
    select 
        *, 
        total_dr_rows = count(*) over(partition by dr)
    from (
        select 
            *, 
            dr = dense_rank() over(order by col1, col2, col3),
            dr_rn = row_number() over(partition by col1, col2, col3 order by other)
        from 
            t
    ) x
)

select * from tdr where total_dr_rows > 1

Здесь учитывается количество строк для каждой отдельной комбинации col1, col2 и col3.

0 голосов
/ 25 января 2018

Я бы предложил использовать

SELECT  * from table where field1 in 
(
  select distinct field1 from table
)

таким образом, если у вас есть одно и то же значение в field1 в нескольких строках, будут возвращены все записи.

...