Sql 为每个组选择包含大多数非关键信息的行
好的,我有一个表,有一些垃圾数据,没有唯一标识符列。让我举一个我正在使用的表格的例子:Sql 为每个组选择包含大多数非关键信息的行,sql,select,sql-server-2012,Sql,Select,Sql Server 2012,好的,我有一个表,有一些垃圾数据,没有唯一标识符列。让我举一个我正在使用的表格的例子: A | B | C | D | E | -------------------------------------------------- 1. Fiona | Smith | NULL | 2152 Cherry Lane | CA | 2. Fiona | Smith | NULL | NULL | N
A | B | C | D | E |
--------------------------------------------------
1. Fiona | Smith | NULL | 2152 Cherry Lane | CA |
2. Fiona | Smith | NULL | NULL | NULL |
3. Bill | NULL | ACME | 2903 Center Road | WA |
4. Bill | NULL | ACME | NULL | NULL |
5. NULL | NULL | ABC | 2300 Water St | PA |
6. NULL | NULL | ABC | 2300 Water St | PA |
7. NULL | NULL | NULL | 3455 B Street | CO |
我需要编写一个SELECT语句,它只捕获不同的行。例如,以第1行和第2行为例。它们显然都指同一个人,但它们只是部分重复。在这两个语句中,我希望SELECT语句中包含第1行,因为它在每列中包含的数据最多。第3行和第4行也是如此。第3行是我想要包含的行。对于第5行和第6行,选择哪一行并不重要,因为它们都是完全重复的。默认情况下会包括第7行,因为它是不同的(意味着A、B和C,而不仅仅是A和B)
以下是我尝试过的:
SELECT A, B, C = MAX(D), MAX(E),
FROM dbo.Data
GROUP BY A, B, C;
这似乎抓住了我想要的唯一行,但数据不知何故被放在了错误的列中
WITH recordsList
AS
(
SELECT A, B, C, D, E,
ROW_NUMBER() OVER (PARTITION BY A,B,C
ORDER BY
CASE WHEN D IS NULL
THEN 0
ELSE 1 END DESC) x
FROM table1
)
SELECT A,B,C,D,E
FROM recordsList
WHERE x = 1
DECLARE @x TABLE
(
A VARCHAR(32),
B VARCHAR(32),
C VARCHAR(32),
D VARCHAR(32),
E VARCHAR(32)
);
INSERT @x VALUES
('Fiona', 'Smith', NULL, '2152 Cherry Lane', 'CA'),
('Fiona', 'Smith', NULL, NULL, NULL),
('Bill', NULL, 'ACME', '2903 Center Road', 'WA'),
('Bill', NULL, 'ACME', NULL, NULL),
(NULL , NULL, 'ABC', '2300 Water St', 'PA'),
(NULL , NULL, 'ABC', '2300 Water St', 'PA'),
(NULL , NULL, NULL, '3455 B Street', 'CO'),
('Bob', 'Barker',NULL, NULL, NULL),
('Bob', 'Barker',NULL, NULL, 'NY');
;WITH x AS
(
SELECT A,B,C,D,E, rn = ROW_NUMBER() OVER
(
PARTITION BY A,B,C
ORDER BY COALESCE(LEN(LEFT(D,1)),0) + COALESCE(LEN(LEFT(E,1)),0) DESC
)
FROM @x
)
SELECT A,B,C,D,E
FROM x WHERE rn = 1;
该方法将D和E视为相等:
DECLARE @x TABLE
(
A VARCHAR(32),
B VARCHAR(32),
C VARCHAR(32),
D VARCHAR(32),
E VARCHAR(32)
);
INSERT @x VALUES
('Fiona', 'Smith', NULL, '2152 Cherry Lane', 'CA'),
('Fiona', 'Smith', NULL, NULL, NULL),
('Bill', NULL, 'ACME', '2903 Center Road', 'WA'),
('Bill', NULL, 'ACME', NULL, NULL),
(NULL , NULL, 'ABC', '2300 Water St', 'PA'),
(NULL , NULL, 'ABC', '2300 Water St', 'PA'),
(NULL , NULL, NULL, '3455 B Street', 'CO'),
('Bob', 'Barker',NULL, NULL, NULL),
('Bob', 'Barker',NULL, NULL, 'NY');
;WITH x AS
(
SELECT A,B,C,D,E, rn = ROW_NUMBER() OVER
(
PARTITION BY A,B,C
ORDER BY COALESCE(LEN(LEFT(D,1)),0) + COALESCE(LEN(LEFT(E,1)),0) DESC
)
FROM @x
)
SELECT A,B,C,D,E
FROM x WHERE rn = 1;
如果D为null,而E不是,这可能会选择数据较少的行(请参阅我答案中的其他示例行)。@user1994209不客气。查询仅基于您的结果。我假设如果
D
为空,那么E
也是空的。无论如何,我很高兴:D
@JW-我有一个简短的问题。如果我添加了E为NULL时的CASE,那么0 ELSE 1 END DESC,那么这个查询会将D和E视为相等吗?如果你的意思是当D为NULL时的CASE,那么0 ELSE 1 END DESC,当E为NULL时的CASE,那么0 ELSE 1 END DESC
。是的,但它先排序D
,然后排序E
。如果D为空,而E不是空,则可能会选择数据较少的行(请参阅我回答中的其他示例行)。@user1994209不客气。查询仅基于您的结果。我假设如果D
为空,那么E
也是空的。无论如何,我很高兴:D
@JW-我有一个简短的问题。如果我添加了E为NULL时的CASE,那么0 ELSE 1 END DESC,那么这个查询会将D和E视为相等吗?如果你的意思是当D为NULL时的CASE,那么0 ELSE 1 END DESC,当E为NULL时的CASE,那么0 ELSE 1 END DESC
。是的,但是它先点了D
,然后点了E
。嘿,亚伦,谢谢你的回答,它成功了!我肯定要做一些研究来弄清楚这段代码到底在做什么以及为什么。允许您根据定义的条件对行(以及相关行的组,称为分区)应用排序。在这种情况下,我知道您认为A,B,C
是您的密钥,所以这就是我们所讨论的。然后决定如何定义每组中最重要的行。COALESCE表达式确保我们为D和E获得0(对于NULL或空字符串)或1(对于填充值)。最高值获胜。如果你想要一个平局,你可以添加、D DESC、E DESC
,或者相反,这取决于……在一行只有D,另一行只有E的情况下,你是喜欢D还是E。我试图演示这个解决方案如何喜欢E中有值的行而不是D中没有值的行。太棒了,谢谢你的解释。我能再问一件事吗?如何将此查询的结果插入到另一个现有表中?请在最后一行的第二行之前插入<代码>)插入dbo。其他表格(cols)选择A、B、C、D、E…嘿,亚伦,谢谢你的回答,它成功了!我肯定要做一些研究来弄清楚这段代码到底在做什么以及为什么。允许您根据定义的条件对行(以及相关行的组,称为分区)应用排序。在这种情况下,我知道您认为A,B,C
是您的密钥,所以这就是我们所讨论的。然后决定如何定义每组中最重要的行。COALESCE表达式确保我们为D和E获得0(对于NULL或空字符串)或1(对于填充值)。最高值获胜。如果你想要一个平局,你可以添加、D DESC、E DESC
,或者相反,这取决于……在一行只有D,另一行只有E的情况下,你是喜欢D还是E。我试图演示这个解决方案如何喜欢E中有值的行而不是D中没有值的行。太棒了,谢谢你的解释。我能再问一件事吗?如何将此查询的结果插入到另一个现有表中?请在最后一行的第二行之前插入<代码>)插入dbo。其他表格(cols)选择A、B、C、D、E…