2

我从客户端获取 CSV,我需要将该文件导入数据库。我经历了无数次迭代,部分解决方案测试无穷大。当我需要完整的解决方案时,我的问题就来了。

CSV 有 14 个字段,tempdb 数据库有 15 个字段(最后一个是标识列)。数据到达时没有身份,我需要根据数据库设计的行唯一编号。

我已经掩盖了显示的测试数据,但它可以模拟数据。

T2012-DAT;09-01-2012;09-01-2012;1;910,91;12;TST;4,55;200,2;6;;;;7,5
T2012-DAT;10-01-2012;10-01-2012;1;910,91;12;TST;4,55;200,2;6;;;;7,5
T2012-DAT;11-01-2012;11-01-2012;1;910,91;12;TST;4,55;200,2;6;;;;7,5
T2012-DAT;12-01-2012;12-01-2012;1;910,91;12;TST;4,55;200,2;6;;;;7,5
T2012-DAT;13-01-2012;13-01-2012;1;910,91;12;TST;4,55;200,2;6;;;;7
T2012-DAT;16-01-2012;16-01-2012;1;910,91;12;TST;4,55;200,2;6;;;;7,5

我在 tempdb 中创建的临时表。您会注意到它有 15 个字段,最后一个是所需的身份。

创建表预算导入(
    sBudgetName varchar(20) COLLATE Danish_Norwegian_CI_AS  
    , dStartDate varchar(12) COLLATE Danish_Norwegian_CI_AS  
    , dEndDate varchar(12) COLLATE Danish_Norwegian_CI_AS   
    , prCode 整数   
    , decTotal varchar(20) COLLATE Danish_Norwegian_CI_AS
    , sRefTimeTypeID varchar(10) COLLATE Danish_Norwegian_CI_AS  
    , sRefEmployeeID varchar(10) COLLATE Danish_Norwegian_CI_AS  
    , decHours varchar(20) COLLATE Danish_Norwegian_CI_AS  
    , decRate varchar(20) COLLATE Danish_Norwegian_CI_AS
    , sDepartmentID varchar(10) COLLATE Danish_Norwegian_CI_AS NULL  
    , sCentre varchar(10) 整理丹麦语_挪威语_CI_AS NULL  
    , 目的 varchar(10) COLLATE Danish_Norwegian_CI_AS NULL  
    , sProjectID varchar(10) COLLATE Danish_Norwegian_CI_AS NULL  
    , decNormHours varchar(20) COLLATE Danish_Norwegian_CI_AS  
    --, iRowNumber int identity(500000,1)  
)

-- 通过 csv 导入数据
 批量插入 BudgetImport
 FROM 'D:\budgetposter.csv'
 和
 (
    场终结者 = ';'
    , 行终止符 = '\r\n'
    , 代码页 = '1252'
 )

当我包含身份时,我收到此错误:

消息 4866,第 16 层,状态 1,第 3 行
批量加载失败。数据文件中第 1 行第 15 列的列太长。请验证是否正确指定了字段终止符和行终止符。

如果我排除它,错误将变为:

消息 4866,第 16 层,状态 1,第 3 行
批量加载失败。数据文件中第 1 行第 14 列的列太长。验证是否正确指定了字段终止符和行终止符。

如果我改变rowterminator = '\n' 它,它会通过,但我错过了身份。

如果我包括身份,则错误变为:

消息 4864,第 16 层,状态 1,第 3 行
第 1 行第 15 列 (iRowNumber) 的批量加载数据转换错误(指定代码页的类型不匹配或无效字符)。

当我测试时,我排除了INSERT INTO dbo."the-real-datatable"并且只是SELECT FROM BudgetImport单独做。因此,我避免在真实数据表中插入另外 16000 行。

如果您注意并了解匈牙利符号,您会注意到我使用的是 varchars,即使 datatime 或 decimal 可能是正确的形式。经过大约 4-6 小时的测试和无尽的头痛和撕裂的头发后,我正在这样做。Varchar 是 KISS 解决方案,我CONVERT()稍后再做。

我的整个问题围绕行中的最后一个字段解决。- 我尝试添加 1 和 2 ;在 decNormHours 之后,我尝试添加空值(;;或;1;或;n;)。- 我尝试过使用 formatfile.xml - 再次没有蛋糕。没有格式文件比使用它更成功。- 我尝试将英国数字符号更改为 . = 使用 DK 表示法更成功。- 我已经尝试了我能想出的每一个技巧,但无济于事。

是的,CSV 中没有身份字段,没关系。identity(500000,1)您只需使用我在表创建中描述的默认自动。哦,500000 是我现在达到的大约行 ID,它会随着时间的推移而增加。

拜托,接下来我需要做什么才能做到这一点?

编辑:
使用格式文件

