SQL Server分组将null视为等于所有值

Dve*_*vey 5 sql-server null grouping

在SQL Server中,我正在尝试按ID分组匹配的行.Null被视为通配符.

说明:匹配行是什么意思?

匹配行意味着 - 只要两行的所有列匹配.

匹配列平均值 - 每个值的相同值('A'='A')或空值('A'/'B'/'C'/ ... = NULL).

在我的例子中:

第1行与第2行匹配 - 因为:

First column: 'A' = 'A'
Second column: 'B' = NULL
Third column: NULL = 'C'
Run Code Online (Sandbox Code Playgroud)

第1行与第4行不匹配:

First column: 'A' = 'A'
Second column: 'B' != 'D'
Third column: NULL = NULL.
Run Code Online (Sandbox Code Playgroud)

比较失败,因为第二列中的值不匹配.

任何人都可以帮助我使用SQL吗?

例如:

用于创建测试表:

create table test_table 
(
    id int,
    column1 varchar(20),
    column2 varchar(20),
    column3 varchar(20)
);

insert into test_table (id, column1, column2, column3) values 
(1, 'A', 'B', NULL),
(2, 'A',NULL, 'C'),
(3, 'A', 'B', 'D'),
(4, NULL, 'D', NULL),
(5, 'A', 'B', 'D');
Run Code Online (Sandbox Code Playgroud)

例如,表格

在此输入图像描述

这是预期的结果:

group id 1: {1,2}
group id 2: {1,3,5}
group id 3: {2,4}
Run Code Online (Sandbox Code Playgroud)

这些行无法加入一个组:{1,2,3}.

表中预期结果的示例:

在此输入图像描述

我试过这个答案:

   SELECT
    T1.id as row_id,
    T2.id as row_id
FROM
    test_table AS T1
    INNER JOIN test_table AS T2 ON
        (T1.column1 = T2.column1 OR T1.column1 IS NULL OR T2.column1 IS NULL) AND
        (T1.column2 = T2.column2 OR T1.column2 IS NULL OR T2.column2 IS NULL) AND
        (T1.column3 = T2.column3 OR T1.column3 IS NULL OR T2.column3 IS NULL)
WHERE
    T1.id < T2.id
Run Code Online (Sandbox Code Playgroud)

结果表: 在此输入图像描述

所以我可以看到第1行与第2,3,5行匹配 - 但是我看不到第2行和第3行不能加入同一个组.我想要的是一个结果,我可以看到行1,3,5可以在同一个组中,因为它们都匹配,但第1行和第2行之间的匹配需要在其他组中,因为第2行与行不匹配3和5.

Zho*_*rov 0

您可以尝试使用以下方法:

  • 找出column1column2和中的所有不同值column3NULL这些值是列中值的可能候选值。
  • NULL使用生成的不同值生成所有可能的值组合
  • 仅选择重复的行
  • 使用生成组编号DENSE_RANK()

陈述:

;WITH ValuesCTE ([column]) AS (
   SELECT column1 FROM #test_table WHERE column1 IS NOT NULL
   UNION 
   SELECT column2 FROM #test_table WHERE column2 IS NOT NULL
   UNION 
   SELECT column3 FROM #test_table WHERE column3 IS NOT NULL
), ReplaceCTE AS (
   SELECT 
      t.id, 
      CASE WHEN t.column1 IS NULL THEN c1.[column] ELSE t.column1 END AS column1, 
      CASE WHEN t.column2 IS NULL THEN c2.[column] ELSE t.column2 END AS column2, 
      CASE WHEN t.column3 IS NULL THEN c3.[column] ELSE t.column3 END AS column3
   FROM #test_table t
   LEFT JOIN ValuesCTE c1 ON t.column1 IS NULL
   LEFT JOIN ValuesCTE c2 ON t.column2 IS NULL
   LEFT JOIN ValuesCTE c3 ON t.column3 IS NULL
), DuplicatesCTE AS (
   SELECT column1, column2, column3 
   FROM ReplaceCTE
   GROUP BY column1, column2, column3
   HAVING COUNT(*) > 1
)
SELECT
   r.id,
   DENSE_RANK() OVER (ORDER BY r.column1, r.column2, r.column3) AS grp
FROM ReplaceCTE r
RIGHT JOIN DuplicatesCTE d ON (r.column1 = d.column1) AND (r.column2 = d.column2) AND (r.column3 = d.column3)
Run Code Online (Sandbox Code Playgroud)

输出:

id  grp
1   1
2   1
1   2
3   2
5   2
2   3
4   3
Run Code Online (Sandbox Code Playgroud)