【问题标题】:T-SQL: How can I match itemsets with transaction lists?T-SQL:如何将项集与事务列表匹配?
【发布时间】:2014-09-03 17:54:54
【问题描述】:

我有一个包含项目列表(= 交易)的表,第二个包含项目子组(= 项目集)的表。 结果我需要一个新表(=结果集)显示包含表“项目集”中的项目的所有事务,例如项目“a”和“f”是事务 1 和 5 的一部分,“a”是事务 1、2、4、5 的一部分,依此类推......

如何使用 T-SQL 解决这个问题?

table1:交易

TID 项目列表 1 a,c,f 2个 3 c,f,g,h,l 4 b、a、c 5 楼

table2:项目集

SID item1 item2 item3 ......... item n 1个 2 升 3 厘米 4 英尺

结果集:

SID TID 1 1 1 2 1 4 1 5 2 3 3 3 4 1 4 5

【问题讨论】:

  • 您的数据库设计存在严重缺陷,应该重构。我不会用 T-SQL 解决这个问题,而是重新设计你的数据库。您将继续面临这种设计的问题。
  • 是垂直表更好还是二进制矩阵更好?你会提出什么建议?
  • Hrrm,我不太清楚你所说的那些东西是什么意思。基本上,您需要将 itemList 列拆分为一个新表,其中每个逗号分隔值都是它自己的行。
  • 没问题,我已经有了。但是然后呢?
  • 那么与项集相同。您的桌子设计效率极低。您应该有一个每行一个项目的表格。如果你有这个,你正在寻找的查询是微不足道的。

标签: sql sql-server tsql


【解决方案1】:

分割函数

CREATE FUNCTION [dbo].[split]  
    (  
      @delimited NVARCHAR(MAX),  
      @delimiter NVARCHAR(100)  
    )   
 RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))  
AS  
BEGIN  
  DECLARE @xml XML  
  SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>'  

  INSERT INTO @t(val)  
  SELECT  r.value('.','varchar(MAX)') as item  
  FROM  @xml.nodes('/t') as records(r)  
  RETURN  
END

测试数据

CREATE TABLE #transactions  (TID INT, itemlist VARCHAR(100))
INSERT INTO #transactions VALUES   
(1 ,'a,c,f'),
(2 ,'a'),
(3 ,'c,f,g,h,l'),
(4 ,'b,a,c'),
(5 ,'f,a')

CREATE TABLE #itemset([SID] INT, item1 VARCHAR(1), item2 VARCHAR(1), item3 VARCHAR(1))
INSERT INTO #itemset VALUES
(1 ,'a', NULL,  NULL),
(2 ,'c', 'l' ,  NULL),
(3 ,'c', 'f' ,  'l' ),
(4 ,'a', NULL,  'f') 

查询

;WITH TIDs AS (
    SELECT t.TID
          ,c.Items
    FROM #transactions t
           CROSS APPLY (SELECT Val FROM dbo.Split(t.itemlist , ',')) c(Items)
  ),
SIDs AS (
    SELECT [SID]
           ,Items
    FROM #itemset t
     UNPIVOT ( Items FOR item IN (item1,item2,item3)) up
  )
SELECT S.[SID]
      ,T.[TID]
FROM TIDs T INNER JOIN SIDs S 
ON T.Items = S.Items

结果

╔═════╦═════╗
║ SID ║ TID ║
╠═════╬═════╣
║   1 ║   1 ║
║   1 ║   2 ║
║   1 ║   4 ║
║   1 ║   5 ║
║   2 ║   1 ║
║   2 ║   3 ║
║   2 ║   4 ║
║   2 ║   3 ║
║   3 ║   1 ║
║   3 ║   3 ║
║   3 ║   4 ║
║   3 ║   1 ║
║   3 ║   3 ║
║   3 ║   5 ║
║   3 ║   3 ║
║   4 ║   1 ║
║   4 ║   2 ║
║   4 ║   4 ║
║   4 ║   5 ║
║   4 ║   1 ║
║   4 ║   3 ║
║   4 ║   5 ║
╚═════╩═════╝

【讨论】:

  • 您的解决方案没有比较集合,您得到的结果太多。
  • @Sean 您想详细说明您的主张吗?
  • M.Ali,谢谢。请在明天之前给我消化和理解您的意见。我会回来找你的。
  • @Nylix 如果您的数据库按应有的规范化,那将是一个简单的查询。
  • @M.Ali 你是绝对正确的。我的数据库设计太复杂了。再次感谢你。我从您的代码示例中学到了很多 - 即使它没有 100% 解决问题
【解决方案2】:

这不适合评论,但作为安倍的意思的一个例子。如果你有两个表 TransItem 和 ItemSet 像这样:

TID     ItemId
1       a
1       c
1       f
2       a

SID     ItemID
1       a
2       c
2       l

那么结果集就是设置项与交易项的比较

with SetItems
    as (select sid
                ,  count(sid) as itemcount 
        from ItemSet 
        group by sid)
, TransSet as (
        Select tid
                , sid
                , count(tid) transcount
        from 
            ItemSet s INNER JOIN 
            TransItem t ON s.Itemid=t.Itemid
        group by sid, tid )
Select s.sid, t.tid
from SetItems s LEFT OUTER JOIN 
TransSet t on s.sid=t.sid
where itemcount=transcount
order by sid, tid

不用说,如果您将项目放在列中,或者作为逗号分隔的字段,则此查询将变得更加困难。

【讨论】:

  • 肖恩,非常感谢。我只是用更大的数据集进行了尝试,并且效果很好。我也有计数的想法,但绝对没有计划如何使用适当的 SQL 代码来实现。
  • 第 2 部分:为了将我的项目集表转换为垂直表,我将采用 M.Ali 提出的 UNPIVOT。因此,在你们俩的投入下,我终于摆脱了这个问题。再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-28
  • 2022-10-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多