2015-04-06 10 views
6

Diciamo che ho una tabella con una chiave composta in due parti, e 4 record, come il seguente:WHERE_IN query con una chiave composta?

KEY_PART_1 KEY_PART_2 
A   1 
B   1 
C   2 
C   3 

voglio scrivere un po 'di SQL dinamico per selezionare solo i record B, 1 e C, 2 utilizzando una clausola "WHERE IN", senza selezionando A, 1 o C, 3.

C'è un modo per farlo senza un tavolo temporaneo?

Non è importante, ma attualmente stiamo usando Oracle e speriamo di passare presto a PostgreSQL.

risposta

12

Questa sintassi funziona per Oracle e PostgreSQL:

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

Non so se Oracle ha lo stesso problema, ma in MySQL se si utilizza questa sintassi non verrà utilizzato l'indice. – Barmar

+1

Funziona bene anche in Postgres. –

0

Non sono sicuro, ma penso che si desidera qualcosa di simile che funziona per quasi tutti i 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

Solo una nota, anche se questa query fornirebbe l'output desiderato. Tuttavia, questa query andrà per 2 scansioni dell'indice. La query di Justin farebbe una singola scansione dell'intervallo dell'indice. Quindi, per quanto riguarda le prestazioni, la domanda di Justin è migliore. –

2

seguito @Justin Cave di risposta, ecco un piccolo test case per dimostrare che Oracle farebbe una INDEX RANGE SCAN seguito da un INERITORE ITERATORE consultato filtro predicato:

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> 

Un indice composito su key1 e key2:

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

Index created. 

SQL> 

Raccogliere statistiche:

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

PL/SQL procedure successfully completed. 

SQL> 

eseguire la query:

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

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

SQL> 

Quindi, dà l'output corretto.

Vediamo il spiegano piano di:

Caso # 1 coppia di valori-chiave nello stesso ordine dell'indice. Chiave principale in testa.

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. 

Caso # 2 coppia chiave-valore in ordine inverso dell'indice. Chiave principale al contrario.

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. 

In entrambi i casi, Oracle utilizza l'indice.

Problemi correlati