将 Maxmind CSV 导入 SQL Server

Posted

技术标签:

【中文标题】将 Maxmind CSV 导入 SQL Server【英文标题】:Importing Maxmind CSV into SQL Server 【发布时间】:2012-04-05 04:07:40 【问题描述】:

我已经从 Maxmind - http://www.maxmind.com/app/geolitecountry 下载了 GeoLiteCountry CSV 文件。使用提供给我的标准格式(以便这可以成为一项自动化任务)我正在尝试将所有数据导入表中。

我创建了一个新表 IPCountries2,其中的列与提供的列完全匹配:

FromIP       varchar(50),
ToIP         varchar(50),
BeginNum     bigint,
EndNum       bigint,
CountryCode  varchar(50),
CountryName  varchar(250)

使用我能找到的各种代码块,我无法使用字段终止符和行终止符让它工作:

BULK
INSERT CSVTest
FROM 'c:\csvtest.txt'
WITH
(
    FIELDTERMINATOR = '","',
    ROWTERMINATOR = '\n'
)
GO

结果是插入了一行,除了最后一行溢出了下一行(如果我没有限制的话,大概是整个数据库)。此外,第一个单元格的开头有一个引号。

我环顾四周,发现了一个叫做格式文件的东西(从未使用过这些文件)。做了一个看起来像:

10.0
6
1   SQLCHAR     0   50  "," 1   FromIP      ""
2   SQLCHAR     0   50  "," 2   ToIP        ""
3   SQLBIGINT   0   19  "," 3   BeginNum    ""
4   SQLBIGINT   0   19  "," 4   EndNum      ""
5   SQLCHAR     0   50  "," 5   CountryCode ""
6   SQLCHAR     0   250 "\n"    6   CountryName ""

但在 bigint 行上出现此错误:

消息 4867,第 16 级,状态 1,第 1 行 第 1 行第 3 列 (BeginNum) 的批量加载数据转换错误(溢出)。

它这样做了 10 次,然后由于最大错误计数而停止。

如果我将第一个方法放入 Excel 并重新保存,我就可以使用它,这会删除引号。但是,我不想依赖这种方法,因为我希望它每周自动更新,而不必手动打开和重新保存。

我不介意最终使用这两种方法中的哪一种,只要它适用于干净的文件即可。我查看了他们的文档,但他们只有 php 或 MS Access 的代码。

编辑

CSV 文件中的一些行:

"1.0.0.0","1.0.0.255","16777216","16777471","AU","Australia"
"1.0.1.0","1.0.3.255","16777472","16778239","CN","China"
"1.0.4.0","1.0.7.255","16778240","16779263","AU","Australia"
"1.0.8.0","1.0.15.255","16779264","16781311","CN","China"
"1.0.16.0","1.0.31.255","16781312","16785407","JP","Japan"
"1.0.32.0","1.0.63.255","16785408","16793599","CN","China"
"1.0.64.0","1.0.127.255","16793600","16809983","JP","Japan"
"1.0.128.0","1.0.255.255","16809984","16842751","TH","Thailand"
"1.1.0.0","1.1.0.255","16842752","16843007","CN","China"
"1.1.1.0","1.1.1.255","16843008","16843263","AU","Australia"
"1.1.2.0","1.1.63.255","16843264","16859135","CN","China"
"1.1.64.0","1.1.127.255","16859136","16875519","JP","Japan"
"1.1.128.0","1.1.255.255","16875520","16908287","TH","Thailand"

更新

经过一番坚持,我能够使用原始方法(没有格式文档)使事情正常工作 95%。但是,它稍作改动,看起来像这样:

BULK INSERT IPCountries2
FROM 'c:\Temp\GeoIPCountryWhois.csv'
WITH
(
    FIELDTERMINATOR = '","',
    ROWTERMINATOR = '"'
)
GO

一切都在正确的字段中,我唯一的问题是在第一列的开头有一个引号。一些示例数据:

FromIP  ToIP    BeginNum    EndNum  CountryCode Country
 "2.21.248.0    2.21.253.255    34994176    34995711    FR  France
 "2.21.254.0    2.21.254.255    34995712    34995967    EU  Europe
 "2.21.255.0    2.21.255.255    34995968    34996223    NL  Netherlands

【问题讨论】:

