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

此方法将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和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…