Удаление дубликатов из SQL-запроса (а не только использование отдельных)

Наверное, все просто, вот мой вопрос:

SELECT DISTINCT U.NAME, P.PIC_ID
FROM USERS U, PICTURES P, POSTINGS P1
WHERE U.EMAIL_ID = P1.EMAIL_ID AND P1.PIC_ID = P.PIC_ID AND P.CAPTION LIKE '%car%';

но это удалит только дубликаты, в которых строка имеет одно и то же имя u.name и p.pic_id. Я хочу, чтобы, если есть какие-либо дубликаты имен, он просто не учитывает другие строки. Это странный запрос, но в целом, как я могу применить отдельный столбец к одному столбцу предложения SELECT?


person Dave    schedule 03.02.2011    source источник
comment
какой из нескольких P.PIC_ID вы хотите использовать с одним U.NAME?   -  person Kris Ivanov    schedule 04.02.2011


Ответы (5)


Произвольное решение оставить минимальный PIC_ID. Также избегайте использования неявного синтаксиса соединения.

SELECT U.NAME, MIN(P.PIC_ID)
    FROM USERS U
        INNER JOIN POSTINGS P1
            ON U.EMAIL_ID = P1.EMAIL_ID
        INNER JOIN PICTURES P
            ON P1.PIC_ID = P.PIC_ID
    WHERE P.CAPTION LIKE '%car%'
    GROUP BY U.NAME;
person Joe Stefanelli    schedule 03.02.2011
comment
В зависимости от бизнес-модели вы можете использовать MIN или MAX (очевидно, не оба одновременно). - person Naufal; 01.08.2017
comment
Что делать, если P.PIC_ID было логическим значением? Я имею в виду, что я хотел бы выбрать первое значение, в котором агрегированный столбец имеет логический тип. Скажем SELECT U.NAME, MIN(P.DELETED) или несколько. - person Andrii Abramov; 12.04.2021

Ваш вопрос сбивает с толку; вы хотите отображать только одну строку для каждого пользователя или вы хотите отображать строку для каждого изображения, но подавлять повторяющиеся значения в поле U.NAME? Я думаю, ты хочешь второй; если нет, то для первого есть множество ответов.

Отображать ли повторяющиеся значения - это логика отображения, для которой SQL на самом деле не был разработан. Вы можете использовать курсор в цикле для обработки результатов строка за строкой, но вы сильно потеряете производительность. Если у вас есть «умный» интерфейсный язык, такой как язык .NET или Java, любую конструкцию, в которую вы помещаете эти данные, можно дешево манипулировать, чтобы подавить повторяющиеся значения перед окончательным отображением их в пользовательском интерфейсе.

Если вы используете Microsoft SQL Server и преобразование ДОЛЖНО выполняться на уровне данных, вы можете рассмотреть возможность использования CTE (вычисляемого табличного выражения) для хранения начального запроса, а затем выбрать значения из каждой строки CTE в зависимости от того, столбцы в предыдущей строке содержат те же данные. Он будет более производительным, чем курсор, но в любом случае будет немного неаккуратно. Наблюдать:

USING CTE (Row, Name, PicID)
AS
(
    SELECT ROW_NUMBER() OVER (ORDER BY U.NAME, P.PIC_ID),
       U.NAME, P.PIC_ID
    FROM USERS U
        INNER JOIN POSTINGS P1
            ON U.EMAIL_ID = P1.EMAIL_ID
        INNER JOIN PICTURES P
            ON P1.PIC_ID = P.PIC_ID
    WHERE P.CAPTION LIKE '%car%'
    ORDER BY U.NAME, P.PIC_ID 
)
SELECT
    CASE WHEN current.Name == previous.Name THEN '' ELSE current.Name END,
    current.PicID
FROM CTE current
LEFT OUTER JOIN CTE previous
   ON current.Row = previous.Row + 1
ORDER BY current.Row

Приведенный выше пример специфичен для TSQL; не гарантируется, что он будет работать в любом другом DBPL, таком как PL / SQL, но я думаю, что в большинстве SQL-движков корпоративного уровня есть нечто подобное.

person KeithS    schedule 03.02.2011

