2015-04-06 2 views
6

Скажем, у меня есть таблица с двумя частями составного ключа в и 4 записи, как следующее:Запрос WHERE_IN с составным ключом?

KEY_PART_1 KEY_PART_2 
A   1 
B   1 
C   2 
C   3 

Я хочу написать некоторые динамические SQL для выбора только записей B, 1 и С 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

Я не уверен, но я думаю, что вы хотите что-то вроде этого, который работает для почти всех РСУБД:

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 сканирования диапазона диапазона. Запрос Юстина выполнил бы одно сканирование диапазона индекса. Итак, производительность разумна, запрос Джастина лучше. –

2

После @Justin пещеры ответ, вот небольшой тестовый пример, чтобы показать, что Oracle сделал бы INDEX RANGE SCAN, а затем INLIST ITERATOR для следующего фильтра предиката:

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

Setup

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> 

Таким образом, это дает правильный вывод.

Давайте посмотрим объяснить план:

Case # 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 использует индекс.

Смежные вопросы