65.9K
CodeProject 正在变化。 阅读更多。
Home

获取与邮政编码相对应的地名

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.07/5 (11投票s)

2009年1月22日

CPOL

4分钟阅读

viewsIcon

34452

downloadIcon

358

如何将 GeoNames.org 的数据库转储导入 SQL Server

引言

有各种 Web 服务可以在您输入邮政编码时提供相应的地点名称。GeoNames 就是这样一个服务。

作为一项额外服务,GeoNames 在知识共享 3.0 许可下提供数据库。首先,您需要从他们最新的数据库转储中下载特定国家的 zip 文件并解压。

Using the Code

如果您只对将数据导入数据库感兴趣,那么可以运行演示。输入一个有效的连接字符串,将文件对话框指向您解压的下载文件,然后等待进度条填满。

源代码相对简单,因为这是一个直接的导入任务。导入逻辑 nicely 封装在“FormMain.ImportProcedure.cs”文件中。该文件包含基于 foreach 循环的 BackgroundWorker 逻辑。

private void backgroundWorker1_DoWork
	(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    [...]

    string[] lines = File.ReadAllLines(args.SourceFileName, Encoding.UTF8);

    foreach (string line in lines)
    {
        //The data format is tab-delimited text in utf8 encoding..
        string[] items = line.Split('\t');

        IDbCommand sqlInsertItem = db.NewCommand(sqlInsertIntoImportTable);
        sqlInsertItem.Parameters.Add(db.NewParam("countrycode", items[0]));
        [...]
        sqlInsertItem.Parameters.Add(db.NewParam("longitude", items[9]));
        sqlInsertItem.Parameters.Add(db.NewParam("accuracy", items[10]));
        sqlInsertItem.ExecuteNonQuery();

支持不同的数据库驱动程序

此版本支持多种数据库格式,并已在 SQL Server、Microsoft Access、SQL CE、SQLite、Oracle XE 和 Microsoft Excel 中进行了测试。

导入逻辑不需要知道所用数据库驱动程序的具体细节,而是使用了一个接口。接口被替换为用户选择的等效驱动程序,在运行时创建对象来替换 IConnection。创建适当对象的任务由内部 DataInterface 类通过调用 static New 方法完成。

然后,此方法会根据用户在下拉列表中选择的驱动程序进行 switch。如果用户想要 SqlClient,我们将返回一个 SqlConnection。如果用户想要 OracleClient 连接,我们将返回一个促进 Oracle 的连接。

    switch (dbType)
    {
        case DataProvider.ODBC:
            {
                result._con = new System.Data.Odbc.OdbcConnection(connectionString);
                break;
            }
        case DataProvider.OleDB:
            {
                result._con = new System.Data.OleDb.OleDbConnection(connectionString);
                break;
            }
        case DataProvider.OracleClient:
            {
                result._con = 
		new System.Data.OracleClient.OracleConnection(connectionString);
                break;
            }
        case DataProvider.SqlClient:
            {
                result._con = new System.Data.SqlClient.SqlConnection(connectionString);
                [...]

可以通过打开连接并发布包含 SQL 语句的 IDbCommands 来访问这些数据库中的每一个。大多数数据库可以处理 ANSI SQL 命令。有关 ANSI 标准的更多信息,请参阅 Asher Barak 的文章“Server Indifferent SQL”。

连接字符串

一些在测试此代码时使用的示例连接及其测试结果

SQL Server Express 2005 (提供程序: SqlClient)

Server=.\SQLEXPRESS;Database=master;Trusted_Connection=True;

16377 条记录,耗时 1 分钟 4 秒 - 平均每条记录 0.0039 秒。

Microsoft Access (提供程序: OleDB)

Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\database1.mdb;User Id=admin;Password=;

16377 条记录,耗时 54 秒,平均每条记录 0.0033 秒。

SQL CE (提供程序: SqlCe)

Data Source=C:\MyDatabase1.sdf;

16377 条记录,耗时 38 秒,平均每条记录 0.023 秒。

SQLite (提供程序: SQLite)

Data Source=C:\Database.sqlite;Version=3;

16377 条记录,耗时 22 分钟 31 秒,平均每条记录 0.0825 秒。

Oracle XE 10g (提供程序: OracleClient)

Data Source=XE;User Id=Anonymous;Password=Password;

16377 条记录,耗时 48 秒,平均每条记录 0.0030 秒。

Microsoft Excel 2007 (提供程序: OleDb)

Provider=Microsoft.ACE.OLEDB.12.0;Data Source=c:\Map1.xlsx;
	Extended Properties="Excel 12.0 Xml;HDR=YES";

16377 条记录,耗时 1 分钟 3 秒,平均每条记录 0.0039 秒。

还需要多久

有一个 ProgressBar 提供关于我们进度的视觉反馈。此进度条会根据我们机器的速度快或慢地填充。如果进度条填充得太慢,我们的反馈值就会下降——因为用户没有得到真实的反馈——他只是在等待进度条中出现另一个条,而不知道这个下一个条何时出现。

一种选择是使进度条更长,从而提供更精细的进度指示。另一种选择是添加一个“估计等待时间”,就像您在 Windows 资源管理器复制文件时看到的那样。当操作由耗时相等的多个工作块组成时,这将效果最好。我们需要跟踪操作开始的时间。接下来我们需要知道的是我们正在为当前操作工作了多久,所以我们从 startMoment 中减去当前日期/时间。

DateTime now = DateTime.Now;
TimeSpan span = now.Subtract(startMoment);

现在我们知道处理了多久,我们可以计算平均每个项目花了多长时间。

// how long does it take to do a single item?
double timePerItem = (span.TotalSeconds / progressBar1.Value);

一旦您知道平均项目处理需要多长时间(这是 progressBar 中的一个单独步骤),我们就可以计算出执行剩余操作(可能)需要多长时间。当您将鼠标指针悬停在 progressBar 上时,您可以看到结果。

注释

  • SQLite 比预期慢了不少。一定有一种更有效的方式来与 SQLite 数据库进行交互。
  • Oracle 不喜欢参数声明中的 @ 符号。运行时一直困扰我“ORA-01036: 非法的变量名/数字”的错误,直到 SQL 语句中的 @ 字符被替换为 : 字符。

历史

  • 2009 年 1 月 21 日 - 初始版本
  • 2009 年 2 月 8 日 - 解耦数据库依赖,并将导入逻辑移至 BackgroundWorker
© . All rights reserved.