2013-05-13 189 views
5

我在將某個表中的數據批量插入新表時遇到一些問題。目標有點是這樣的:INSERT INTO/SELECT DISTINCT導致SYS_GUID的主鍵衝突

CREATE TABLE TEST_T (
     T_GUID RAW(16) DEFAULT SYS_GUID() NOT NULL, 
     T_VAL1 NUMBER(10) NOT NULL, 
     T_VAL2 VARCHAR2(10) NOT NULL, 
     PRIMARY KEY (T_GUID) 
) 

語句的簡化版本,我打算用數據來填充:

INSERT INTO TEST_T (T_VAL1, T_VAL2) 
SELECT DISTINCT 
    CAST(SUBSTR(zip_code, 1,1) AS NUMBER) as t_val1, 
    zip_code as t_val2 
FROM OTHER_TABLE_T 
WHERE ... 
ORDER BY t_val1 

因爲我沒有提供一個T_GUID看重的,我會一直假定我會得到一個由SYS_GUID函數爲每個新行提供的函數。但是出了問題,我得到了主鍵的唯一性約束違規。

如果我刪除DISTINCT,語句成功,但我得到大量重複條目。當然,如果我在我的SELECT中明確提供SYS_GUID()呼叫,那麼結果完全相同。

現在我發現,如果我只是把另一SELECT圍繞礦山,它的作品了好了,不違反約束和不同行得到插入:

INSERT INTO ... 
SELECT x.* FROM (
    SELECT DISTINCT ... 
) x 

所以,你在哪裏的重複的GUID從何而來?如果整行行沒有問題,爲什麼要通過不同的原因排除行?由於SYS_GUID爲每個調用創建一個唯一的標識符,我只能想象,在不同的情況下,它只會被整個子句調用一次,這由周圍的包裝SELECT解決。如果有人能夠解釋這種情況下的執行情況如何,我會非常高興。

+0

確定的GUID是重複?仔細看看它們,它們看起來很相似,但你應該注意到它們每個都至少有一個不同的字符。 – GriffeyDog 2013-05-13 16:00:31

+0

您的代碼看起來正確。您可能會碰到一個Oracle錯誤,請查看「在My Oracle Support上,在AIX上生成的DUPLICATE SYS_GUID可能導致排隊期間發生ORA-1錯誤[ID 1371805.1]」。 – 2013-05-13 18:33:46

回答

0

將CAST替換爲to_number()並添加guid。測試你的選擇,然後再插入...:

SELECT DISTINCT 
    sys_guid() guid 
    To_Number(SUBSTR(zip_code, 1,1)) as t_val1, 
    zip_code as t_val2 
FROM OTHER_TABLE_T 
/

鮮明的GUID例如:

SELECT sys_guid() gid, deptno 
    FROM 
(
SELECT distinct deptno FROM scott.emp 
) 
ORDER BY deptno 
/

GID         DEPTNO 
------------------------------------------- 
DC9B9132492C1A45E04011AC3EEB463A 10 
DC9B9132492B1A45E04011AC3EEB463A 20 
DC9B9132492A1A45E04011AC3EEB463A 30 
+0

感謝您提供'to_number'建議,但這並不能真正解決我的主要問題。如果我將一個sys_guid引入到select中,那麼distinct將不會過濾掉任何重複的行(例如,如果我有多行具有相同的zip_code,但是具有不同的其他列)。 – mhd 2013-05-13 15:12:28

+0

@mhd - 然後擺脫不同的使用組或存在的運營商等...爲什麼使用guid而不是某種類型的序列... – Art 2013-05-13 16:21:14

+0

設計選擇在這裏工作,大多數表格有GUID作爲ID PKs。是的,有幾種解決方法可能,我用一個簡單的包裝SELECT解決了我的問題。但是這有點像舊的「醫生,當我這樣做時我的手臂很痛」/「那麼不要這樣做」的笑話。對於我自己的個人教育,我想知道原文有什麼問題,關係模型的概念是否不好,或者它只是一個錯誤。 – mhd 2013-05-14 08:58:31

1

嘗試是這樣的:

insert into test_t(t_guid, t_val1, t_val2) 
    select sys_guid(), t_val1, t_val2 
    from (select distinct to_number(substr(zip_code, 1, 1)) as t_val1, zip_code as t_val2 
      from other_table_t 
      where ...) 
+0

我甚至不需要那樣做。正如我上面寫的,只要我從中選擇*(選擇不同...),它就可以工作。我只是沒有很好的解釋。 – mhd 2013-05-13 16:15:21