我正在将美国人口普查原始数据处理到SQL Server数据库中。解压缩后的tar文件会产生略多于14,000个CSV文件,需要将其处理到266个不同的数据库表中。我必须遍历每个CSV文件并向该文件附加一个标头,以便SSIS可以将原始数据ETL到目标SQL Server表中。
每个CSV文件的前6列完全相同。每个文件的其余列均不同。其余列中的数据大部分是数字值(整数和十进制)。但是,人口普查局会添加称为“ jam”值的字符,以表示为什么没有值。我需要将这些Jam值替换为null或空字符串,因为目标数据库表列为DECIMALS,并且jam值导致SSIS插入失败。
因此,我有一个C#(DotNet Core)类库,循环遍历14K文件。对于每个文件,我必须执行以下操作:
我有3个嵌套循环:
这是我遍历每个文件的代码:
private static Boolean BuildCensusDataFileWithHeader(String censusDataFilePath, String rowHeader, String censusDataDestinationFilePath)
{
try
{
// BUILD NEW FILE WITH HEADER
StringBuilder currentContent = new StringBuilder();
currentContent.Append(rowHeader + Environment.NewLine);
//RETRIEVE ALL LINES IN TARGET FILE
List<String> rawList = File.ReadAllLines(censusDataFilePath).ToList();
// LOOP THROUGH EACH LINE AND REMOVE ANY STRINGS IN COLUMNS AFTER COLUMN 6
// NOTE: COLUMNS 1-6 CONTAINS STRINGS NEEDED IN DATABASE
foreach (var row in rawList)
{
//TURN COMMA DELIMITED ROW OF DATA INTO ARRAY
String[] rowArray = row.Split(",");
// PEEL OFF FIRST 6 COLUMNS TO BE KEPT AS IS
IList<String> goodStrings = rowArray.Take(6).ToList();
// RETRIEVE REMAINING COLUMNS TO BE CLEANED OF STRINGS
IList<String> stringsToNullList = rowArray.Skip(6).ToList();
// REMOVE ALL STRINGS
stringsToNullList.OnlyDecimalValues();
// PUT GOOD COLUMNS AND CLEANED COLUMNS BACK TOGETHER AS A ROW
var cleanedRow = $"{String.Join(",", goodStrings)},{String.Join(",", stringsToNullList)}";
// APPEND ROW TO NEW DOCUMENT TO BE WRITTEN TO TARGET DIRECTORRY CONTAINING CLEANED DATA
currentContent.Append(cleanedRow + Environment.NewLine);
}
File.WriteAllText(censusDataDestinationFilePath, currentContent.ToString());
return true;
}
catch (Exception ee)
{
string temp = ee.Message;
return false;
}
}
这是我的扩展方法,用空格替换字符:
public static void OnlyDecimalValues(this IList<String> stringToClean)
{
for (int i = 0; i < stringToClean.Count; ++i)
{
stringToClean[i] = (stringToClean[i].IsDecimal()) ? stringToClean[i] : "";
}
}
public static bool IsDecimal(this string text)
{
decimal test;
return decimal.TryParse(text, out test);
}
这都是通过蛮力编程来完成的。有更有效的方法吗?
谢谢您的时间。
答案 0 :(得分:0)
我有两个建议可以加快速度。 首先,由于对解析后的十进制值不做任何事情,因此可以使用正则表达式检查字符串是否仅包含数字。它比使用TryParse更快。我使用秒表来检查速度,这样在“假”情况下产生的性能会稍微好一些,而在“真”情况下产生的性能会好得多。因此,IsDecimal方法将变为:
private static bool IsDecimal(string text)
{
var regex = @"^-?(0|[1-9]\d*)(\.\d+)?$";
return Regex.Match(text, regex).Success;
}
第二个建议是将if-else块转换为if块。因此,这一行:
stringToClean[i] = (stringToClean[i].IsDecimal()) ? stringToClean[i] : "";
将成为这个:
if (!stringToClean[i].IsDecimal())
{
stringToClean[i] = "";
}
答案 1 :(得分:0)
我建议重温流程设计。在适当的平衡中使用sql和ssis的功能。 使用siss循环浏览文件夹中的所有文件,并将原始文本行加载到新创建的原始表中。 然后使用sql代码进行其余处理。您可以使用charindex或patIndex函数拆分原始行,而SQL的一个好处是可以大大减少运行时间,因为您将在给定文件的单个事务中处理整个批处理。
另一个可能的好处是,您可能只需要为所有不同的文件创建一个原始表,该表具有三列-id,fileName和rawText。因此设计看起来像这样:
在SSIS中执行的步骤
使用SQL执行的步骤
patindex
或charindex
函数与replace
函数结合使用的单个选择语句使用数字语句保留数值数据,以使卡纸值无效。