表中缺少数据

时间:2014-03-18 14:42:34

标签: sql sql-server excel tsql database-design

我有一个SQL挑战

我的数据提供商向我发送了一个格式如下的示例的CSV数据 现在由于某种原因,文件丢失数据可能是为了节省空间并使表更小,我不确定。

在Field_1和Field_2中缺少数据。数据存在于一条记录中,以下记录在下一条记录之前具有NULL值。所以在下面的例子中,在Field_1的第二和第三个记录中,值应该是“ID_1”而不是NULL同样适用于Field_2,值应该是ABC而不是NULL

Field_1 Field_2 Field_3
-----------------------
ID_1    ABC    Value_3
NULL    NULL   Value_3  --> ID_1   ABC   Value_3
NULL    NULL   Value_3  --> ID_1   ABC   Value_3
ID_2    CDE    Value_3
NULL    NULL   Value_4  --> ID_2   CDE   Value_4
ID_3    EFG    Value_X

到目前为止,我编写了一个excel模块,在导入之前修复了我的数据,但文件开始变得非常大而且excel将无法处理。 所以我的选择是使用TSQL游标并执行一些将填充数据的过程。或者我可以构建我的选择查询来补偿丢失的数据,并在运行数据选择之前生成带有填充数据的虚拟表

最佳解决方案是什么?我的要求是低维护和空间效率之间的愉快 我说的是17个缺少数据的字段和每月约150,000条记录。

感谢您的帮助

6 个答案:

答案 0 :(得分:1)

我猜你不能向你的数据提供商询问其他格式? 因为看起来文件格式不好。

答案 1 :(得分:1)

将数据加载到数据库的两个基本规则:

  1. 不要破坏数据。随着数据的传递,它们也将被加载。

  2. 可以在加载时添加数据,并且可以更改表示。例如,您可以添加行号或文件名作为新列,并且可以将无用的"N/A""NULL"字符串更改为零长度字符串,从而在数据库中创建NULL。标准的Unix工具非常适合这个目的;很多都是available on Windows

  3. 另一项好政策是:

    1. 不要使用光标。如果您想尝试使用光标,则需要考虑行。想想套装。
    2. 在您的情况下,正如其他人所指出的那样,您对如何为缺失代理值提供代理价值的想法 - 通过使用"之前的"值 - 取决于知道CSV文件中出现的行的顺序。在数据库理论中,数据中称为隐含意义。在SQL中,我们只有显式含义:对于一行是"在"之前另外,必须有一个要比较的列。

      所以:对行进行编号,并加载NULL,可以这么说。

      然后,您可以获得所需的信息以获得所需的效果:您可以将表格加入到自身中,并合并相关的"更早的"数据丢失的数据。不需要触发器或任何异国情调。找到最后一个好的"行,并使用这些值代替缺失的值。

      create table T (line, Field_1, Field_2, Field_3);
      insert into T values
        (1, 'ID_1', 'ABC', 'Value_3')
      , (2, NULL, NULL, 'Value_3')
      , (3, NULL, NULL, 'Value_3')
      , (4, 'ID_2', 'CDE', 'Value_3')
      , (5, NULL, NULL, 'Value_4')
      , (6, 'ID_3', 'EFG', 'Value_X');
      
      create view vT as
      select   a.line
             , coalesce(a.Field_1, b.Field_1) as Field_1
             , coalesce(a.Field_2, b.Field_2) as Field_2
             , a.Field_3
      from T as a join T as b
      on b.line = ( -- last line before a.line with good values (unless a is good)
          select max(line) from T
          where line <= a.line
          and Field_1 is not NULL
          and Field_2 is not NULL
      );
      
      select * from T;
      select * from vT;
      

      输出:

      line        Field_1     Field_2     Field_3   
      ----------  ----------  ----------  ----------
      1           ID_1        ABC         Value_3   
      2                                   Value_3   
      3                                   Value_3   
      4           ID_2        CDE         Value_3   
      5                                   Value_4   
      6           ID_3        EFG         Value_X   
      
      line        Field_1     Field_2     Field_3   
      ----------  ----------  ----------  ----------
      1           ID_1        ABC         Value_3   
      2           ID_1        ABC         Value_3   
      3           ID_1        ABC         Value_3   
      4           ID_2        CDE         Value_3   
      5           ID_2        CDE         Value_4   
      6           ID_3        EFG         Value_X   
      

      coalesce函数采用列列表并返回第一个非NULL值。 b行保证不具有NULL; a行可能不会。如果a是好的,我们会使用它,否则我们会从b获取。

