programing

SQL: 처음 찾은 행에서 조인을 제한하는 방법은 무엇입니까?

cafebook 2023. 7. 2. 20:58
반응형

SQL: 처음 찾은 행에서 조인을 제한하는 방법은 무엇입니까?

두 테이블 간에 조인을 하되 조인 조건을 충족하는 첫 번째 행으로 제한하는 방법은 무엇입니까?

이 간단한 예에서는 table_A의 모든 행에 대해 조건을 만족시키는 table_B의 첫 번째 행을 구하고자 합니다.

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

Oracle이 이러한 기능을 제공할 수 있습니다(성능이 문제입니다).

여기서 키워드는 FIRST입니다.분석 기능을 사용할 수 있습니다.FIRST_VALUE또는 골재 구조FIRST.
위해서FIRST또는LAST성능은 결코 나쁘지 않으며 종종 동등한 성능보다 낫습니다.FIRST_VALUE또는LAST_VALUE불필요한 창 정렬이 없기 때문에 실행 비용이 절감됩니다.

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 */
;

12c 이후 도입된 연산자LATERAL,게다가CROSS/OUTER APPLY조인, 오른쪽에 상관된 하위 쿼리를 사용할 수 있도록 합니다.JOIN절:

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 */
;

단일 값만 원하는 경우 스칼라 하위 쿼리를 사용할 수 있습니다.

SELECT
    id, name, (SELECT city FROM table_B WHERE id2 = table_A.id AND ROWNUM = 1) city
FROM
    table_A

쿼리:

SELECT a.id,
       a.name,
       b.city
FROM   table_A a
       INNER JOIN
       ( SELECT id2,
                city
         FROM   (
           SELECT id2,
                  city,
                  ROW_NUMBER() OVER ( PARTITION BY id2 ORDER BY NULL ) rn
           FROM   Table_B
         )
         WHERE rn = 1
       ) b
       ON ( a.id = b.id2 )
--WHERE  ...

출력:

        ID NAME CITY   
---------- ---- --------
         1 John New York 
         2 Marc Boston   
select table_A.id, table_A.name,
FIRST_VALUE(table_B.city) IGNORE NULLS 
         OVER (PARTITION BY table_B.id2 ORDER BY table_B.city) AS "city"
from table_A join table_B 
on table_A.id = table_B.id2
where ..

Oracle 12c에는 드디어 새로운 교차/외부 적용 연산자가 등장하여 사용자가 요청한 사항을 해결 방법 없이 처리할 수 있습니다.

다음은 'SYS'로 시작하는 이름을 가진 사용자가 소유한 (아마도) 많은 개체 중 하나에 대해서만 사전 보기를 보는 예입니다.

select *
from (
        select USERNAME
        from ALL_USERS
        where USERNAME like 'SYS%'
    ) U
    cross apply (
        select OBJECT_NAME
        from ALL_OBJECTS O
        where O.OWNER = U.USERNAME
            and ROWNUM = 1
    )

Oracle 11g 및 이전 버전에서는 동일한 결과를 얻기 위해 일반적으로 두 번째 테이블의 ID를 기반으로 두 번째 테이블을 전체 검색하는 해결 방법만 사용해야 하지만 테스트 용도의 경우 측면 연산자를 활성화하고 다른 연산자를 사용할 수 있습니다.

-- Enables some new features
alter session set events '22829 trace name context forever';

select *
from (
        select USERNAME
        from ALL_USERS
        where USERNAME like 'SYS%'
    ) U,
    lateral (
        select OBJECT_NAME
        from ALL_OBJECTS O
        where O.OWNER = U.USERNAME
            and ROWNUM = 1
    );

이 솔루션은 일반 조인에서와 같이 전체 테이블을 사용하지만 첫 번째 행으로 제한됩니다.저는 다른 솔루션들이 하나의 필드만 사용하거나 큰 테이블에 성능 문제가 있기 때문에 충분하지 않아서 이 글을 올립니다.저는 오라클 전문가가 아니기 때문에 누군가 이를 개선할 수 있다면 기꺼이 당신의 버전을 사용하겠습니다.

select *
from tableA A
cross apply (
    select *
    from (
        select B.*, 
            ROW_NUMBER() OVER (
                -- replace this by your own partition/order statement
                partition by B.ITEM_ID order by B.DELIVERYDATE desc
            ) as ROW_NUM
        from tableB B
        where 
        A.ITEM_ID=B.ITEM_ID
    )
    where ROW_NUM=1
) B

파티션을 사용하여 id2를 분리한 다음 r_num = 1을 가져갑니다.

SELECT A.ID, A.NAME, B.CITY
  FROM TABLE_A A,
      (SELECT ID2, CITY,
              ROW_NUMBER() OVER (PARTITION BY ID2 ORDER BY ID2) AS R_NUM
        FROM TABLE_B) B
  WHERE A.ID = B.ID2
  AND R_NUM = 1;

언급URL : https://stackoverflow.com/questions/35255271/sql-how-to-limit-a-join-on-the-first-found-row

반응형