2013-10-15 68 views
2

考慮一個表與一個複合主鍵:是否可以在where條件中使用列元組?

create table T (
    C1 int not null, 
    C2 int not null, 
    ... 
    primary key (C1, C2) 
) 

和檢索的行大於一定的主鍵元組的問題:

select * from T where (C1, C2) > (10, 100) 

上述僞語法無效上MSSQL和甲骨文。它可以實現爲:

select * from T where (C1 = 10 and C2 > 100) or (C1 > 10) 

PK的列數越多,得到的醜陋。有沒有這樣做的優雅方式(MSSQL和Oracle)?

此外,利用(C1,C2)上的唯一索引很重要。我不想連接字符串中的列來模擬元組,然後結束表掃描。

+0

我想我不明白你爲什麼認爲這是醜陋的。您要麼在where子句中添加更多列,要麼將更多列添加到組合鍵。只要你從pk中最左邊的列開始,就應該使用索引。我認爲如果它是一個覆蓋索引,你可以跳過列(但可能是錯誤的)。 – Andrew

+0

要看到醜陋,想象一下情況如何尋找10列。如果元組被支持,它就會是(c1,c2,c3,c4,c5,c6,c7,c8,c9,c10)>(?,?,?,?,?,?,?,?,? ?)。我會讓你填寫另一個,它是O(N^2)...另外,在我的真實情況下,這個SQL是動態的,因此生成顯式條件的複雜性更高。 –

+1

我認爲這個問題更多地屬於dba.stackexchange.com。 – Rachcha

回答

0

afair如果你真的只有2個int列 - 嘗試將它們合併成一個bigint,但是對於更多 - 你將需要在條件,好消息的情況下產生這樣的醜陋 - 它將使用主鍵索引並且工作得很快

0

如果您將JOIN表中的問題提交給另一個表(例如臨時表或變量表),則可以非常有效地獲得您正在查找的結果。我已經把一個簡單的測試是這樣的:

CREATE TABLE KeyTest 
(
    C1 INT NOT NULL 
    , C2 INT NOT NULL 
    CONSTRAINT PK_KeyTest PRIMARY KEY CLUSTERED (C1, C2) 
); 

INSERT INTO KeyTest (C1, C2) VALUES (
      CAST((RAND() * 1000E0) AS INT), 
      CAST((RAND() * 10000E0) + 1000 AS INT)); 
GO 100 

SELECT * FROM KeyTest; /* make note of a sample row for the next step 
            in my example, a randomly chosen row had 
            C1 = 275 and C2 = 6367 
          */ 


DECLARE @TestFilter TABLE 
(
    C1 INT NOT NULL 
    , C2 INT NOT NULL 
); 

INSERT INTO @TestFilter (C1, C2) VALUES (275,6366); 

SELECT KT.* 
FROM KeyTest KT 
    INNER JOIN @TestFilter TF ON KT.C1 = TF.C1 AND KT.C2 >= TF.C2; 

這將返回所有匹配C1和大於或等於C2與包含在@TestFilter的值,在我的例子275和6366.結果的行:

enter image description here

你可以很容易地改變這個返回其中複合關鍵比賽由C1值大於10的所有行:

INSERT INTO @TestFilter (C1, C2) VALUES (10,0); 

SELECT KT.* 
FROM KeyTest KT 
    INNER JOIN @TestFilter TF ON KT.C1 > TF.C1; 
+0

這不回答問題。預先指定參數和通過表連接添加間接級別沒有區別。此外,你錯過了C1> 10的條件。 –

+0

你是對的,我沒有真正使用'C1> 10',而是我的例子使用的值大於C2-'KT.C2> = TF.C2'。 JOIN允許您輕鬆選擇各行,而無需更改實際的SQL語句,並允許多個選擇。我的示例在@TestFilter中只有一行,但它可以很容易地包含很多行。 –

+0

使用這樣的JOIN還允許SQL Server優化語句執行。 –

0

你所尋找的是粘鍵的比較:

 
'11000' > '10100' 
'10101' > '10100' 
'10099' < '10100' 
'09999' < '10100' 

要做到這一點,你需要一個虛擬列。在Oracle中,你會只是建立一個函數索引,在SQL Server中,你會首先創建一個計算列,並以此爲基礎的指數。

你可以寫一個確定的粘貼功能粘上你的鑰匙在一起,並使用這個(!):

alter table T add column GluedKeys as GlueTKeys(c1,c2,c3,c4,c5); 

create index IndexGluedTKeys on T(GluedKeys); 

select * from T where GluedKeys > GlueTKeys(?,?,?,?,?); 

注意的單按鍵多長時間都可以。千萬不要粘上10 + 100至10100和20 + 10到2010年,而是20 + 10至20010

+0

我知道這不符合您要求使用主鍵索引的要求。它確實使用索引,而且SQL看起來很整潔。 –

0

在評論你的問題,你此話,在你的真實情況下,SQL是動態的。那麼,爲什麼甚至不屑?您可以輕鬆地在生產循環創建N個按鍵的聲明 「......(C1> 10)或(C1 = 10和c2> 100)或(C1 = 10和c2 = 100和C3> ...」。

那可以或不可以使用你的PK指數我敢說,有這麼多的ORS很可能不使用你將不得不迫使它則:

select * 
from T with (index(pk_t)) 
where ... 
+0

我測試了它並且實際使用了索引。這是一個非常令人驚喜的事情。 –

相關問題