代码之家  ›  专栏  ›  技术社区  ›  Corey Sunwold

将列更新为不同的聚合值

  •  3
  • Corey Sunwold  · 技术社区  · 15 年前

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

    有两次输入同一电子邮件的实例,但有时输入的LNGV值不同。为了解决这个问题,我需要从所有副本中获取lngValue,并将它们分配给一个幸存的记录,然后删除其余的记录。

    警告:前方代码混乱

    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

    示例行1:

    lngContactFK:1
    lngValue:33
    裙子:“me@myaddress.com"

    示例第2行:
    lngInternetPK:2

    lngValue:40
    裙子:“me@myaddress.com"

    如果这两种情况合并在一起,则会得到理想的结果:
    lngInternetPK:1
    lngContactFK:1
    lngValue:41
    裙子:“me@myaddress.com"

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

    3 回复  |  直到 15 年前
        1
  •  3
  •   Quassnoi    15 年前

    SQL Server 缺少本机按位聚合,这就是为什么我们需要模拟它们。

    这里的主要思想是从 0 15 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
    

        2
  •  0
  •   Ben Griswold    15 年前

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

    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
    
        3
  •  0
  •   VoteCoffee    10 年前

    您可以在.NET中创建SQL Server聚合函数,然后在SQL Server内联中实现这些函数。我认为这至少需要SQLServer2005和VisualStudio2010。我使用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 CLR下配置目标CLR语言(如VB)
    2. 右键单击新项目并选择添加->新项目。。。

    现在,您可以在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->生成项目名称(如果生成失败,出现错误04018,则下载新版本的数据工具@ http://msdn.microsoft.com/en-US/data/hh297027 或转到菜单栏:工具->扩展和更新,然后在更新下选择更新用于Microsoft SQL Server更新用于数据库工具)
    2. 将编译后的DLL复制到C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn和C:\
    3. 注册DLL:

      从c:CLRTools.dll创建程序集[CLRTools],权限为\u SET=SAFE

    4. 在SQL中创建聚合:

      创建聚合[dbo]。[AggregateBitwiseOR](@value INT) 外部名称[CLRTools]。[CLRTools.AggregateBitwiseOR];

    如果出现错误“外部”附近的语法不正确”,请使用以下命令更改数据库兼容性级别:

    对于SQL Server 2005:EXEC sp_dbcmptlevel“DatabaseName”,90

    1. 测试您的代码:

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