生成唯一的主键

时间:2014-06-19 19:21:06

标签: c# sql sql-server xml

我有一个SQL Server数据库,它将包含许多连接的表,每个表都有一个主键。我有一个Dictionary跟踪每个表的主键字段。我的任务是每天从以属性为中心的XML文件中提取数据,并将它们插入到主数据库中。每个XML文件都具有相同的架构。我是通过使用XMLReader并将数据导入DataSet

来实现此目的的

我无法使用AutoNumber作为密钥。假设昨天的XML文件生成了DataTable,类似于以下内容,并将其导入数据库

-------------------------------------
| Key | Column1 | Column2 | Column3 |
|-----------------------------------|
|  0  | dsfsfsd | sdfsrer | sdfsfsf |
|-----------------------------------|
|  1  | dertert | qweqweq | xczxsdf |
|-----------------------------------|
|  2  | prwersd | xzcsdfw | qwefkgs |
-------------------------------------

如果今天的XML文件产生以下DataTable

-------------------------------------
| Key | Column1 | Column2 | Column3 |
|-----------------------------------|
|  0  | sesdfsd | hjghjgh | edrgffb |
|-----------------------------------|
|  1  | wrwerwr | zxcxfsd | pijghjh |
|-----------------------------------|
|  2  | vcbcvbv | vbnvnbn | bnvfgnf |
-------------------------------------

然后当我使用SqlBulkCopy将新数据导入数据库时​​,会有重复的键。我的解决方案是使用DateTime.Now.Ticks生成唯一键。从理论上讲,这应该始终创建一个唯一的密钥。

但是,出于某种原因,DateTime.Now.Ticks并不是唯一的。例如,一行中的5个记录可能都具有键635387859864435908,并且接下来的7个记录可能具有键635387859864592164,即使我在不​​同时间生成该值。我想说问题的原因是我的脚本在更新时间之前多次调用DateTime.Now.Ticks

其他人可以想到更好的生成密钥的方法吗?

3 个答案:

答案 0 :(得分:3)

出于性能原因,DateTime.Now的值可能会缓存一小段时间。我们做了类似的事情,我们使用了两种可能的选项:

  1. 保留您在服务器上使用的数字列表,如果您可以确定已使用的数字,请增加
  2. 将字段转换为字符串,并在其末尾附加GUID或其他随机标识符。可以使用System.Guid.NewGuid().ToString();
  3. 创建GUID

    显然,这些计划都不会使碰撞风险为零,但它们可以帮助减少碰撞。

答案 1 :(得分:2)

如果您有大量数据,并且每行需要一个唯一的密钥,请使用GUID

答案 2 :(得分:0)

您可以执行以下操作来获取唯一ID(SQL Fiddle):

SELECT
CONCAT(YEAR(GETDATE()), DATEDIFF(DAY, STR(YEAR(GETDATE()), 4) + '0101',
GETDATE() ) + 1,  ROW_NUMBER() OVER(ORDER BY id DESC)) UniqueID
FROM supportContacts s

如果您每天只运行一次查询,这将有效。如果你每天运行多次,你需要抓住秒或其他东西(SQL Fiddle):

SELECT CONCAT(CurrYear, CurrJulian, CurrSeconds, Row) AS UniqueID
FROM
(
  SELECT
  YEAR(GETDATE()) AS CurrYear, 
  DATEDIFF(DAY, STR(YEAR(GETDATE()), 4) + '0101', GETDATE() ) + 1 AS CurrJulian,  
  ROW_NUMBER() OVER(ORDER BY id DESC) AS Row,
  datediff(second, left(convert(varchar(20), getdate(), 126), 10), getdate()) AS CurrSeconds
  from supportContacts s
) AS m