Вам нужно указать запросу, какое значение выбрать для других столбцов, MIN или MAX кажутся подходящими вариантами.

 SELECT
   U.NAME, MIN(P.PIC_ID)
 FROM
   USERS U,
   PICTURES P,
   POSTINGS P1
 WHERE
   U.EMAIL_ID = P1.EMAIL_ID AND
   P1.PIC_ID = P.PIC_ID AND
   P.CAPTION LIKE '%car%'
 GROUP BY
   U.NAME;
person Brandon Horsley    schedule 03.02.2011
comment
Не думаю, что он этого хочет. Я думаю, ему нужны все изображения, но в случаях, когда у одного пользователя есть несколько изображений, он не хочет, чтобы имя пользователя повторялось в списке. - person KeithS; 04.02.2011
comment
Не поощряйте использование подразумеваемого синтаксиса соединения. Если вы показываете ему, как что-то делать, покажите ему, как это делать правильно. - person HLGEM; 04.02.2011
comment
@HLGEM, насколько мне известно, что не так с подразумеваемым синтаксисом? Некоторые драйверы ODBC (например, D3 от tigerlogic) поддерживают только подразумеваемый синтаксис. - person Brandon Horsley; 04.02.2011
comment
@Brandon Horsley: этот подразумеваемый синтаксис JOIN устарел и неясен - цель того, что вы пытаетесь сделать, не видна из вашего запроса. Таким образом, стандартизированный синтаксис ANSI JOIN намного яснее, поскольку вы явно указываете, какой тип JOIN вы хотите (INNER, LEFT OUTER и т. Д.), И указываете, какие столбцы присоединять непосредственно там (не спрятаны где-то дальше в предложении WHERE , смешанный с другими условиями WHERE, которые не имеют ничего общего с JOIN) - person marc_s; 04.02.2011
comment
Неявный синтаксис @Brandon Horsley также подвержен случайным перекрестным соединениям и проблемам в обслуживании, когда вам нужно перейти на внешние соединения, поскольку смешивание неявных и явных соединений может дать неверные результаты (и на сервере SQL, по крайней мере, неявный синтаксис внешнего соединения нарушен в настоящее время и не рекомендуется). И если вы планировали перекрестное соединение, сопровождающий не знает, правда ли это или это была случайность, поскольку случайные соединения довольно часто встречаются в сложных запросах. Ни в коем случае нельзя писать код с использованием неявных объединений, и если инструмент поддерживает только это, пора избавиться от этого инструмента. - person HLGEM; 04.02.2011
comment
Неявные соединения также устарели почти на 20 лет. Давно прошло то время, когда их нельзя было использовать, и, конечно, никогда не следует поощрять их на подобном сайте, где мы привязываемся к обучению передовым методам. - person HLGEM; 04.02.2011

Если я вас правильно понимаю, вы хотите перечислить, чтобы исключить дубликаты только в одном столбце, внутреннее соединение с подвыборкой

select u.* [whatever joined values]
from users u
inner join
(select name from users group by name having count(*)=1) uniquenames
on uniquenames.name = u.name
person Xhalent    schedule 03.02.2011

Если я вас правильно понял, вам нужен список всех изображений с одинаковыми именами (и их разными идентификаторами), чтобы их имя повторялось в таблице более одного раза. Я думаю, это поможет:

SELECT U.NAME, P.PIC_ID
FROM USERS U, PICTURES P, POSTINGS P1
WHERE U.EMAIL_ID = P1.EMAIL_ID AND P1.PIC_ID = P.PIC_ID AND U.Name IN (
SELECT U.Name 
FROM USERS U, PICTURES P, POSTINGS P1
WHERE U.EMAIL_ID = P1.EMAIL_ID AND P1.PIC_ID = P.PIC_ID AND P.CAPTION LIKE '%car%';
GROUP BY U.Name HAVING COUNT(U.Name) > 1)

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

person Chris B. Behrens    schedule 03.02.2011
comment
Не поощряйте использование подразумеваемого синтаксиса соединения. Если вы показываете ему, как что-то делать, покажите ему, как это делать правильно. - person HLGEM; 04.02.2011
comment
Я подумал об этом, но я хотел решить именно ту проблему, над которой он работал. - person Chris B. Behrens; 04.02.2011