【问题标题】:T-SQL query: find most frequent pair of valuesT-SQL 查询:查找最频繁的值对
【发布时间】:2019-02-21 23:58:35
【问题描述】:

我的文本列中的数值用分号分隔。我试图弄清楚如何获得出现在同一行中的最频繁的一对值。我在 Python Finding the most frequent occurrences of pairs in a list of lists 中找到了一个非常相似问题的解决方案,但我不知道如何使用 SQL 重写它在下面的示例中,它返回 2 和 3,因为这对在输入集中出现了 3 次:

Input rows      Output
----------      -------
';1;2;3;5'    |  '2;3'     
';2;3'        |  '1;2'
';3;4;5;1;2'  |  '1;3' 
';1;5;2'      |  '1;5'

原始数据:

【问题讨论】:

  • 请以文本格式发布您的数据,而不是图片。此外,您需要解释 940 和 10662 是如何预期的结果。
  • 阅读Is storing a delimited list in a database column really that bad?,您会看到很多理由说明为什么这个问题的答案是绝对是的!你有一个损坏的数据模型,这就是为什么它很难使用。如果你想规范你的数据库,这个任务将是微不足道的。
  • 您的 SQL Server 版本是多少?
  • 2017 开发人员
  • @AdamStawarek 为什么1;21;52;5 不在输出中? 2;33;2 是一样的吗?

标签: sql sql-server tsql


【解决方案1】:

您可以尝试以下方法。首先,使用OPENJSON(),获取所有可能的组合。当OPENJSON 解析 JSON 数组时,JSON 文本中元素的索引作为键(从 0 开始)返回。然后,用DENSE_RANK() 计算最频繁的对。

输入:

CREATE TABLE #Items (
   Id int,
   ItemValues varchar(max)
)
INSERT INTO #Items
   (Id, ItemValues)
VALUES   
   (1, '1;2;3;5'),
   (2, '2;3'),
   (3, '3;4;5;1;2'),
   (4, '1;5;2')

声明:

;WITH combinationsCTE AS (
   SELECT 
      CASE 
         WHEN s1.[value] <= s2.[value] THEN CONCAT(s1.[value], ';', s2.[value])
         ELSE CONCAT(s2.[value], ';', s1.[value]) 
      END AS PairValue
   FROM #Items i
   CROSS APPLY (SELECT [key], [value] FROM OPENJSON('["' +  REPLACE(i.ItemValues,';','","') + '"]')) s1
   CROSS APPLY (SELECT [key], [value] FROM OPENJSON('["' +  REPLACE(i.ItemValues,';','","') + '"]')) s2
   WHERE (s1.[key] < s2.[key])
), rankingCTE AS (
   SELECT 
      PairValue, 
      DENSE_RANK() OVER (ORDER BY COUNT(PairValue) DESC) AS PairRank
   FROM combinationsCTE
   GROUP BY PairValue
)
SELECT PairValue
FROM rankingCTE
WHERE PairRank = 1

输出:

PairValue
1;2
1;5
2;3
2;5

【讨论】:

  • 谢谢,这正是我所需要的
【解决方案2】:

先有拆分功能

CREATE FUNCTION Splitfn(@String varchar(8000), @Delimiter char(1))       
returns @temptable TABLE (items varchar(8000))       
as       
begin       
    declare @idx int       
    declare @slice varchar(8000)       

    select @idx = 1       
        if len(@String)<1 or @String is null  return       

    while @idx!= 0       
    begin       
        set @idx = charindex(@Delimiter,@String)       
        if @idx!=0       
            set @slice = left(@String,@idx - 1)       
        else       
            set @slice = @String       

        if(len(@slice)>0)  
            insert into @temptable(Items) values(@slice)       

        set @String = right(@String,len(@String) - @idx)       
        if len(@String) = 0 break       
    end   
return      

end

第二步获取单个字符串中的所有行

Declare @val Varchar(MAX); 
Select @val = COALESCE(@val + '; ' + YourColumn, YourColumn) 
        From YourTable

第三步,

SELECT TOP 1 items, count(*)
FROM dbo.Splitfn(@Val, ';')
WHERE LTRIM(RTRIM(items)) <> ''
GROUP BY items
ORDER BY Count(*) DESC

【讨论】:

  • 这可能是在 SQL 中拆分字符串的最糟糕的方法。如果使用 2016 或更高版本,最好的方法是使用内置的 string_split。对于较低版本,请阅读 Aaron Bertrand 的 Split strings the right way – or the next best way
  • 这将返回最频繁的值,但我的目的是获取最频繁的值对,因此对于每一行中的每组值,我需要找到所有值组合并返回在整个集合中最常见
猜你喜欢
  • 1970-01-01
  • 2013-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-19
  • 2022-06-15
  • 1970-01-01
  • 2021-12-09
相关资源
最近更新 更多