你能贴出 CSV 文件的前几行数据吗? 啊,我真傻,在我的 OP 中找到 在原始批量插入中,您将 FIELDTERMINATOR 指定为 '","'。为什么逗号两边有双引号? 如果我不指定引号,我会得到 Msg 4864, Level 16, State 1, Line 1 第 1 行的批量加载数据转换错误(指定代码页的类型不匹配或无效字符) ,第 3 列 (BeginNum)。。大概这是因为它试图将引号符号插入到无法处理的字段中(即 bigint) 【参考方案1】:
declare @sql varchar(1000)
declare @filename varchar(100) = 'C:\Temp\GeoIPCountryWhois.csv'

set @sql = 
'BULK INSERT geoip FROM ''' + @filename + ''' 
WITH
(
CHECK_CONSTRAINTS,
FIELDTERMINATOR = '','',
ROWTERMINATOR = ''' + char(0x0A) + '''
)'
exec (@sql)

【讨论】:

【参考方案2】:

成功。 Searching around 和 another forum 的一些帮助终于让我找到了我的解决方案。对于那些需要类似解决方案的人,请继续阅读:

我最终使用了格式文件方法——我不确定是否可以使用字段终止符和行终止符。

我的 SQL 代码如下所示:

CREATE TABLE #TempTable
(
    DuffColumn  varchar(50),
    FromIP      varchar(50),
    ToIP        varchar(50),
    BeginNum    bigint,
    EndNum      bigint,
    CountryCode varchar(50),
    CountryName varchar(250)
)

BULK
INSERT #TempTable
FROM 'c:\Temp\GeoIPCountryWhois.csv'
WITH
(
    FORMATFILE = 'C:\Temp\format.fmt'
)

INSERT INTO IPCountries2 (FromIP, ToIP, BeginNum, EndNum, CountryCode, Country)
    SELECT FromIP, ToIP, BeginNum, EndNum, CountryCode, CountryName FROM #TempTable

在我的研究中发现,有必要有一个无用的列,它只是捕获了第一个引用。

我的格式文件如下:

10.0
7
1   SQLCHAR     0   1   ""      1   DuffColumn  ""
2   SQLCHAR     0   50  "\",\"" 2   FromIP      ""
3   SQLCHAR     0   50  "\",\"" 3   ToIP        ""
4   SQLCHAR     0   19  "\",\"" 4   BeginNum    ""
5   SQLCHAR     0   19  "\",\"" 5   EndNum      ""
6   SQLCHAR     0   50  "\",\"" 6   CountryCode ""
7   SQLCHAR     0   250 "\"\n"  7   CountryName ""

要注意,尽管最终存储为 BIGINT,BeginNum 和 EndNum 都作为 SQLCHARS 传入,否则插入对数字进行奇数乘法(关于将其读取为字节而不是数字,我没有完全明白了)。

就是这样。完全自动化此脚本的最后一件事是首先截断表以清除旧记录。然而,这可能不是每个人的需要。

【讨论】:

【参考方案3】:

试试这个命令。我所做的只是从您的 FIELDTERMINATOR 中删除双引号:

BULK
INSERT CSVTest
FROM 'c:\csvtest.txt'
WITH
(
    FIELDTERMINATOR = ',',
    ROWTERMINATOR = '\n'
)
GO

您的数据字段实际上以逗号结尾,而不是用引号括起来的逗号。我还建议构建一个与源文件的数据类型完全匹配的暂存/导入表,在这种情况下看起来像:

FromIP       varchar(50),
ToIP         varchar(50),
BeginNum     varchar(50),
EndNum       varchar(50),
CountryCode  varchar(50),
CountryName  varchar(250)

BeginNum 和 EndNum 的源数据实际上是字符串,而不是 bigint。将这些数据导入临时表后,您就可以对其进行转换。

【讨论】:

请看我对 OP 的评论,遗憾的是这无济于事

以上是关于将 Maxmind CSV 导入 SQL Server的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MySQL 中创建数据库以导入 Maxmind GeoLite2 city csv

将 MaxMind 的 GeoLite2 导入 MySQL

oracle导入csv文件

在 SQL Server 中查询 Maxmind GeoLite2 City Blocks csv 以获取 IPv6 和 IPv4 地址的 geoname_id

sql [sql] [csv]将csv文件导入数据库表

如何把csv文件导入到sql数据库