2015-04-06 71 views
6

比方說,我有兩部分的複合鍵的表,和4個記錄,類似如下:WHERE_IN使用組合鍵查詢?

KEY_PART_1 KEY_PART_2 
A   1 
B   1 
C   2 
C   3 

我想寫一些動態SQL只選擇記錄B,1和C 2使用「WHERE IN」子句,沒有選擇A,1或C,3。

有沒有辦法做到這一點,沒有臨時表?

這並不重要,但我們目前正在使用Oracle,並希望儘快遷移到PostgreSQL。

回答

12

該語法同樣適用於Oracle和PostgreSQL:

SELECT * 
    FROM table_name 
WHERE (key_part_1, key_part_2) IN (('B',1), ('C',2)); 
+1

不知道Oracle是否有相同的問題,但在MySQL中如果使用這種語法,它不會使用索引。 – Barmar

+1

它在Postgres中工作得很好。 –

0

我不知道,但我想你想是這樣的,其適用於幾乎所有的RDBMS:

select KEY_PART_1, KEY_PART_2 from your_table where KEY_PART_1='B' and KEY_PART_2 = '1' 
UNION 
select KEY_PART_1, KEY_PART_2 from your_table where KEY_PART_1='C' and KEY_PART_2 = '2' 
+0

只是一個註釋,雖然這個查詢會給出所需的輸出。但是,此查詢將用於2個索引範圍掃描。 Justin的查詢將執行單個索引範圍掃描。所以,性能方面,賈斯汀的質詢更好。 –

2

繼@Justin洞的回答,這裏有一個小測試用例來表明Oracle會做INDEX RANGE SCAN後面跟着INLIST ITERATOR以下過濾謂詞

WHERE (key_part_1, key_part_2) IN (('B',1), ('C',2)) 

設置

SQL> CREATE TABLE t(key1 VARCHAR2(1), key2 NUMBER); 

Table created. 

SQL> 
SQL> INSERT INTO t VALUES('A', 1); 

1 row created. 

SQL> INSERT INTO t VALUES('B', 1); 

1 row created. 

SQL> INSERT INTO t VALUES('C', 2); 

1 row created. 

SQL> INSERT INTO t VALUES('C', 3); 

1 row created. 

SQL> 
SQL> COMMIT; 

Commit complete. 

SQL> 

KEY1和KEY2綜合指數

SQL> CREATE INDEX t_idx ON t(key1, key2); 

Index created. 

SQL> 

收集相關統計數據:

SQL> EXEC DBMS_STATS.gather_table_stats('LALIT', 'T'); 

PL/SQL procedure successfully completed. 

SQL> 

執行查詢:

SQL> SELECT * FROM t 
    2 WHERE (key1, key2) IN (('B',1), ('C',2)); 

K  KEY2 
- ---------- 
B   1 
C   2 

SQL> 

所以,它給正確的輸出。

讓我們來看看解釋計劃

案例#1鍵值對索引的順序相同。領先的關鍵。

SQL> SELECT * FROM TABLE(dbms_xplan.display); 

PLAN_TABLE_OUTPUT 
-------------------------------------------------------------------------------- 
Plan hash value: 2301620486 

--------------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
--------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |  |  2 | 10 |  1 (0)| 00:00:01 | 
| 1 | INLIST ITERATOR |  |  |  |   |   | 
|* 2 | INDEX RANGE SCAN| T_IDX |  2 | 10 |  1 (0)| 00:00:01 | 
--------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 

PLAN_TABLE_OUTPUT 
-------------------------------------------------------------------------------- 
--------------------------------------------------- 

    2 - access(("KEY1"='B' AND "KEY2"=1 OR "KEY1"='C' AND "KEY2"=2)) 

14 rows selected. 

情況#2鍵 - 值對中的索引的順序相反。領先鑰匙反向。

SQL> EXPLAIN PLAN FOR SELECT * FROM t 
    2 WHERE (key2, key1) IN ((1, 'B'), (2, 'C')); 

Explained. 

SQL> 
SQL> SELECT * FROM TABLE(dbms_xplan.display); 

PLAN_TABLE_OUTPUT 
-------------------------------------------------------------------------------- 
Plan hash value: 2301620486 

--------------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
--------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |  |  2 | 10 |  1 (0)| 00:00:01 | 
| 1 | INLIST ITERATOR |  |  |  |   |   | 
|* 2 | INDEX RANGE SCAN| T_IDX |  2 | 10 |  1 (0)| 00:00:01 | 
--------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 

PLAN_TABLE_OUTPUT 
-------------------------------------------------------------------------------- 
--------------------------------------------------- 

    2 - access(("KEY1"='B' AND "KEY2"=1 OR "KEY1"='C' AND "KEY2"=2)) 

14 rows selected. 

在任一情況下,Oracle使用索引