将列更新为不同的聚合值

时间:2009-07-10 23:04:13

标签: tsql duplicate-removal

我正在创建一个脚本,用于“合并”并从表中删除重复的行。该表包含地址信息,并使用整数字段将有关电子邮件的信息存储为位标志(列名lngValue)。例如,lngValue& 1 == 1表示其主要地址。

有两次输入相同电子邮件的情况,但有时会使用不同的lngValues。要解决这个问题,我需要从所有重复项中获取lngValue并将它们分配给一个幸存的记录并删除其余的记录。

到目前为止,我最头疼的是记录的“合并”。我想要做的是将重复记录的按位或所有lngValues放在一起。这是我到目前为止所做的,它只能按位或一起找到所有lngValues的值。

警告:前面的代码混乱

declare @duplicates table
(
lngInternetPK int,
lngContactFK int,
lngValue int
)

insert into @duplicates (lngInternetPK, lngContactFK, lngValue) 
(
select  tblminternet.lngInternetPK, tblminternet.lngContactFK, tblminternet.lngValue   from tblminternet  inner join 
(select strAddress, lngcontactfk, count(*) as count from tblminternet where lngValue & 256 <> 256 group by strAddress, lngcontactfk) secondemail
On tblminternet.strAddress = secondemail.strAddress and
tblminternet.lngcontactfk = secondemail.lngcontactfk 
where count > 1 and tblminternet.strAddress is not null and tblminternet.lngValue & 256 <> 256 --order by lngContactFK, strAddress
)

update @duplicates set lngValue = t.val

from 
                (select (sum(dupes.lngValue) & 65535) as val from 
                    (select  here.lngInternetPK,                     here.lngContactFK, here.lngValue from tblminternet here  inner join 
                    (select strAddress, lngcontactfk, count(*) as count from tblminternet where lngValue & 256 <> 256 group by strAddress, lngcontactfk) secondemail
                    On here.strAddress = secondemail.strAddress     and
                    here.lngcontactfk = secondemail.lngcontactfk 
                    where count > 1 and here.strAddress is not      null and here.lngValue & 256 <> 256) dupes, tblminternet this

                where this.lngContactFK = dupes.lngContactFK
                ) t
where lngInternetPK in (select lngInternetPK from @duplicates)    

编辑:
  根据要求,这里有一些示例数据:

表名:tblminternet
栏目名称:
lngInternetPK
lngContactFK
lngValue
strAddress

示例第1行:
lngInternetPK:1
lngContactFK:1
lngValue:33
strAddress:“me@myaddress.com”

示例第2行:
lngInternetPK:2
lngContactFK:1
lngValue:40
strAddress:“me@myaddress.com”

如果这两个合并在这里是期望的结果:
lngInternetPK:1
lngContactFK:1
lngValue:41
strAddress:“me@myaddress.com”

其他必要规则:
每个联系人都可以有多封电子邮件,但每封电子邮件行必须是不同的(每封电子邮件只能显示为一行)。

3 个答案:

答案 0 :(得分:3)

SQL Server缺少原生的按位聚合,这就是我们需要模仿它们的原因。

