INNER JOIN содержит дублированные логины - PullRequest
0 голосов
/ 11 июля 2011

У меня есть таблица Users, которая содержит столбцы Login и Phone, и у меня есть таблица GeoPhone, которая содержит столбцы Mask и Region.

Телефон хранится как varchar ("+380981234567").Маска хранится как varchar («+38098»).Маски перекрываются, например, +380 и + 38098.

Мне нужно представление, которое объединяет таблицы Users и GeoPhone и назначает регион для каждого входа в систему с использованием самой подходящей маски.

Я написал оператор SQLниже, но результат содержит дублированные логины, и я не знаю, как этого избежать:

SELECT TOP (5000) 
    Users.Login, Users.Phone, GeoPhone.Region, LEN(GeoPhone.Mask) AS MaskLen
FROM   Users 
INNER JOIN GeoPhone ON LEFT(Users.Phone, LEN(GeoPhone.Mask)) = GeoPhone.Mask
ORDER BY Users.Login, MaskLen DESC

Пожалуйста, помогите улучшить его.

Ответы [ 3 ]

2 голосов
/ 11 июля 2011

Один из способов сделать это - использовать Cross Apply в SQL 2005 или более поздней версии.

SELECT  
    TOP (5000) Users.Login, 
    Users.Phone, 
    GeoPhone.Region, 
    LEN(GeoPhone.Mask) AS MaskLen 
FROM    Users
    CROSS APPLY
    (
        SELECT  TOP 1 Region,Mask
        FROM    geophone
        WHERE   LEFT (users.phone, Len(geophone.mask)) = geophone.mask 
        ORDER BY
            Len(geophone.mask) DESC
        ) geophone

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

Вот решение, использующее MAX () и его реально переносимое

SELECT TOP (5000) users.LOGIN, 
                  users.phone, 
                  geophone.region, 
                  Len(geophone.mask) AS masklen 
FROM   users 
       INNER JOIN geophone 
         ON LEFT(users.phone, Len(geophone.mask)) = geophone.mask 
       INNER JOIN (SELECT MAX(Len(geophone.mask)) maxlength, 
                          users.phone 
                   FROM   users 
                          INNER JOIN geophone 
                            ON LEFT(users.phone, Len(geophone.mask)) = 
                               geophone.mask 
                   GROUP  BY users.phone) t 
         ON t.phone = users.phone 
            AND t.maxlength = Len(geophone.mask) 

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

Вы также можете использовать ROW_NUMBER в SQL 2005 или более поздней версии

0 голосов
/ 11 июля 2011
select top (5000) 
    users.login, 
    users.phone, 
    geophone.region, 
    max(len(geophone.mask)) as masklen
from   users 
inner join geophone on left(users.phone, len(geophone.mask)) = geophone.mask
group by users.login, users.phone, geophone.region
order by users.login, masklen desc
0 голосов
/ 11 июля 2011

Вы можете удалить повторяющиеся результаты, используя ключевое слово DISTINCT. Однако, используйте только это ключевое слово, ваша логика на самом деле здорова, а не взломать ваши результаты. Это означает, что вы получаете только повторяющиеся результаты, потому что в вашей логике присоединения есть какая-то ошибка. Если допустимо иметь более одного результата, в вашем случае, для имени, тогда это допустимое использование.

SELECT DISTINCT TOP (5000) 
   Users.Login, 
   Users.Phone, 
   GeoPhone.Region, 
   LEN(GeoPhone.Mask) AS MaskLen
FROM Users 
   INNER JOIN GeoPhone ON LEFT(Users.Phone, LEN(GeoPhone.Mask)) = GeoPhone.Mask
ORDER BY Users.Login, MaskLen DESC
...