【问题标题】:Preventing Duplicates SQL Server 2008 and Classic ASP防止重复 SQL Server 2008 和经典 ASP
【发布时间】:2012-05-04 13:24:24
【问题描述】:

我正在从 Excel 导入记录,我想避免重复。在 ASP Classic 中,我编写了一个检查数据库是否存在重复项的函数。如果找到一个,它会在用户名的末尾添加一个数字并再次检查用户名是否唯一,例如 petejones 变为 petejones1。不幸的是,这个脚本太慢了,因为数据库有大约 150k 条记录,而且搜索唯一性需要很长时间。有没有办法在 T-SQL 的 SQL Server 2008 中直接做同样的事情?所以整个过程会很快。是否有制作独特的流程?

这是经典 ASP 中的函数。我知道有更好的方法可以做到这一点,所以不要嘲笑我的脚本。

FUNCTION CreateUniqueUsername(str)
  SET DbConn = Server.CreateObject("ADODB.connection")
  DbConn.Open DSN_LINK
  nCounter = 0
  Unique = ""
  IF InStr(str, "@") > 0 THEN
     strUsername = Left(str,InStr(str, "@")-1)
  ELSE
     strUsername = str
  END IF
  strUsername = FormatUsername(strUsername)
  strSQL = "SELECT UserName FROM Member WHERE UserName = '" & strUsername & "';"
  SET rs = DbConn.Execute(strSQL)
  IF rs.EOF AND rs.BOF THEN
    nFinalUsername = strUsername
  ELSE
    DO UNTIL Unique = true
      nCounter = nCounter + 1
      nFinalUsername = strUsername & nCounter
      strSQL2 = "SELECT UserName FROM Member WHERE UserName = '" & nFinalUsername & " ' "
      SET objRS = DbConn.Execute(strSQL2)
      IF objRS.EOF THEN
        Unique = true
      ELSE
        intCount = intCount
      END IF
    LOOP
    objRS.Close
    SET objRS = Nothing 
  END IF
  rs.Close
  SET rs = Nothing 
  SET DbConn = Nothing
  CreateUniqueUsername = nFinalUsername
END FUNCTION

