多列的唯一组合,顺序无关紧要

Unique combination of multiple columns, order doesn't matter

假设 table 有 3 列。每行代表每个值的唯一组合:

a a a
a a b
a b a
b b a
b b c
c c a
...

然而,我想要的是,

aab = baa = aba 
cca = cac = acc
...

最后,我想以 CSV 格式获取这些值作为每个值的组合,就像我附加的图像一样。

感谢您的帮助!

下面是生成我的问题的查询,请看一下!

--=======================================
--populate test data
--=======================================
drop table if exists #t0
;
with 
cte_tally as
(
select row_number() over (order by (select 1)) as n 
from sys.all_columns
)
select 
  char(n) as alpha
into #t0
from 
  cte_tally
where
  (n > 64 and n < 91) or
  (n > 96 and n < 123);

drop table if exists #t1
select distinct upper(alpha) alpha into #t1 from #t0

drop table if exists #t2
select
    a.alpha c1
,   b.alpha c2
,   c.alpha c3
,   row_number()over(order by (select 1)) row_num
into #t2
from #t1 a
join #t1 b on 1=1
join #t1 c on 1=1


drop table if exists #t3
select *
into #t3
from (
    select *
    from #t2
) p
unpivot
    (cvalue for c in (c1,c2,c3)
) unpvt


select
    row_num
,   c
,   cvalue
from #t3
order by 1,2

--=======================================
--these three rows should be treated equally
--=======================================
select *
from #t2
where concat(c1,c2,c3) in  ('ABA','AAB', 'BAA')

--=======================================
--what i've tried...
--row count is actually correct, but the problem is that it ommits where there're any duplicate alphabet.
--=======================================
select 
    distinct
    stuff((
        select
            distinct
        '.' + cvalue
        from #t3 a
        where a.row_num = h.row_num
    for xml path('')
    ),1,1,'') as comb
from #t3 h

很好奇为什么,肯定有原因。可能建议查找 table,将所有关联的键保存到“映射 Table”。您可以在实施时优化其中的一些。首先创建一个 table 用于保存“Next/New 键”(这是 1、2、3... 的来源)。在将每批记录批量插入“映射 Table”后,您会获得一个新的“新密钥”。 “映射 Table”包含键值的组合,每个组合一行与您的“新键”一起应该得到一个 table 看起来像:

A, B, C, 1
A, C, B, 1
B, A, C, 1
...
X, Y, Z, 2
X, Z, Y, 2

如果您可以更新源 table 以保留“映射键”(1、2、3)的列,那么您只需从映射 table 中查找,其中 (c1 =a, c2=a, c3=b) 此查找的顺序无关紧要。一个建议是在您的映射 table 上使用 c1、c2、c3 创建一个复合唯一键。然后要获取您的记录,只需从映射 table 中查找“映射键值”,然后查询与映射键值匹配的记录。或者,如果您不进行预查找以获取映射键,您应该能够使用映射键值进行自连接...

正如 所指出的,您可以对值进行逆透视,以正确的顺序对它们进行排序,然后将它们重新聚合到一行中。然后您可以按这些新值对原始行进行分组。

SELECT *
FROM #t2
CROSS APPLY (
    SELECT a = MIN(val), b = MIN(CASE WHEN rn = 2 THEN val), c = MAX(val)
    FROM (
        SELECT *, rn = ROW_NUMBER() OVER (ORDER BY val)
        FROM (VALUES (c1),(c2),(c3) ) v3(val)
    ) v2
) v
GROUP BY v.a, v.b, v.c;

实际上,您也许应该首先确保值的顺序正确:

ALTER TABLE #t2
   ADD CONSTRAINT t2_ValuesOrder
       CHECK (c1 <= c2 AND c2 <= c3);

如果您希望它们采用 CSV 格式:

select distinct v.cs
from #t2 t2 cross apply
     (select string_agg(c order by c desc, ',') as cs
      from (values (t2.c1), (t2.c2), (t2.c3)
           ) v(c)
     ) v;

在我看来,您需要的是某种形式的掩蔽*。拿这个 fiddle:

http://sqlfiddle.com/#!18/fc67f/8

我在其中创建了一个映射 table,其中包含所有可能的值并将其与 10 的递增顺序配对。在该映射 table 上进行交叉连接,连接值,添加掩码和总计分组将为您提供所有独特的组合。

这是来自 fiddle 的代码:

CREATE TABLE maps (
  val varchar(1),
  num int
);

INSERT INTO maps (val, num) VALUES ('a', 1), ('b', 10), ('c', 100);

SELECT mask, max(vals) as val 
FROM (
  SELECT concat(m1.val, m2.val, m3.val) as vals,
      m1.num + m2.num + m3.num as mask
  FROM maps m1
  CROSS JOIN maps m2
  CROSS JOIN maps m3
) q GROUP BY mask

使用这些值 10 将确保掩码包含每个值的计数,结果数字中每个位置列一个,然后您可以对其进行分组以获得唯一的(ish)字符串。

我不知道你的数据是什么样的,如果你有超过 10 个可能的值,那么你将不得不使用 10 以外的其他基数,但理论应该仍然适用。我没有编写代码来将值 table 中的列提取到映射 table 中,但我相信你可以做到这一点。

*实际上,我认为我正在寻找的术语是标志。