복붙노트

[SQL] 실생활의 예를 들어, 때 OUTER / CROSS는 SQL에 적용 사용

SQL

실생활의 예를 들어, 때 OUTER / CROSS는 SQL에 적용 사용

나는 동료와 함께 적용 CROSS / OUTER에서 찾고있다 그리고 우리는 그것들을 사용하는 곳의 실제 사례를 찾기 위해 애 쓰고 있습니다.

나는 십자가 내부에 걸쳐 적용 사용해야 가입하는 경우에 시간이 찾고 꽤 많이 보냈어요? 그리고 인터넷 검색을하지만 주 (전용) 예 (다른 테이블에서 선택하는 행 수를 결정하기 위해 테이블에서 행 개수를 사용하여) 꽤 이상한 것 같다.

나는 OUTER 혜택을 누릴 수 있습니다이 시나리오가 적용 생각 :

연락처 표 (각 연락처에 대해 한 기록을 포함) 통신 항목 표 (포함 N 수 있습니다 전화, 팩스, 각 연락처에 이리저리 이메일)

그러나 하위 쿼리를 사용하여, 공통 테이블 표현식은 OUTER는 모두가 동등하게 수행하는 것 적용 RANK ()와 OUTER에 가입하세요. 나는 시나리오가 적용에 적용되지 않습니다 수단을 추측하고있어.

몇 가지 실제 사례를 공유하시기 바랍니다 도움이 기능을 설명!