FUNCTION FormatUsername(str)
  Dim OutStr
  IF ISNULL(str) THEN EXIT FUNCTION
  OutStr = lCase(Trim(str))
  OutStr = Replace(OutStr, "’", "")
  OutStr = Replace(OutStr, "”", "")
  OutStr = Replace(OutStr, "'","")
  OutStr = Replace(OutStr, "&","and")
  OutStr = Replace(OutStr, "'", "")
  OutStr = Replace(OutStr, "*", "")
  OutStr = Replace(OutStr, ".", "")
  OutStr = Replace(OutStr, ",", "")
  OutStr = Replace(OutStr, CHR(34),"")
  OutStr = Replace(OutStr, " ","")
  OutStr = Replace(OutStr, "|","")
  OutStr = Replace(OutStr, "&","")
  OutStr = Replace(OutStr, "[","")
  OutStr = Replace(OutStr, ";", "")
  OutStr = Replace(OutStr, "]","")
  OutStr = Replace(OutStr, "(","")
  OutStr = Replace(OutStr, ")","")
  OutStr = Replace(OutStr, "{","")
  OutStr = Replace(OutStr, "}","")
  OutStr = Replace(OutStr, ":","")
  OutStr = Replace(OutStr, "/","")
  OutStr = Replace(OutStr, "\","")
  OutStr = Replace(OutStr, "?","")
  OutStr = Replace(OutStr, "@","")
  OutStr = Replace(OutStr, "!","")
  OutStr = Replace(OutStr, "_","")
  OutStr = Replace(OutStr, "''","")
  OutStr = Replace(OutStr, "%","")
  OutStr = Replace(OutStr, "#","")
  FormatUsername = OutStr
END FUNCTION

由于我仍在学习 SQL,因此将不胜感激。

【问题讨论】:

    标签: sql sql-server sql-server-2008 asp-classic


    【解决方案1】:

    您可以在 SQL 中执行此操作。 这会寻找匹配的名称。如果找到匹配项,则获取当前附加到它的最大数量并加一。所以它最多只做两个SELECTS。当有很多重复时应该会更快。

    -- example table
    declare @Member table(ID int identity, UserName varchar(80))
    insert @Member values('Pete')
    insert @Member values('Jill')
    insert @Member values('Bob')
    insert @Member values('Sam')
    insert @Member values('Pete1')
    insert @Member values('Pete2')
    insert @Member values('Pete3')
    insert @Member values('Bob1')
    
    
    declare @UserName varchar(80), @FinalUserName varchar(80)
    set @UserName = 'Pete'
    
    set @FinalUserName = @UserName
    if(exists(SELECT 1 FROM @Member WHERE left(UserName,len(@UserName)) = @UserName))
    begin
        SELECT 
            @FinalUserName = @UserName + convert(varchar(12),max(substring(UserName,len(@UserName)+1,99)+1)) 
        FROM @Member 
        WHERE left(UserName,len(@UserName)) = @UserName
    end
    
    SELECT @FinalUserName 
    

    【讨论】:

    • 需要一些解释,只是发布代码并不能做出答案。顺便说一句,如果用户自己在他们请求的用户名末尾添加了一个数字,您的代码在所有情况下仍然有效吗?
    • 如果名称上附加了一个数字(例如 Pete500)并且如果存在“Pete500”,则将其更改为“Pete5001”。下一个“Pete”变成“Pete5002”——一个潜在的缺点。
    • +1 我想只要用户名是唯一的就没有问题。
    【解决方案2】:

    这个繁琐的表达式将检索第一个可用的用户名。如果存在同名用户并且用户名的其余部分是数字,则表达式将返回用户名与下一个数字连接。如果找不到这样的用户名,则表达式将返回此用户名。

    您可以将每个“@username”替换为实际值,或者最好使用SqlCommand.ExecuteScalar。 SqlCommand 将允许使用参数,这是更好的解决方案,因为您不必连接丑陋的字符串,并且它们会阻止使用 Sql Injection

    select @username 
         + isnull(convert (varchar (10),
             max (case when isnumeric (substring (m.Username, len (@username) + 1, 100)) = 1
                       then cast (substring (m.Username, len (@username) + 1, 100) as int) 
                       else (case when m.username = @username then 0 end)  
                       end) 
           + 1), '') UserName
    from @members m
    where m.username like @username + '%'
    

    这是Sql Fiddle testing ground。将set @username = 'aa' 替换为其他用户名以查看结果。

    【讨论】:

      【解决方案3】:

      这可以通过插入允许重复的临时表中来实现,然后从临时表转移到主表中,在此过程中解决重复。

      INSERT INTO MainTable (Column1, Column2, UniqueName)
      SELECT  Column1,
              Column2,
              UserName + ISNULL(CONVERT(VARCHAR, NULLIF(RowNumber, 0)), '') [UniqueName]
      FROM    (   SELECT  *, *, ROW_NUMBER() OVER (PARTITION BY UserName ORDER BY Column1) - 1 [Rownumber]
                  FROM    StagingTable
              ) staging
      

      此声明的重要部分是:

      ROW_NUMBER() OVER (PARTITION BY UserName ORDER BY Column1) - 1
      

      这给每一行一个行号(显然)。 PARTITION BY 就像一个 group by,这基本上意味着当用户名更改时行数将重置为 1。 ORDER BY 部分确定哪个重复的用户名应该是第 1 行,哪个应该是第 2 行等。ROW_NUMBER() 从 1 开始,所以我从中减去了 1,所以它从 0 开始。

      接下来就是将此行号与用户名结合起来:

      UserName + CONVERT(VARCHAR, RowNumber) [UniqueName]
      

      这将产生用户名0、用户名1、用户名2...所以下一步是让“用户名0”只显示为用户名,给出用户名、用户名1、用户名2的列表:

      UserName + ISNULL(CONVERT(VARCHAR, NULLIF(RowNumber, 0)), '') [UniqueName]
      

      这基本上说如果行号为 0 则变为 null,然后如果 this 的结果为 null 则变为 ''。

      【讨论】:

        猜你喜欢
        • 2010-09-23
        • 2015-09-01
        • 2013-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多