答案 2 :(得分:0)

抱歉,我不明白......

你说:

  

所以在下面的例子中,在Field_1的第二和第三个记录中,值应为&#34; ID_1&#34;并且不是NULL同样适用于Field_2,值应该是ABC而不是NULL

Field_1 Field_2 Field_3
-----------------------
ID_1    ABC    Value_3
NULL    NULL   Value_3
NULL    NULL   Value_3
ID_2    CDE    Value_3
NULL    NULL   Value_4
ID_3    EFG    Value_X

如果我接受你所说的并将它应用到桌子上,它就会像这样......

Field_1 Field_2 Field_3
-----------------------
ID_1    ABC    Value_3
ID_1    ABC    Value_3
ID_1    ABC    Value_3
ID_2    CDE    Value_3
ID_2    CDE    Value_4
ID_3    EFG    Value_X

因此,假设您需要副本数据,您可以将其导入表中,并创建一个存储过程,从完全填充的行复制数据,并将其插入具有相同Field_1 ID的行中?

答案 3 :(得分:0)

一种可行的方法。但是,请查看表格的实际顺序并替换ORDER BY (SELECT NULL)

WITH cte AS (
    SELECT  *, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as row_num
    FROM   YourTable
)
SELECT  
     Field_1 = ISNULL(Field_1,(SELECT TOP 1 Field_1 FROM cte c1 WHERE c1.Field_1 IS NOT NULL AND c1.row_num < c.row_num ORDER BY c1.row_num DESC)) 
    ,Field_2 = ISNULL(Field_2,(SELECT TOP 1 Field_2 FROM cte c1 WHERE c1.Field_2 IS NOT NULL AND c1.row_num < c.row_num ORDER BY c1.row_num DESC))  
    ,Field_3
FROM    cte c

答案 4 :(得分:0)

表没有固有的顺序 即使是带有群集PK的表也没有订购 如果没有order by子句,则无法保证选择

因此,如果您要修复SQL中的数据,则需要插入标识,以便重现订单。

我会更新数据,所以你只需要做一次 选择查找上面的数据是一个相当昂贵的查询

这只是在一个时间和一列做一行,但它是一个开始

update tableTarget
   set tableTarget.Field_1 = tableSource.Field_1 
  from table as tableTarget 
  join table as tableSource 
    on tableTarget.Iden = tableSource.Iden + 1 
   and tableTarget.Field_1 is null 
   and tableSource.Field_1 is not null 

现在这一次只能做一对,所以如果连续最多4个空,那么你需要运行它4次
运行它直到说明零行更新
但是你连续可以有4个空值,而且只需要运行4次

我知道多次运行相同的更新似乎很麻烦,但它是一个非常有效的更新 根据样本数据,一行中只有几个空值

未经测试 它效率不高,但您只需为每列运行一次

update tableTarget
   set tableTarget.Field_1 = (select top 1 tableSource.Field_1 
                                from table as tableSource
                               where tableSource.Field_1 is not null 
                                 and tableSource.Iden < tableTarget.iden 
                               order by tableSource.Iden desc )
  from table as tableSource 
 where tableTarget.Field_1 is null 

答案 5 :(得分:0)

我尝试了所有这些查询,但它们都有效。据说他们需要永远完成 我能用excel快10倍

来做到这一点

我很好奇使用CURSOR

完成此操作会不会更快