Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WHERE_IN query with a composite key?

Tags:

sql

oracle

Let's say I have a table with a two-part composite key, and 4 records, like the following:

KEY_PART_1 KEY_PART_2
A          1
B          1
C          2
C          3

I want to write some dynamic SQL to select only the records B,1 and C,2 using a "WHERE IN" clause, without selecting A,1 or C,3.

Is there some way to do this without a temp table?

Not that it matters, but we are currently using Oracle, and hoping to move to PostgreSQL soon.

like image 627
Kevin Pauli Avatar asked Apr 06 '15 21:04

Kevin Pauli


People also ask

How do I use composite key in PostgreSQL?

Composite Primary Key's Syntax in PostgreSQL We use the “PRIMARY KEY” keyword with a bracket in which we write the columns' names separated with commas to specify them as a composite primary key.

How do you identify a composite key in a database?

It is a combination of two or more columns. Above, our composite keys are StudentID and StudentEnrollNo. The table has two attributes as primary key. Therefore, the Primary Key consisting of two or more attribute is called Composite Key.

What is composite query in SQL?

Composite Query enables you to combine data from existing queries and then apply filters, aggregates, and so on before presenting the report results, which show the combined data set.


2 Answers

This syntax works for Oracle and PostgreSQL:

SELECT *   FROM table_name  WHERE (key_part_1, key_part_2) IN ( ('B',1), ('C',2) ); 
like image 180
Justin Cave Avatar answered Oct 25 '22 19:10

Justin Cave


Following @Justin Cave's answer, here is a small test case to show that Oracle would do an INDEX RANGE SCAN followed by an INLIST ITERATOR for the following filter predicate:

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> 

A composite index on key1 and key2:

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

Gather stats:

SQL> EXEC DBMS_STATS.gather_table_stats('LALIT', 'T');  PL/SQL procedure successfully completed.  SQL> 

Execute the query:

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

So, it gives the correct output.

Let's see the explain plan:

Case# 1 Key-value pair in the same order of the index. Leading key in the lead.

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. 

Case# 2 Key-value pair in opposite order of the index. Leading key in reverse.

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 either cases, Oracle uses the index.

like image 29
Lalit Kumar B Avatar answered Oct 25 '22 18:10

Lalit Kumar B