【问题标题】:How to find duplicate sets of values in column SQL如何在列 SQL 中查找重复的值集
【发布时间】:2021-01-26 10:30:31
【问题描述】:

我在 SQL Server 中有一个这样的数据库表:

  +----+--------+
  | ID | Number |
  +----+--------+
  |  1 |      4 |
  |  2 |      2 |
  |  3 |      6 |
  |  4 |      5 |
  |  5 |      3 |
  |  6 |      2 |
  |  7 |      6 |
  |  8 |      4 |
  |  9 |      5 |
  | 10 |      1 |
  | 11 |      6 |
  | 12 |      4 |
  | 13 |      2 |
  | 14 |      6 |
  +----+--------+

我想在列号中获取与最后一行或最后2行或最后3行或....相同的行的所有值,当找到这些值时,将继续获取值​​接下来出现的并数其出现的次数。

结果输出如下:

  1. 如果与最后一行相同:
  • 我们看到 Number 列中 6 旁边的数字是 4 和 5。

  • 时间出现在第 6,4 对的列数为 2,第 6,5 对为 1。

     +---------------------+-------------------------+--------------+
     | "Condition to find" | "Next Number in column" | Times appear |
     +---------------------+-------------------------+--------------+
     |                   6 |                       5 |            1 |
     |                   6 |                       4 |            2 |
     +---------------------+-------------------------+--------------+
    
  1. 如果与最后两行相同:

    +---------------------+-------------------------+--------------+
    | "Condition to find" | "Next Number in column" | Times appear |
    +---------------------+-------------------------+--------------+
    | 2,6                 |                       5 |            1 |
    | 2,6                 |                       4 |            1 |
    +---------------------+-------------------------+--------------+
    
  2. 如果与最后3行相同:

    +---------------------+-------------------------+--------------+
    | "Condition to find" | "Next Number in column" | Times appear |
    +---------------------+-------------------------+--------------+
    | 4,2,6               |                       5 |            1 |
    +---------------------+-------------------------+--------------+
    
  3. 如果最后 4,5,6...行,查找直到出现时间返回 0

    +---------------------+-------------------------+--------------+
    | "Condition to find" | "Next Number in column" | Times appear |
    +---------------------+-------------------------+--------------+
    | 6,4,2,6             |                         |              |
    +---------------------+-------------------------+--------------+
    

任何想法如何得到这个。非常感谢!

【问题讨论】:

  • SQL Server 版本是多少?
  • 我使用的是 sql server 2008!

标签: sql sql-server duplicates


【解决方案1】:

这是一个使用“Lead”函数的答案 - 该函数(一旦排序)从前面的特定行数中获取一个值。

它将您的表格转换为 1 个数字,并在每行中包含接下来的 3 个数字。

然后您可以加入这些列以获取数字等。

CREATE TABLE #Src (Id int PRIMARY KEY, Num int)
INSERT INTO #Src (Id, Num) VALUES
  ( 1, 4),
  ( 2, 2),
  ( 3, 6),
  ( 4, 5),
  ( 5, 3),
  ( 6, 2),
  ( 7, 6),
  ( 8, 4),
  ( 9, 5),
  (10, 1),
  (11, 6),
  (12, 4),
  (13, 2),
  (14, 6)

CREATE TABLE #SrcWithNext (Id int PRIMARY KEY, Num int, Next1 int, Next2 int, Next3 int)

-- First step - use LEAD to get the next 1, 2, 3 values

INSERT INTO #SrcWithNext (Id, Num, Next1, Next2, Next3)
SELECT      ID, Num, 
            LEAD(Num, 1, NULL) OVER (ORDER BY Id) AS Next1,
            LEAD(Num, 2, NULL) OVER (ORDER BY Id) AS Next2,
            LEAD(Num, 3, NULL) OVER (ORDER BY Id) AS Next3
    FROM    #Src

SELECT * FROM #SrcWithNext

/* Find number with each combination */

