Как удалить «дубликаты» строк из представления? - PullRequest
4 голосов
/ 10 июля 2009

У меня есть вид, который работал нормально, когда я присоединялся к основному столу:

LEFT OUTER JOIN OFFICE ON CLIENT.CASE_OFFICE = OFFICE.TABLE_CODE.

Однако мне нужно было добавить следующее соединение:

LEFT OUTER JOIN OFFICE_MIS ON CLIENT.REFERRAL_OFFICE = OFFICE_MIS.TABLE_CODE 

Хотя я добавил DISTINCT, я все еще получаю «дубликат» строки. Я говорю «дубликат», потому что вторая строка имеет другое значение.

Однако, если я изменю LEFT OUTER на INNER JOIN, я потеряю все строки для клиентов, у которых есть эти «дублирующие» строки.

Что я делаю не так? Как я могу удалить эти «дубликаты» строк из моего представления?


Примечание:

Этот вопрос не применяется в данном случае:

Как удалить повторяющиеся строки?

Ответы [ 5 ]

7 голосов
/ 10 июля 2009

DISTINCT не поможет вам, если в строках есть какие-либо другие столбцы. Очевидно, что в одной из таблиц, к которым вы присоединяетесь, имеется несколько строк для одной строки в другой таблице. Чтобы вернуть одну строку, вам нужно исключить другие несколько строк в таблице, к которой вы присоединяетесь.

Самый простой способ сделать это - усилить условие where или ограничение JOIN, чтобы присоединиться только к той записи, которую вы хотите. Обычно это требует определения правила, которое всегда будет выбирать «правильную» запись из другой таблицы.

Предположим, у вас есть простая проблема, такая как:

Person:  Jane
Pets: Cat, Dog

Если вы создадите простое соединение здесь, вы получите две записи для Джейн:

Jane|Cat
Jane|Dog

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

SELECT Person.Name, Pets.Name
FROM Person
  LEFT JOIN Pets pets1 ON pets1.PersonID = Person.ID
WHERE 0 = (SELECT COUNT(pets2.ID) 
             FROM Pets pets2
             WHERE pets2.PersonID = pets1.PersonID
                AND pets2.ID < pets1.ID);

Для этого применяется правило, ограничивающее запись «Домашние животные» в соединении с домашним животным с наименьшим идентификатором (сначала в таблице «Домашние животные»). Предложение WHERE по существу гласит: «если нет домашних животных, принадлежащих одному и тому же человеку с более низким значением ID».

Это даст один результат записи:

Jane|Cat

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

Возможно, вам придется переосмыслить содержание вашего представления и то, что вы пытаетесь достичь с помощью своего представления, если вы начинаете отфильтровывать действительные данные.

3 голосов
/ 10 июля 2009

То есть вы добавили внешнее левое соединение, соответствующее двум строкам? OFFICE_MIS.TABLE_CODE не является уникальным в этой таблице, я полагаю? вам нужно ограничить это объединение только одной строкой. Это зависит от того, какую строку вы ищете, но вы можете сделать что-то вроде этого ...

LEFT OUTER JOIN OFFICE_MIS ON 
  OFFICE_MIS.ID = /* whatever the primary key is? */
    (select top 1 om2.ID
    from OFFICE_MIS om2
    where CLIENT.REFERRAL_OFFICE = om2.TABLE_CODE
    order by om2.ID /* change the order to fit your needs */)
3 голосов
/ 10 июля 2009

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

2 голосов
/ 10 июля 2009

Вместо использования DISTINCT, вы можете использовать GROUP BY.

  • Группировка по всем полям, которые вы хотите вернуть как уникальные значения.
  • Используйте MIN / MAX / AVG или любую другую функцию, чтобы получить один результат для полей, которые могут возвращать несколько значений.

Пример:

SELECT Office.Field1, Client.Field1, MIN(Office.Field1), MIN(Client.Field2)  
FROM YourQuery  
GROUP BY Office.Field1, Client.Field1
1 голос
/ 10 июля 2009

Вы можете попробовать использовать Distinct Top 1 , но, как указал Хантер, если есть хотя бы один столбец, то он должен быть либо включен, либо если вам не нужен или нуждающийся в этом столбец. вероятно, следует удалить его. Любые другие предложения, вероятно, потребуют более конкретной информации.

РЕДАКТИРОВАТЬ: При использовании Distinct Top 1 вам необходимо иметь соответствующую группу по выражению . Вы бы действительно использовали часть Top 1 . Distinct там, потому что если есть связь для Top 1 , вы получите ошибку, не имея какого-либо способа избежать связи. Два наиболее распространенных способа, которые я видел, - это добавление Distinct к Top 1 , или вы можете добавить столбец к запросу, который является уникальным, чтобы sql мог выбрать, какую запись выбрать то, что в противном случае было бы галстуком.

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