提问人:Dvey 提问时间:2/24/2019 最后编辑:Dvey 更新时间:7/31/2019 访问量:582
SQL Server 分组将 null 视为等于所有值
SQL Server grouping consider null as equals to all values
问:
在 SQL Server 中,我尝试按 ID 对匹配行进行分组。Null 被视为通配符。
解释:匹配行是什么意思?
匹配行意味着 – 仅当两行的所有列都匹配时。
匹配列均值 – 相同的值 ('A' = 'A') 或每个值的 null 值 ('A'/'B'/'C'/... = NULL)。
在我的例子中:
第 1 行与第 2 行匹配 – 因为:
First column: 'A' = 'A'
Second column: 'B' = NULL
Third column: NULL = 'C'
第 1 行与第 4 行不匹配:
First column: 'A' = 'A'
Second column: 'B' != 'D'
Third column: NULL = NULL.
比较失败,因为第二列中的值不匹配。
谁能帮我处理 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');
例如,表格
这是预期的结果:
group id 1: {1,2}
group id 2: {1,3,5}
group id 3: {2,4}
这些行不能联接到一个组:{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
因此,我可以看到第 1 行与第 2、3、5 行匹配 - 但我看不到第 2 行和第 3/5 行无法加入同一组。 我想要的是一个结果,我可以看到第 1、3、5 行可以在同一组中,因为它们都匹配,但第 1 行和第 2 行之间的匹配需要在其他组中,因为第 2 行与第 3 行和第 5 行不匹配。
答:
0赞
Zhorov
2/24/2019
#1
您可以尝试以下方法:
- 查找 和 中的所有不同值。这些值是列中值的可能候选项。
column1
column2
column3
NULL
- 使用生成的不同值为值生成所有可能的组合
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)
输出:
id grp
1 1
2 1
1 2
3 2
5 2
2 3
4 3
0赞
KumarHarsh
7/31/2019
#2
这个比实际看起来更容易。
如果它不适用于任何其他示例数据,请告诉我。
drop table if exists #test_table
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');
WITH CTE
AS (SELECT t.id,
ISNULL(t.column1, t1.column1) col1,
ISNULL(t.column2, t1.column2) col2,
ISNULL(t.column3, t1.column3) col3,
t1.id AS tid,
ISNULL(t1.column1, t.column1) col4,
ISNULL(t1.column2, t.column2) col5,
ISNULL(t1.column3, t.column3) col6
FROM #test_table t
INNER JOIN #test_table t1 ON ISNULL(t.column1, t1.column1) = ISNULL(t1.column1, t.column1)
AND ISNULL(t.column2, t1.column2) = ISNULL(t1.column2, t.column2)
AND ISNULL(t.column3, t1.column3) = ISNULL(t1.column3, t.column3)
WHERE t1.id > t.id),
CTE1
AS (SELECT *,
DENSE_RANK() OVER(
ORDER BY col4,
col5,
col6) rn
FROM CTE)
SELECT DISTINCT
t.id,
ca.rn
FROM #test_table t
CROSS APPLY
(
SELECT c.id,
c.tid,
rn
FROM cte1 c
WHERE t.id = c.id
OR t.id = c.tid
) ca
ORDER BY rn;
For optimize query
:请抛出真实的表格结构。结果集中需要记录总数和多少行?
column1,column2,column3 仅包含特定值是否有任何限制。或者它们可以包含任何东西?
评论
T1.id < T2.id