해결법

  1. ==============================

    1.에 대한 몇 가지 용도는 적용 ...

    에 대한 몇 가지 용도는 적용 ...

    1) 그룹 쿼리 당 최고 N ()는 일부 카디널리티 더 효율적으로 할 수있다

    SELECT pr.name,
           pa.name
    FROM   sys.procedures pr
           OUTER APPLY (SELECT TOP 2 *
                        FROM   sys.parameters pa
                        WHERE  pa.object_id = pr.object_id
                        ORDER  BY pr.name) pa
    ORDER  BY pr.name,
              pa.name 
    

    2) 외부 쿼리의 각 행에 대한 테이블 값 함수 호출

    SELECT *
    FROM sys.dm_exec_query_stats AS qs
    CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle)
    

    3) 열 별칭 재사용

    SELECT number,
           doubled_number,
           doubled_number_plus_one
    FROM master..spt_values
    CROSS APPLY (SELECT 2 * CAST(number AS BIGINT)) CA1(doubled_number)  
    CROSS APPLY (SELECT doubled_number + 1) CA2(doubled_number_plus_one)  
    

    4) 열 이상의기를 Unpivoting

    1NF 테이블 구조를 위반 가정 ....

    CREATE TABLE T
      (
         Id   INT PRIMARY KEY,
    
         Foo1 INT, Foo2 INT, Foo3 INT,
         Bar1 INT, Bar2 INT, Bar3 INT
      ); 
    

    예 2008+ VALUES 구문을 사용.

    SELECT Id,
           Foo,
           Bar
    FROM   T
           CROSS APPLY (VALUES(Foo1, Bar1),
                              (Foo2, Bar2),
                              (Foo3, Bar3)) V(Foo, Bar); 
    

    2005 년 UNION ALL 대신 사용할 수 있습니다.

    SELECT Id,
           Foo,
           Bar
    FROM   T
           CROSS APPLY (SELECT Foo1, Bar1 
                        UNION ALL
                        SELECT Foo2, Bar2 
                        UNION ALL
                        SELECT Foo3, Bar3) V(Foo, Bar);
    
  2. ==============================

    2.당신은 CROSS 적용하거나 외부 적용 피할 수있는 여러 가지 상황이 있습니다.

    당신은 CROSS 적용하거나 외부 적용 피할 수있는 여러 가지 상황이 있습니다.

    당신이 두 개의 테이블을 고려하십시오.

    마스터 테이블

    x------x--------------------x
    | Id   |        Name        |
    x------x--------------------x
    |  1   |          A         |
    |  2   |          B         |
    |  3   |          C         |
    x------x--------------------x
    

    세부 사항 표

    x------x--------------------x-------x
    | Id   |      PERIOD        |   QTY |
    x------x--------------------x-------x
    |  1   |   2014-01-13       |   10  |
    |  1   |   2014-01-11       |   15  |
    |  1   |   2014-01-12       |   20  |
    |  2   |   2014-01-06       |   30  |
    |  2   |   2014-01-08       |   40  |
    x------x--------------------x-------x                                       
    

    우리는 INNER를 교체해야 적용 CROSS에 가입 많은 상황이있다.

    우리는 INNER로 2 개 위에 테이블 n 결과에 가입하려면 1. 기능 가입

    우리는 정보 테이블에서 각 ID에 대한 마스터와 마지막 두 날짜에서 ID와 이름을 선택해야하는 경우 고려하십시오.

    SELECT M.ID,M.NAME,D.PERIOD,D.QTY
    FROM MASTER M
    INNER JOIN
    (
        SELECT TOP 2 ID, PERIOD,QTY 
        FROM DETAILS D      
        ORDER BY CAST(PERIOD AS DATE)DESC
    )D
    ON M.ID=D.ID
    

    위의 쿼리는 다음과 같은 결과를 생성합니다.

    x------x---------x--------------x-------x
    |  Id  |   Name  |   PERIOD     |  QTY  |
    x------x---------x--------------x-------x
    |   1  |   A     | 2014-01-13   |  10   |
    |   1  |   A     | 2014-01-12   |  20   |
    x------x---------x--------------x-------x
    

    그것은 지난 날짜의 ID와 마지막 두 날짜에 대한 결과를 생성 만 잘못된 ID를 외부 쿼리에이 기록에 합류 참조하십시오. 이를 위해, 우리는 CROSS가 적용 사용해야합니다.

    SELECT M.ID,M.NAME,D.PERIOD,D.QTY
    FROM MASTER M
    CROSS APPLY
    (
        SELECT TOP 2 ID, PERIOD,QTY 
        FROM DETAILS D  
        WHERE M.ID=D.ID
        ORDER BY CAST(PERIOD AS DATE)DESC
    )D
    

    그리고 다음과 같은 결과를 형성한다.

    x------x---------x--------------x-------x
    |  Id  |   Name  |   PERIOD     |  QTY  |
    x------x---------x--------------x-------x
    |   1  |   A     | 2014-01-13   |  10   |
    |   1  |   A     | 2014-01-12   |  20   |
    |   2  |   B     | 2014-01-08   |  40   |
    |   2  |   B     | 2014-01-06   |  30   |
    x------x---------x--------------x-------x
    

    여기에 작업입니다. CROSS 내부 쿼리 INNER이 할 수없는 외부 조인 테이블을 참조 할 수 있습니다 적용 (컴파일 오류가 발생합니다). 마지막 두 날짜를 찾을 때, CROSS 내부에서 수행되는 접합은 WHERE M.ID = D.ID, 즉 적용됩니다.

    2. 우리는 INNER이 기능을 사용하여 기능을 가입이 필요합니다.

    우리는 마스터 테이블과 함수의 결과를 얻을 필요가있을 때 INNER와 교체 가입으로 CROSS 사용할 수 있습니다 적용됩니다.

    SELECT M.ID,M.NAME,C.PERIOD,C.QTY
    FROM MASTER M
    CROSS APPLY dbo.FnGetQty(M.ID) C
    

    그리고 여기에 기능입니다

    CREATE FUNCTION FnGetQty 
    (   
        @Id INT 
    )
    RETURNS TABLE 
    AS
    RETURN 
    (
        SELECT ID,PERIOD,QTY 
        FROM DETAILS
        WHERE ID=@Id
    )
    

    이는 다음과 같은 결과를 생성

    x------x---------x--------------x-------x
    |  Id  |   Name  |   PERIOD     |  QTY  |
    x------x---------x--------------x-------x
    |   1  |   A     | 2014-01-13   |  10   |
    |   1  |   A     | 2014-01-11   |  15   |
    |   1  |   A     | 2014-01-12   |  20   |
    |   2  |   B     | 2014-01-06   |  30   |
    |   2  |   B     | 2014-01-08   |  40   |
    x------x---------x--------------x-------x
    

    우리는 왼쪽으로 2 개 TOP에 테이블 n 결과에 가입하려면 1. 기능 가입

    우리는 정보 테이블에서 각 ID에 대한 마스터와 마지막 두 날짜에서 ID와 이름을 선택해야하는 경우 고려하십시오.

    SELECT M.ID,M.NAME,D.PERIOD,D.QTY
    FROM MASTER M
    LEFT JOIN
    (
        SELECT TOP 2 ID, PERIOD,QTY 
        FROM DETAILS D  
        ORDER BY CAST(PERIOD AS DATE)DESC
    )D
    ON M.ID=D.ID
    

    어떤 형태의 다음과 같은 결과

    x------x---------x--------------x-------x
    |  Id  |   Name  |   PERIOD     |  QTY  |
    x------x---------x--------------x-------x
    |   1  |   A     | 2014-01-13   |  10   |
    |   1  |   A     | 2014-01-12   |  20   |
    |   2  |   B     |   NULL       |  NULL |
    |   3  |   C     |   NULL       |  NULL |
    x------x---------x--------------x-------x
    

    이것은 우리가 아이디로 가입하더라도 그것은 상관없이 아이디의 정보 테이블에서만 최신 두 날짜 데이터를 가져올 것이다, 잘못된 결과 즉 가져올 것이다. 그래서 적절한 솔루션은 OUTER APPLY를 사용하고 있습니다.

    SELECT M.ID,M.NAME,D.PERIOD,D.QTY
    FROM MASTER M
    OUTER APPLY
    (
        SELECT TOP 2 ID, PERIOD,QTY 
        FROM DETAILS D  
        WHERE M.ID=D.ID
        ORDER BY CAST(PERIOD AS DATE)DESC
    )D
    

    어떤 형태 다음 원하는 결과

    x------x---------x--------------x-------x
    |  Id  |   Name  |   PERIOD     |  QTY  |
    x------x---------x--------------x-------x
    |   1  |   A     | 2014-01-13   |  10   |
    |   1  |   A     | 2014-01-12   |  20   |
    |   2  |   B     | 2014-01-08   |  40   |
    |   2  |   B     | 2014-01-06   |  30   |
    |   3  |   C     |   NULL       |  NULL |
    x------x---------x--------------x-------x
    

    2. 우리는 LEFT 함수를 사용하여 기능을 가입이 필요합니다.

    우리는 마스터 테이블과 함수의 결과를 얻을 필요가있을 때 LEFT와 교체 가입으로 OUTER 사용할 수 있습니다 적용됩니다.

    SELECT M.ID,M.NAME,C.PERIOD,C.QTY
    FROM MASTER M
    OUTER APPLY dbo.FnGetQty(M.ID) C
    

    그리고 기능이 여기에 표시됩니다.

    CREATE FUNCTION FnGetQty 
    (   
        @Id INT 
    )
    RETURNS TABLE 
    AS
    RETURN 
    (
        SELECT ID,PERIOD,QTY 
        FROM DETAILS
        WHERE ID=@Id
    )
    

    이는 다음과 같은 결과를 생성

    x------x---------x--------------x-------x
    |  Id  |   Name  |   PERIOD     |  QTY  |
    x------x---------x--------------x-------x
    |   1  |   A     | 2014-01-13   |  10   |
    |   1  |   A     | 2014-01-11   |  15   |
    |   1  |   A     | 2014-01-12   |  20   |
    |   2  |   B     | 2014-01-06   |  30   |
    |   2  |   B     | 2014-01-08   |  40   |
    |   3  |   C     |   NULL       |  NULL |
    x------x---------x--------------x-------x
    

    CROSS 적용 또는 OUTER은 교환 할 수있다 unpivoting NULL 값을 유지하는 데 사용할 수 있습니다 적용됩니다.

    당신은 테이블 아래를 고려하십시오

    x------x-------------x--------------x
    |  Id  |   FROMDATE  |   TODATE     |
    x------x-------------x--------------x
    |   1  |  2014-01-11 | 2014-01-13   | 
    |   1  |  2014-02-23 | 2014-02-27   | 
    |   2  |  2014-05-06 | 2014-05-30   |    
    |   3  |   NULL      |   NULL       | 
    x------x-------------x--------------x
    

    당신은 하나 개의 컬럼에 FROMDATE 및 TODATE을 가지고 UNPIVOT을 사용하면 기본적으로 NULL 값을 제거합니다.

    SELECT ID,DATES
    FROM MYTABLE
    UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
    

    이는 아래의 결과를 생성한다. 우리는 ID 번호의 기록을 놓친 것을 주 3

      x------x-------------x
      | Id   |    DATES    |
      x------x-------------x
      |  1   |  2014-01-11 |
      |  1   |  2014-01-13 |
      |  1   |  2014-02-23 |
      |  1   |  2014-02-27 |
      |  2   |  2014-05-06 |
      |  2   |  2014-05-30 |
      x------x-------------x
    

    이러한 경우에서 CROSS 적용 또는 OUTER 유용 할 것입니다 적용

    SELECT DISTINCT ID,DATES
    FROM MYTABLE 
    OUTER APPLY(VALUES (FROMDATE),(TODATE))
    COLUMNNAMES(DATES)
    

    이는 다음과 같은 결과를 형성하고, 그 값이 3이고 이드 유지

      x------x-------------x
      | Id   |    DATES    |
      x------x-------------x
      |  1   |  2014-01-11 |
      |  1   |  2014-01-13 |
      |  1   |  2014-02-23 |
      |  1   |  2014-02-27 |
      |  2   |  2014-05-06 |
      |  2   |  2014-05-30 |
      |  3   |     NULL    |
      x------x-------------x
    
  3. ==============================

    3.당신이 스케줄러를했고, 가장 최근의 로그 항목이 각각의 예약 된 작업에 대한 무엇인지보고 싶었다 경우 하나의 실생활의 예로들 수 있습니다.

    당신이 스케줄러를했고, 가장 최근의 로그 항목이 각각의 예약 된 작업에 대한 무엇인지보고 싶었다 경우 하나의 실생활의 예로들 수 있습니다.

    select t.taskName, lg.logResult, lg.lastUpdateDate
    from task t
    cross apply (select top 1 taskID, logResult, lastUpdateDate
                 from taskLog l
                 where l.taskID = t.taskID
                 order by lastUpdateDate desc) lg
    
  4. ==============================

    4.예를 노크 위의 지점에 대답하려면 :

    예를 노크 위의 지점에 대답하려면 :

    create table #task (taskID int identity primary key not null, taskName varchar(50) not null)
    create table #log (taskID int not null, reportDate datetime not null, result varchar(50) not null, primary key(reportDate, taskId))
    
    insert #task select 'Task 1'
    insert #task select 'Task 2'
    insert #task select 'Task 3'
    insert #task select 'Task 4'
    insert #task select 'Task 5'
    insert #task select 'Task 6'
    
    insert  #log
    select  taskID, 39951 + number, 'Result text...'
    from    #task
            cross join (
                select top 1000 row_number() over (order by a.id) as number from syscolumns a cross join syscolumns b cross join syscolumns c) n
    

    그리고 지금 실행 계획을 가진 두 개의 쿼리를 실행합니다.

    select  t.taskID, t.taskName, lg.reportDate, lg.result
    from    #task t
            left join (select taskID, reportDate, result, rank() over (partition by taskID order by reportDate desc) rnk from #log) lg
                on lg.taskID = t.taskID and lg.rnk = 1
    
    select  t.taskID, t.taskName, lg.reportDate, lg.result
    from    #task t
            outer apply (   select  top 1 l.*
                            from    #log l
                            where   l.taskID = t.taskID
                            order   by reportDate desc) lg
    

    당신은 외부 쿼리가 더 효율적 적용된다는 것을 알 수있다. (나는 ... 도현 새 사용자 해요로 계획을 첨부 할 수 없습니다.)

  5. from https://stackoverflow.com/questions/9275132/real-life-example-when-to-use-outer-cross-apply-in-sql by cc-by-sa and MIT license