将原始数据转换为关系数据

时间:2012-06-06 17:28:08

标签: sql-server stored-procedures etl

简介

我已经把一个凌乱的excel转储直接放到桌子上了。现在我需要把这个烂摊子变成有用的东西。 转储有重复和不一致......好时光!

到目前为止,我一直在抨击每一种方法:( - 希望你能帮助我。

鉴于此示例数据集:

ExcelDump
+----+------+------+------+
| ID | Col1 | Col2 | Col3 |
+----+------+------+------+
|  1 |      |      | C    |
|  1 |      | B    | C    |
|  1 | A    | B    | D    |
|  1 | E    | B    | C    |
|  2 | A    | B    | C    |
|  2 | A    | B    | C    |
|  3 | A    | B    | C    |
|  3 | A    | B    | F    |
|  4 | A    | B    | C    |
|  4 | G    | B    | C    |
+----+------+------+------+

一个可能的结果可能是:

OutputTable
+----+------+------+------+
| ID | Col1 | Col2 | Col3 |
+----+------+------+------+
|  1 | A    | B    | C    |
|  2 | A    | B    | C    |
|  3 | A    | B    | C    |
|  4 | A    | B    | C    |
+----+------+------+------+

很好,很整洁。 唯一ID键和数据以有意义的方式合并在一起。

如何选择哪些数据正确?

你可能已经注意到另一个可能的结果可能是:

+----+------+------+------+
| ID | Col1 | Col2 | Col3 |
+----+------+------+------+
|  1 | E    | B    | C    |
|  2 | A    | B    | C    |
|  3 | A    | B    | F    |
|  4 | G    | B    | C    |
+----+------+------+------+

这是变得复杂的地方。我希望能够根据我可以操作的一些条件选择最有意义的集合。

例如,我想设置一个条件:“选择最多(非空)公共值,如果没有找到最常见的值,则发现 first 值不为null 。“ 此条件应适用于按ID分组的选择。 这种情况的结果将是:

+----+------+------+------+
| ID | Col1 | Col2 | Col3 |
+----+------+------+------+
|  1 | A    | B    | C    |
|  2 | A    | B    | C    |
|  3 | A    | B    | C    |
|  4 | A    | B    | C    |
+----+------+------+------+

如果我后来发现该假设是错误的,那么它应该是:“选择最多(非空)公共值,如果没有找到最常见的值,则取 last 值发现它不是空的。“

+----+------+------+------+
| ID | Col1 | Col2 | Col3 |
+----+------+------+------+
|  1 | E    | B    | C    |
|  2 | A    | B    | C    |
|  3 | A    | B    | F    |
|  4 | G    | B    | C    |
+----+------+------+------+

所以基本上我想根据每组ID的一组条件选择值。

3 个答案:

答案 0 :(得分:3)

如上所述,您可以使用简单的GROUP BY

执行此操作
SELECT 
    id, 
    Col1 = MAX(Col1),
    Col2 = MAX(Col2),
    Col3 = MAX(Col3)
FROM
   ExcelDump
GROUP BY
   id

此模式将为每个id值提供每列最高的非空值。

答案 1 :(得分:1)

我修改了我的解决方案,以考虑问题中添加的额外信息。以下查询将为您提供您指定的第二个排序优先级。为了得到第一个,你将外部的“max”更改为“min”并将“sortOrder desc”更改为“sortOrder asc”。请记住,如果您有最多频繁的多个关系,比如A,A,B,B,C和A首先出现,它将与下面的代码中的B一起使用,因为这是最高的计数并且在2 A之后。< / p>

-- setup test table
create table ExcelDump(
    id int
,   Col1 char(1)
,   Col2 char(1)
,   Col3 char(1)
)

insert into ExcelDump values(1,null,null,'C')
insert into ExcelDump values(1,null,'B','C')
insert into ExcelDump values(1,'A','B','D')
insert into ExcelDump values(1,'E','B','C')
insert into ExcelDump values(2,'A','B','C')
insert into ExcelDump values(2,'A','B','C')
insert into ExcelDump values(3,'A','B','C')
insert into ExcelDump values(3,'A','B','F')
insert into ExcelDump values(4,'A','B','C')
insert into ExcelDump values(4,'G','B','C')

-- create temp tables to make it easier to debug
select distinct
    id
into #distinct
from ExcelDump

-- number order isn't guaranteed but should be sorting them as first come first serve from the original table if no indexes exist
select
    row_number() over(order by (select 1)) as numberOrder
,   ID
,   Col1
,   Col2
,   Col3
into #sorted
from ExcelDump

-- actual query
select
    ui.Id
,   col1.Col1
,   col2.Col2
,   col3.Col3
from #distinct ui
  outer apply (
        select top 1
            ed.Col1
        ,   count(*) as cnt
        ,   max(ed.numberOrder) as sortOrder
        from #sorted ed
        where ed.id = ui.id
        and ed.Col1 is not null -- ignore nulls
        group by ed.Col1
        order by cnt desc, sortOrder desc -- get most common value, then get last one found if there are multiple
    ) col1
  outer apply (
        select top 1
            ed.Col2
        ,   count(*) as cnt
        ,   max(ed.numberOrder) as sortOrder
        from #sorted ed
        where ed.id = ui.id
        and ed.Col2 is not null -- ignore nulls
        group by ed.Col2
        order by cnt desc, sortOrder desc -- get most common value, then get last one found if there are multiple
    ) col2
  outer apply (
        select top 1
            ed.Col3
        ,   count(*) as cnt
        ,   max(ed.numberOrder) as sortOrder
        from #sorted ed
        where ed.id = ui.id
        and ed.Col3 is not null -- ignore nulls
        group by ed.Col3
        order by cnt desc, sortOrder desc -- get most common value, then get last one found if there are multiple
    ) col3

答案 2 :(得分:0)

您还可以使用游标迭代临时ExcelDump表以过滤每一行。您可以将过滤后的结果存储到另一个临时表中,如果需要,可以有自己的约束,如唯一或非空,通过使用游标,您可以编写专门的代码来处理您需要的每个验证。