【问题标题】:Splitting rows in SQL在 SQL 中拆分行
【发布时间】:2010-09-18 05:19:18
【问题描述】:

有人可以告诉我如何使用 SQL 获取以不同方式相交的三行的不同段吗? #t2 中的三行代表集合 A、B、C - 我正在寻找 AIB、AIC、BIC、AIBIC、A'、B'、C' 等,(在维恩图中有 3 行的 7 个可能段) I 是交叉口。

我正在寻找一个通用解决方案,它可以处理 #t2 中的 n 行。

-- SQL Code Begin
create table #t1 (key1 int, key2 int) -- for each Key1 there can be 1 or more Key2
go
create table #t2 (row_id int identity(101, 1), key1 int) --row_id is the primary key
go 

insert into #t1
select 1, 11 union select 1, 12 union select 1, 13 union select 1, 14 union 
select 2, 13 union select 2, 15 union select 2, 16 union select 2, 17 union 
select 3, 13 union select 3, 12 union select 3, 16 union select 3, 17

-- 1 --> 11, 12, 13, 14
-- 2 --> 13, 15, 16, 17
-- 3 --> 13, 12, 16, 17

insert into #t2 (key1)
select 1 union select 2 union select 3

-- SQL Code End

我正在寻找的输出是,

1001  11 (A')
1001  14 (A')
1002  12 (A I C - A I B I C)
1003  13 (A I B I C)
1004  15 (B')
1005  16 (B I C - A I B I C)
1005  17 (B I C - A I B I C)

输出有 5 个段,而不是可能的 7 个段,因为其中两个为 NULL。

【问题讨论】:

  • 您可能想要编辑您的问题以删除实际不是代码的部分之前的空格。真的很难按原样阅读这里的内容。
  • 帮助我理解你的问题。字母是从哪里来的?你真的想要结果中的字母吗?如果是这样,分配它们的规则是什么?另外,我不明白数字 12、16 和 17 的输出,为什么在结果中包含 A、B 和 C 的交集?
  • 如果我可以改写您的问题,这是否准确?您需要 #t1.key2 中的每个不同值以及它们所属的 #t2 中的哪些记录。
  • 我正在寻找的是当 A、B 和 C 相交时所有可能的不同段(如在维恩图中)。其中一些段可能为 NULL。
  • 我真的不需要结果中的字母。我只是想展示结果的来源。 12 - 它是 A 和 C 的交集减去三个项目之间的公共交集。尽管我的示例是 3 行,但我正在寻找一种通用解决方案来解决更大的行数。

标签: sql rows split


【解决方案1】:

如果我正确理解了这个问题,我认为您可能不得不求助于使用循环来处理“n”行数

DECLARE @Key2 INT
DECLARE @Subset VARCHAR(1000)
DECLARE @tblResults TABLE
(
    Key2 INT,
    Subset VARCHAR(1000)
)

SET @Subset = ''
SELECT @Key2 = MIN(Key2) FROM #t1

WHILE @Key2 IS NOT NULL
BEGIN
    SELECT @Subset = @Subset + CAST(Key1 AS VARCHAR(10))
    FROM #t1
    WHERE Key2 = @Key2

    INSERT INTO @tblResults (Key2, Subset)
    VALUES (@Key2, @Subset)

    SET @Subset = ''
    SELECT @Key2 = MIN(Key2) FROM #t1 WHERE Key2 > @Key2
END

SELECT * FROM @tblResults

【讨论】:

  • 谢谢。它似乎可以解决问题。我试图避免我不确定是否可能的循环。再次感谢。
【解决方案2】:

这个怎么样?

SELECT key2,
  CASE
  WHEN InA = 1 and InB = 1 and InC = 1 THEN 'ABC'
  WHEN InA = 0 and InB = 1 and InC = 1 THEN 'BC'
  WHEN InA = 1 and InB = 0 and InC = 1 THEN 'AC'
  WHEN InA = 1 and InB = 1 and InC = 0 THEN 'AB'
  WHEN InA = 1 and InB = 0 and InC = 0 THEN 'A'
  WHEN InA = 0 and InB = 1 and InC = 0 THEN 'B'
  WHEN InA = 0 and InB = 0 and InC = 1 THEN 'C'
  ELSE 'I''m broke'
  END as [SubSet]
FROM

(
SELECT key2,
  MAX(CASE WHEN key1 = 1 THEN 1 ELSE 0 END) as InA,
  MAX(CASE WHEN key1 = 2 THEN 1 ELSE 0 END) as InB,
  MAX(CASE WHEN key1 = 3 THEN 1 ELSE 0 END) as InC
FROM #t1
WHERE key1 in (1, 2, 3)
GROUP BY key2
) sub

ORDER BY key2

【讨论】:

  • 谢谢。它适用于 3 个值。但是,我实际上正在寻找一种可以处理任何更大的 n 值(例如,100、1000 等)的解决方案。当然,并不是所有的组合都存在,结果会像一个稀疏矩阵,但是查询需要处理组合不为NULL的地方。
【解决方案3】:

如果您可以将表 2 填充为

1, Key1-Value 1
2, Key1-Value 2
4, Key1-Value 3

同样,如果您有更多的 key1,那么您所拥有的标识列应该填充为二叉树。 这样 t2 中的值将是

1 , 1
2 , 2
4 , 3

然后你需要做一个选择:

select sum(identity), key2
from t1, t2
where t1.key1 = t2.key1
groupby key2

你将得到的输出将是

1   11
5   12
7   13
1   14
2   15
6   16
6   17

你可以看到 1,2,4 将是 A',B',C' 2 将是 A|B , 7 将是 A|B|C 等等

【讨论】:

  • 我了解您建议将 #t2 插入到 #t2 值 (1, 1)、(2, 2)、(4,3) 中,其中 1,2 和 4 是生成的值 (2 ^n)。但是,我不确定“如果您有更多的 key1,那么身份列 ...二叉树 ... 1, 1 2, 2 4, 3.”。请举例说明。
  • 另外,如果 #t2 有 1000 行,我们大约取 2 ^ 1000。您有更好的建议吗?谢谢。
  • 如果我们有更多的 Key1,那么 t2 中的 row_id 将具有 1、2、4、8、16、32 等值。如果我们谈论的是 1000 行,那么我认为这不是一个可行的选项,因为 row_id 值将变得非常大。你能解释一下 1001,1002 等在你的输出中的意义和重要性吗?
  • 数字 1001、1002 等没有任何意义。它们只是从 1001 开始的标识值。我只是将它们与 Keys 值 1、2、3、101、102 区分开来等,在示例中。它可以是任何数字。但是,拥有 2 ^ n 不适用于 1000 行。谢谢。
  • 澄清一下,所有 A' 的标识值 1001 应该相同?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多