3

我正在创建一个用于“合并”和删除表中重复行的脚本。该表包含地址信息,并使用整数字段将有关电子邮件的信息存储为位标志(列名 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"

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

4

3 回答 3

3

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

这里的主要思想是从 到 生成一组位015对于每个位,将位掩码应用于值并选择MAX(这将为给定位提供OR一个),然后选择SUM(这将合并位掩码)。

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

;WITH   bits AS
        (
        SELECT  0 AS b
        UNION ALL
        SELECT  b + 1
        FROM    bits
        WHERE   b < 15
        ),
        v AS
        (
        SELECT  i.*,
                (
                SELECT  SUM(value)
                FROM    (
                        SELECT  MAX(lngValue & POWER(2, b)) AS value
                        FROM    tblmInternet ii
                        CROSS JOIN
                                bits
                        WHERE   ii.lngContactFK = i.lngContactFK
                                AND ii.strAddress = i.strAddress
                        GROUP BY
                                b
                        ) q
                ) AS lngNewValue
        FROM    (
                SELECT  ii.*, ROW_NUMBER() OVER (PARTITION BY lngContactFK, strAddress ORDER BY lngInternetPK) AS rn
                FROM    tblmInternet ii
                ) i
        WHERE   rn = 1
        )
UPDATE  v
SET     lngValue = lngNewValue;

;WITH    v AS
        (
        SELECT  ii.*, ROW_NUMBER() OVER (PARTITION BY lngContactFK, strAddress ORDER BY lngInternetPK) AS rn
        FROM    tblmInternet ii
        )
DELETE  v
WHERE   rn > 1

请参阅我的博客中的这篇文章以获得更详细的解释:

于 2009-07-13T17:13:34.807 回答
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
于 2009-07-13T16:48:46.867 回答
0

您可以在 .NET 中创建 SQL Server 聚合函数,然后可以在 SQL Server 内联中实现这些函数。我认为这至少需要 SQL Server 2005 和 Visual Studio 2010。我使用 Visual Studio 2013 社区版(甚至免费用于商业用途)与 .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 -> SQL Server 数据库项目
  2. 右键单击新项目并选择属性
  3. 在项目设置下配置目标 SQL Server 版本
  4. SQL CLR下配置目标CLR语言(如VB)
  5. 右键单击新项目并选择 Add -> New Item...
  6. 弹出对话框时,选择 SQL Server -> SQL CLR VB -> SQL CLR VB Aggregate

现在您可以在 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 -> Build ProjectName(如果构建失败并出现错误 04018,则下载新版本的数据工具 @ http://msdn.microsoft.com/en-US/data/hh297027或通过转到菜单栏:工具 -> 扩展和更新,然后在更新下选择 Microsoft SQL Server Update For Database Tooling 的更新)
  2. 将已编译的 DLL 复制到 C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn 和 C:\
  3. 注册 DLL:

    使用 PERMISSION_SET = SAFE 从“c:CLRTools.dll”创建程序集 [CLRTools]

  4. 在 SQL 中创建聚合:

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

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

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

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

  1. 测试你的代码:

    从 Bar 中选择 dbo.AggregateBitwiseOR(Foo) AS Foo

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

于 2015-02-11T17:33:07.027 回答