这里的主要思想是从015生成一组位,每个位将位掩码应用于值并选择MAX(这将给我们一个{对于给定位,{1}},然后选择OR(将合并位掩码)。

我们只是使用新值SUM更新任何给定lngInternetPK的第一个(lngContactFK, strValue),并删除所有重复项。

lngValue

有关更详细的说明,请参阅我的博客中的这篇文章:

答案 1 :(得分:0)

我相信以下查询可以满足您的需求。此例程假定每个联系人最多有两个重复地址。如果每个联系人有多个重复,则必须修改查询。我希望这会有所帮助。

Declare @tblminternet 
Table 
( lngInternetPK int,   
  lngContactFK int,  
  lngValue int, 
  strAddress varchar(255)
)

Insert Into @tblminternet 
select 1, 1, 33, 'me@myaddress.com' 
union
select 2, 1, 40, 'me@myaddress.com'
union 
select 3, 2, 33, 'me@myaddress2.com'
union 
select 4, 2, 40, 'me@myaddress2.com'
union 
select 5, 3, 2, 'me@myaddress3.com'

--Select * from @tblminternet

Select  Distinct   
    A.lngContactFK , 
    A.lngValue | B.lngValue as 'Bitwise OR', 
    A.strAddress
From @tblminternet A, @tblminternet B
Where A.lngContactFK = B.lngContactFK
And A.strAddress = B.strAddress
And A.lngInternetPK != B.lngInternetPK

答案 2 :(得分:0)

您可以在.NET中创建SQL Server聚合函数,然后可以在SQL Server内联中实现。我认为这需要最少的SQL Server 2005和Visual Studio 2010.我使用Visual Studio 2013 Community Edition(甚至免费用于商业用途)与.NET 2和SQL Server 2005一起使用。

请参阅MSDN文章:https://msdn.microsoft.com/en-us/library/91e6taax(v=vs.90).aspx

首先,您需要在SQL Server中启用CLR功能:https://msdn.microsoft.com/en-us/library/ms131048.aspx

sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'clr enabled', 1;
GO
RECONFIGURE;
GO
  1. 创建SQL Server - &gt; SQL Server数据库项目
  2. 右键单击新项目,然后选择“属性”
  3. 在“项目设置”
  4. 下配置目标SQL Server版本
  5. 在SQL CLR(例如VB)
  6. 下配置目标CLR语言
  7. 右键点击新项目,然后选择添加 - &gt;新物品......
  8. 弹出对话框时,选择SQL Server - &gt; SQL CLR VB - &gt; SQL CLR VB聚合
  9. 现在您可以在VB中编写您的按位代码:

    Imports System
    Imports System.Data
    Imports System.Data.SqlClient
    Imports System.Data.SqlTypes
    Imports Microsoft.SqlServer.Server
    
    
    <Serializable()> _
    <Microsoft.SqlServer.Server.SqlUserDefinedAggregate(Format.Native)> _
    Public Structure AggregateBitwiseOR
    
        Private CurrentAggregate As SqlTypes.SqlInt32
    
        Public Sub Init()
            CurrentAggregate = 0
        End Sub
    
        Public Sub Accumulate(ByVal value As SqlTypes.SqlInt32)
            'Perform Bitwise OR against aggregate memory
            CurrentAggregate = CurrentAggregate OR value
        End Sub
    
        Public Sub Merge(ByVal value as AggregateBitwiseOR)
            Accumulate(value.Terminate())
        End Sub
    
        Public Function Terminate() As SqlInt32
            Return CurrentAggregate
        End Function
    
    End Structure
    

    现在部署它:https://msdn.microsoft.com/en-us/library/dahcx0ww(v=vs.90).aspx

    1. 使用菜单栏构建项目:Build - &gt;构建ProjectName(如果构建失败,错误04018,则下载新版本的数据工具@ http://msdn.microsoft.com/en-US/data/hh297027或转到菜单栏:工具 - &gt;扩展和更新,然后在更新下选择更新Microsoft SQL Server数据库工具更新)
    2. 将已编译的DLL复制到C:\ Program Files \ Microsoft SQL Server \ MSSQL.1 \ MSSQL \ Binn和C:\
    3. 注册DLL:

      从'c:CLRTools.dll'创建汇编[CLRTools] WITH PERMISSION_SET = SAFE

    4. 在SQL中创建聚合:

      CREATE AGGREGATE [dbo]。[AggregateBitwiseOR](@ value INT)     退货INT     外部名称[CLRTools]。[CLRTools.AggregateBitwiseOR];

    5. 如果您收到错误“EXTERNAL'附近的语法不正确”,请使用以下命令更改数据库兼容级别:

      对于SQL Server 2005:EXEC sp_dbcmptlevel'DatabaseName',90

      对于SQL Server 2008:EXEC sp_dbcmptlevel'DatabaseName',100

      1. 测试您的代码:

        SELECT dbo.AggregateBitwiseOR(Foo)AS Foo FROM Bar

      2. 我发现这篇文章很有用:http://www.codeproject.com/Articles/37377/SQL-Server-CLR-Functions