$lt;? xml 版本=“1.0”?$gt;
$lt;BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"$gt;
 $lt;记录$gt;
  FIELD ID="1" xsi:type="NCharTerm" TERMINATOR=";" COLLATION="SQL_Latin1_General_CP1_CI_AS"/
  FIELD ID="2" xsi:type="CharFixed" LENGTH="9" COLLATION="SQL_Latin1_General_CP1_CI_AS"/
  FIELD ID="3" xsi:type="CharFixed" LENGTH="9" COLLATION="SQL_Latin1_General_CP1_CI_AS"/
  FIELD ID="4" xsi:type="NCharTerm" TERMINATOR=";"/
  FIELD ID="5" xsi:type="NCharTerm" TERMINATOR=";"/
  FIELD ID="6" xsi:type="NCharTerm" TERMINATOR=";" MAX_LENGTH="20" COLLATION="SQL_Latin1_General_CP1_CI_AS"/
  FIELD ID="7" xsi:type="NCharTerm" TERMINATOR=";" MAX_LENGTH="20" COLLATION="SQL_Latin1_General_CP1_CI_AS"/
  FIELD ID="8" xsi:type="NCharTerm" TERMINATOR=";"/
  FIELD ID="9" xsi:type="NCharTerm" TERMINATOR=";"/
  FIELD ID="10" xsi:type="NCharTerm" TERMINATOR=";" MAX_LENGTH="20" COLLATION="SQL_Latin1_General_CP1_CI_AS"/
  FIELD ID="11" xsi:type="NCharTerm" TERMINATOR=";" MAX_LENGTH="50" COLLATION="SQL_Latin1_General_CP1_CI_AS"/
  FIELD ID="12" xsi:type="NCharTerm" TERMINATOR=";" MAX_LENGTH="50" COLLATION="SQL_Latin1_General_CP1_CI_AS"/
  FIELD ID="13" xsi:type="NCharTerm" TERMINATOR=";" MAX_LENGTH="20" COLLATION="SQL_Latin1_General_CP1_CI_AS"/
  FIELD ID="14" xsi:type="NCharTerm" TERMINATOR=";"/
 /记录
 排
  COLUMN SOURCE="1" NAME="sBudgetName" xsi:type="SQLNVARCHAR" LENGTH="20" /
  COLUMN SOURCE="2" NAME="dStartDate" xsi:type="SQLDATETIME"/
  COLUMN SOURCE="3" NAME="dEndDate" xsi:type="SQLDATETIME"/
  COLUMN SOURCE="4" NAME="prCode" xsi:type="SQLSMALLINT"/
  COLUMN SOURCE="5" NAME="decTotal" xsi:type="SQLDECIMAL"/
  COLUMN SOURCE="6" NAME="sRefTimeTypeID" xsi:type="SQLNVARCHAR" LENGTH="10"/
  COLUMN SOURCE="7" NAME="sRefEmployeeID" xsi:type="SQLNVARCHAR" LENGTH="10"/
  COLUMN SOURCE="8" NAME="decHours" xsi:type="SQLDECIMAL"/
  COLUMN SOURCE="9" NAME="decRate" xsi:type="SQLDECIMAL"/
  COLUMN SOURCE="10" NAME="sDepartmentID" xsi:type="SQLNVARCHAR" LENGTH="10"/
  COLUMN SOURCE="11" NAME="中心" xsi:type="SQLNVARCHAR" LENGTH="10"/
  COLUMN SOURCE="12" NAME="Purpose" xsi:type="SQLNVARCHAR" LENGTH="10"/
  COLUMN SOURCE="13" NAME="sRefProjectID" xsi:type="SQLNVARCHAR" LENGTH="10"/
  COLUMN SOURCE="14" NAME="decNormHours" xsi:type="SQLDECIMAL"/
/排

让我回到正确的第一个领域。因此,从争取最终的细节正确开始,我最终会努力让它首先工作/做任何事情。错误:

消息 4863,第 16 层,状态 1,第 3 行
第 1 行第 1 列 (sBudgetName) 的批量加载数据转换错误(截断)。

注意:嗯似乎 SO 不喜欢 xml。多么奇怪。

4

1 回答 1

0

这比解决方案更像是一种解决方法,但是由于您面临列数问题,为什么不在之后添加索引列?

你可以做这样的事情:

  • 将您的 CSV 导入具有相同列数的临时表

然后,

ALTER TABLE BudgetImport
    ADD Id  INTEGER
GO

WITH Cte
AS
(
    SELECT *
    , ROW_NUMBER() OVER(ORDER BY [**column of your choice**] DESC) AS RowNumber
    FROM BudgetImport
)
UPDATE Cte
SET Id = RowNumber
GO

ALTER TABLE BudgetImport
ALTER COLUMN Id INTEGER NOT NULL 
GO

ALTER TABLE BudgetImport
ADD PRIMARY KEY (Id)
GO
于 2012-10-25T12:09:57.390 回答