Удаление дубликатов из SQL-запроса (а не просто «использовать разные») - PullRequest
13 голосов
/ 04 февраля 2011

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

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?

Ответы [ 5 ]

18 голосов
/ 04 февраля 2011

Произвольно выбирая минимальный 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;
2 голосов
/ 04 февраля 2011

Ваш вопрос немного запутан; Вы хотите показать только одну строку для каждого пользователя или хотите показать строку для каждого изображения, но подавить повторяющиеся значения в поле 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 уровня предприятия имеют нечто подобное.

1 голос
/ 04 февраля 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
1 голос
/ 04 февраля 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;
0 голосов
/ 04 февраля 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)

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

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