Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL: how to limit a join on the first found row?

How to make a join between two tables but limiting to the first row that meets the join condition ?

In this simple example, I would like to get for every row in table_A the first row from table_B that satisfies the condition :

select table_A.id, table_A.name, table_B.city  from table_A join table_B  on table_A.id = table_B.id2 where ..  table_A (id, name) 1, John 2, Marc  table_B (id2, city) 1, New York 1, Toronto 2, Boston  The output would be: 1, John, New York 2, Marc, Boston 

May be Oracle provides such a function (performance is a concern).

like image 873
kkung Avatar asked Feb 07 '16 15:02

kkung


People also ask

How do I select just one row in SQL?

While the table name is selected type CTRL + 3 and you will notice that the query will run and will return a single row as a resultset. Now developer just has to select the table name and click on CTRL + 3 or your preferred shortcut key and you will be able to see a single row from your table.

How do I limit a record in SQL?

If you don't need to omit any rows, you can use SQL Server's TOP clause to limit the rows returned. It is placed immediately after SELECT. The TOP keyword is followed by integer indicating the number of rows to return. In our example, we ordered by price and then limited the returned rows to 3.

How do I select the first row of a group in SQL?

To do that, you can use the ROW_NUMBER() function. In OVER() , you specify the groups into which the rows should be divided ( PARTITION BY ) and the order in which the numbers should be assigned to the rows ( ORDER BY ). You assign the row numbers within each group (i.e., year).

Is there a limit to joins in SQL?

Theoretically, there is no upper limit on the number of tables that can be joined using a SELECT statement. (One join condition always combines two tables!) However, the Database Engine has an implementation restriction: the maximum number of tables that can be joined in a SELECT statement is 64.


2 Answers

The key word here is FIRST. You can use analytic function FIRST_VALUE or aggregate construct FIRST.
For FIRST or LAST the performance is never worse and frequently better than the equivalent FIRST_VALUE or LAST_VALUE construct because we don't have a superfluous window sort and as a consequence a lower execution cost:

select table_A.id, table_A.name, firstFromB.city  from table_A  join (     select table_B.id2, max(table_B.city) keep (dense_rank first order by table_B.city) city     from table_b     group by table_B.id2     ) firstFromB on firstFromB.id2 = table_A.id  where 1=1 /* some conditions here */ ; 

Since 12c introduced operator LATERAL, as well as CROSS/OUTER APPLY joins, make it possible to use a correlated subquery on right side of JOIN clause:

select table_A.id, table_A.name, firstFromB.city  from table_A  cross apply (     select max(table_B.city) keep (dense_rank first order by table_B.city) city     from table_b     where table_B.id2 = table_A.id      ) firstFromB where 1=1 /* some conditions here */ ; 
like image 105
0xdb Avatar answered Sep 21 '22 09:09

0xdb


If you want just single value a scalar subquery can be used:

SELECT     id, name, (SELECT city FROM table_B WHERE id2 = table_A.id AND ROWNUM = 1) city FROM     table_A 
like image 33
Husqvik Avatar answered Sep 22 '22 09:09

Husqvik