-- 2 chars
SELECT  A.Num, A.Next1, COUNT(*) AS Num_Instances
FROM    (SELECT DISTINCT Num, Next1 FROM #SrcWithNext) AS A
        INNER JOIN #SrcWithNext AS B ON A.Num = B.Num AND A.Next1 = B.Next1
WHERE   A.Num <= B.Num
GROUP BY A.Num, A.Next1
ORDER BY A.Num, A.Next1

-- 3 chars
SELECT  A.Num, A.Next1, A.Next2, COUNT(*) AS Num_Instances
FROM    (SELECT DISTINCT Num, Next1, Next2 FROM #SrcWithNext) AS A
        INNER JOIN #SrcWithNext AS B 
            ON A.Num = B.Num 
            AND A.Next1 = B.Next1 
            AND A.Next2 = B.Next2
WHERE   A.Num <= B.Num
GROUP BY A.Num, A.Next1, A.Next2
ORDER BY A.Num, A.Next1, A.Next2

-- 4 chars
SELECT  A.Num, A.Next1, A.Next2, A.Next3, COUNT(*) AS Num_Instances
FROM    (SELECT DISTINCT Num, Next1, Next2, Next3 FROM #SrcWithNext) AS A
        INNER JOIN #SrcWithNext AS B 
            ON A.Num = B.Num 
            AND A.Next1 = B.Next1 
            AND A.Next2 = B.Next2
            AND A.Next3 = B.Next3
WHERE   A.Num <= B.Num
GROUP BY A.Num, A.Next1, A.Next2, A.Next3
ORDER BY A.Num, A.Next1, A.Next2, A.Next3

这里有一个db<>fiddle 来查看。

注意事项

  • A.Num
  • 此答案可找到所有组合。要过滤,它目前需要过滤为单独的列,例如,您将过滤 Num = 2 AND Next1 = 6,而不是 2,6。然后随意执行各种文本/字符串连接功能,为您首选的搜索/过滤方法创建参考。

【讨论】:

  • 非常感谢!它大致返回我需要的东西,但有没有更短的方法?
  • 可能有,但我尽量保持简单,因为我不确定你想用这个函数做什么(例如,你是否只要求一个组合?或者你是级联问题,例如,找到最常见的值,然后找到最常见的值对等)。因此,您有一些工作要做。因此采用了“保持简单”的方法。
【解决方案2】:

嗯。 . .我在想您想将“要查找的模式”创建为字符串。可惜string_agg()不是开窗函数,但可以使用apply

select t.*, p.*
from t cross apply
     (select string_agg(number, ',') within group (order by id) as pattern
      from (select top (3) t2.*
            from t t2
            where t2.id <= t.id
            order by t2.id desc
           ) t2
     ) p;

您可以将“3”更改为您想要的任意行数。

然后您可以使用它来识别模式匹配和聚合的行:

with tp as (
       select t.*, p.*
       from t cross apply
            (select string_agg(number, ',') within group (order by id) as pattern
             from (select top (3) t2.*
                   from t t2
                   where t2.id <= t.id
                   order by t2.id desc
                  ) t2
            ) p
       )
select pattern_to_find, next_number, count(*)
from (select tp.*,
             first_value(pattern) over (order by id desc) as pattern_to_find,
             lead(number) over (order by id) as next_number
      from tp
     ) tp
where pattern = pattern_to_find
group by pattern_to_find, next_number;

Here 是一个 dbfiddle。

如果您使用的是旧版本的 SQL Server(不支持 string_agg() 的版本),您可以使用 lag() 计算 pattern

with tp as (
       select t.*,
              concat(lag(number, 2) over (order by id), ',',
                     lag(number, 1) over (order by id), ',',
                     number
                    ) as pattern
       from t
      )

实际上,如果您有大量数据,知道哪个更快——apply 版本或lag() 版本会很有趣。我怀疑lag() 可能更快。

编辑:

在不受支持的 SQL Server 版本中,您可以使用以下方式获取模式:

select t.*, p.*
from t cross apply
     (select (select cast(number as varchar(255)) + ','
              from (select top (3) t2.*
                    from t t2
                    where t2.id <= t.id
                    order by t2.id desc
                   ) t2
              order by t2.id desc
              for xml path ('')
             ) as pattern
     ) p

您可以对lead() 使用类似的逻辑。

【讨论】:

  • 感谢您的回答,这正是我所期望的,但我收到此错误“未启用并行数据仓库 (PDW) 功能。”。可能是我的 SQL Server 版本不支持!。
  • @SBPAE 。 .我不清楚这些功能是如何在这个查询中使用的。正如 SQL Fiddle 所示,此代码有效。此答案中使用的窗口函数在所有受支持的 SQL Server 版本中。
  • @SBPAE 。 . .窗口函数在所有支持的 SQL Server 版本中可用。您应该使用受支持的版本。
  • 当我使用应用版本时,我得到这个“'string_agg' 不是一个可识别的内置函数名称”,而使用 lag() 版本,我得到“并行数据仓库 (PDW ) 功能未启用。”。
  • 是的,我正在下载新的 SQL 版本!
【解决方案3】:

我试图通过将“数字”列转换为字符串来解决这个问题。 这是我的代码使用输入“最后选择的行数”的函数: (注意主表的名字是“test”)

      create function duplicate(@nlast int)
            returns @temp table (RowNumbers varchar(20), Number varchar(1))
            as 
            begin
                
    
    declare @num varchar(20)
                set @num=''
                declare @count int=1
                while @count <= (select count(id) from test)
                begin
                  set @num =  @num + cast((select Number from test where @count=ID) as varchar(20)) 
                  set @count=@count+1
                    end
                    declare @lastnum varchar(20)
                    set @lastnum= (select RIGHT(@num,@nlast))
                    declare @count2 int=1
                    while @count2 <= len(@num)-@nlast
                    begin
                          if (SUBSTRING(@num,@count2,@nlast) = @lastnum)
                            begin
                              insert into @temp
                              select @lastnum ,SUBSTRING(@num,@count2+@nlast,1)
                          end 
                  set @count2=@count2+1
                end
            return
        end 
go 
select RowNumbers AS "Condition to find",  Number AS "Next Number in column" , COUNT(Number) AS "Times appear" from dbo.duplicate(2) 
group by Number, RowNumbers

【讨论】:

    猜你喜欢
    • 2023-02-02
    • 2011-02-21
    • 1970-01-01
    • 1970-01-01
    • 2012-12-08
    • 2011-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多