比方說,我有兩部分的複合鍵的表,和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。
比方說,我有兩部分的複合鍵的表,和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。
該語法同樣適用於Oracle和PostgreSQL:
SELECT *
FROM table_name
WHERE (key_part_1, key_part_2) IN (('B',1), ('C',2));
我不知道,但我想你想是這樣的,其適用於幾乎所有的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'
只是一個註釋,雖然這個查詢會給出所需的輸出。但是,此查詢將用於2個索引範圍掃描。 Justin的查詢將執行單個索引範圍掃描。所以,性能方面,賈斯汀的質詢更好。 –
繼@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使用索引。
不知道Oracle是否有相同的問題,但在MySQL中如果使用這種語法,它不會使用索引。 – Barmar
它在Postgres中工作得很好。 –