我有一个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条记录。
感谢您的帮助
答案 0 :(得分:1)
我猜你不能向你的数据提供商询问其他格式? 因为看起来文件格式不好。
答案 1 :(得分:1)
将数据加载到数据库的两个基本规则:
不要破坏数据。随着数据的传递,它们也将被加载。
可以在加载时添加数据,并且可以更改表示。例如,您可以添加行号或文件名作为新列,并且可以将无用的"N/A"
或"NULL"
字符串更改为零长度字符串,从而在数据库中创建NULL。标准的Unix工具非常适合这个目的;很多都是available on Windows。
另一项好政策是:
在您的情况下,正如其他人所指出的那样,您对如何为缺失代理值提供代理价值的想法 - 通过使用"之前的"值 - 取决于知道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
完成此操作会不会更快