2011-07-11 62 views
0

我有表包含列登录和电话的用户,并且我有包含列掩码和区域的表格GeoPhone。INNER JOIN结果包含重复登录

电话存储为varchar(“+380981234567”)。掩码存储为varchar(“+38098”)。面具重叠,例如+380和+38098。

我需要一个加入用户和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 

请帮助完善它。

+0

你想,如果你有两个记录在地震检波器,其中有一个为“最长匹配的面具”领带做的事,而且SQL服务器的什么版本你有? –

回答

2

一种方法是在SQL 2005或更高版本中使用Cross Apply。

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(解决方​​案)及其realtively便携式

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) 

但是如果两个地震检波器中的行长度最长,两个结果都会返回。我不知道这对你是好还是坏。

您也可以在SQL 2005使用ROW_NUMBER或更高版本

+0

“不支持CROSS APPLY SQL结构或语句。”我在部署时在我的开发服务器和MS SQL 2005上使用MS SQL 2005 Express。 – Denis

+0

@Denis我增加了一个更便携的版本,但请注意关系的问题 –

+0

@Denis我认为你可能在兼容模式下运行。你可以通过运行'sp_dbcmptlevel'YourDbname''来检查它。如果它的80那么这意味着SQL 2005中的某些东西将不起作用。 –

0

您可以使用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 
+0

我不认为这符合OP的“每个通过最长匹配的面膜”。要求 –

+0

我以前试过但没有工作。 – Denis

0
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

我在发布第一个问题之前试过这个,这对我不起作用,因为JOIN为同一登录返回不同的登录电话区域对,GROUP BY不会过滤这一点。 – Denis