从数据库列创建唯一的主键(哈希)

时间:2009-08-25 17:10:39

标签: sql oracle primary-key hash

我有这个没有主键的表。

我将在一个新表中插入一些记录来分析它们,我正在考虑用所有可用列的值创建一个新的主键。

如果这是像Java这样的编程语言,我会:

 int hash = column1 * 31 + column2 * 31 + column3*31 

或类似的东西。但这是SQL。

如何根据可用列的值创建主键?简单地将所有列标记为PK对我来说不起作用,因为我需要做的是将它们与来自其他DB表的数据进行比较。

我的桌子上有3个号码和一个日期。

编辑我的问题是什么

我认为需要更多背景知识。我很抱歉没有提供它。

我有一个数据库(dm),每天从另一个db(原始源)更新。它有过去两年的记录。

上个月(7月)更新过程中断,一个月内没有数据更新到dm。

我在Oracle XE中手动创建一个具有相同结构的表,然后将原始源中的记录复制到我的db(myxe)中,我从7月份仅复制了记录,以创建月末所需的报告。

最后在8月8日,更新过程得到修复,并且等待通过此自动过程迁移的记录被复制到数据库中(从originalsource到dm)。

此过程会在复制数据(到dm)后从原始源清除数据。

一切看起来都不错,但我们刚刚意识到有一些记录丢失了(约占7月份的25%)

所以,我想要做的是使用我的备份(myxe)并将所有缺失的记录插入数据库(dm)。

这里的问题是:

  • 他们没有明确的PK。
  • 他们在不同的数据库中。

所以我想如果我可以从两个表创建一个唯一的pk,它给出了相同的数字,我可以分辨出哪些丢失并插入它们。

编辑2

所以我在当地环境中做了以下事情:

select a.* from the_table@PRODUCTION a , the_table b where
a.idle = b.idle and 
a.activity = b.activity and 
a.finishdate = b.finishdate

返回两个数据库中存在的所有行(... union?)我有2000条记录。

接下来要做的是从目标数据库中删除它们,然后将它们从我的数据库中的所有内容插入到目标表中

我希望我没有陷入最糟糕的事情: - S:-S

4 个答案:

答案 0 :(得分:3)

只需创建一个代理键:

ALTER TABLE mytable ADD pk_col INT

UPDATE  mytable
SET     pk_col = rownum

ALTER TABLE mytable MODIFY pk_col INT NOT NULL

ALTER TABLE mytable ADD CONSTRAINT pk_mytable_pk_col PRIMARY KEY (pk_col)

或者这个:

ALTER TABLE mytable ADD pk_col RAW(16)

UPDATE  mytable
SET     pk_col = SYS_GUID()

ALTER TABLE mytable MODIFY pk_col RAW(16) NOT NULL

ALTER TABLE mytable ADD CONSTRAINT pk_mytable_pk_col PRIMARY KEY (pk_col)

后者使用GUID,它们在数据库中是唯一的,但占用的空间更多,生成速度要慢得多(INSERT的速度会很慢)

<强>更新

如果您需要在具有相同数据的两个表上创建相同的PRIMARY KEY,请使用以下命令:

MERGE
INTO    mytable v
USING   (
        SELECT  rowid AS rid, rownum AS rn
        FROM    mytable
        ORDER BY
                co1l, col2, col3
        )
ON      (v.rowid = rid)
WHEN MATCHED THEN
UPDATE
SET     pk_col = rn

请注意,表格应该相同,直到一行(即具有相同数量的行,其中包含相同的数据)。

Update 2

对于您的问题,您根本不需要PK

如果您只想选择dm中缺少的记录,请使用此记录(在dm侧)

SELECT  *
FROM    mytable@myxe
MINUS
SELECT  *
FROM    mytable

这将返回mytable@myxe但不在mytable@dm

中的所有记录

请注意,如果有的话,它会缩小所有重复项。

答案 1 :(得分:3)

通过组合3个数字和日期来创建哈希值的危险在于它可能不是唯一的,因此不能安全地用作主键。

相反,我建议您为主键使用自动增量ID。

答案 2 :(得分:1)

假设您确保了唯一性......您可以在SQL中执行几乎相同的操作。唯一的问题是将日期转换为数值,以便您可以对其进行哈希处理。

Select Table2.SomeFields 
    FROM Table1 LEFT OUTER JOIN Table2 ON
        (Table1.col1 * 31) + (Table1.col2 * 31) + (Table1.col3 * 31) + 
            ((DatePart(year,Table1.date) + DatePart(month,Table1.date) + DatePart(day,Table1.date) )* 31) = Table2.hashedPk

上述查询适用于SQL Server,Oracle的唯一区别在于您处理日期转换的方式。此外,还有其他功能用于在SQL Server中转换日期,因此这绝不是唯一的解决方案。

并且,您可以将此与Quassnoi的SET语句结合使用以填充新字段。只需使用Join条件逻辑的左侧作为值。

答案 3 :(得分:1)

如果您使用旧表中的值加载新表,然后需要加入这两个表,则只有在能够唯一标识原始表中的每一行时才能“正确”执行此操作。 Quassnoi的解决方案将允许您执行此操作,如果您可以通过添加新列来更改旧表。

如果您无法更改原始表,则可以使用基于旧表的列生成某种形式的哈希代码 - 但是,仅当哈希码唯一标识每一行时才会生效。 (Oracle有校验和功能,对吗?如果有,请使用它们。)

如果无法保证哈希码唯一性,则可能必须满足由确保唯一性所需的多列组成的主键(例如,自然键)。如果没有自然键,那么,我曾经听说Oracle为每行数据提供了一个rownum,你可以使用它吗?