Search code examples
sql-serversql-server-2012cross-applysql

When to use the table operator APPLY


I'm trying to understand the table operator APPLY.

Here is the example:

CREATE TABLE #y ( Name char(8), hoursWorked int);
GO
INSERT INTO #y VALUES ('jim',4);
INSERT INTO #y VALUES ('michael',40);
INSERT INTO #y VALUES ('raj',1000);
INSERT INTO #y VALUES ('jason',7);
INSERT INTO #y VALUES ('tim',50);
GO

CREATE TABLE #x ( Name char(8),game char(8), NumBets int);
GO
INSERT INTO #x VALUES ('jim','chess',4);
INSERT INTO #x VALUES ('jim','BG',10);
INSERT INTO #x VALUES ('jim','draughts',100);
INSERT INTO #x VALUES ('jim','football',5);
INSERT INTO #x VALUES ('michael','chess',40);
INSERT INTO #x VALUES ('michael','BG',7);
INSERT INTO #x VALUES ('michael','draughts',65);
INSERT INTO #x VALUES ('michael','football',50);
INSERT INTO #x VALUES ('raj','chess',400);
INSERT INTO #x VALUES ('raj','BG',70);
INSERT INTO #x VALUES ('raj','draughts',650);
INSERT INTO #x VALUES ('tim','draughts',60000);
GO

SELECT  y.Name, 
        y.hoursWorked,
        x.game,
        x.NumBets
FROM    #y y
        OUTER APPLY 
          (
          SELECT TOP 2 *
          FROM   #x
          WHERE  Name = y.Name 
          ORDER BY NumBets
        ) x
ORDER BY  y.Name,
        x.NumBets DESC;

My main hurdle is understanding when to use APPLY.
So I'm wondering how difficult would it be to get the same result as above using standard sql implemented in sql-server 2005 ?
Does APPLY make the query a lot shorter or more readable?
If this example shows no massive advantages to using APPLY then what is a clear example where there is an advantage to using APPLY?


Solution

  • First of all - with apply you could call table-valued functions where parameter values are taken from table you query, something like this:

    select
        t1.col3, -- column from table
        f1.col1  -- column from function
    from table1 as t1
        left outer join table2 as t2 on t2.col1 = t1.col1
        outer apply dbo.function1(t1.col1, t2.col2) as f1
    

    or shredding xml columns

    select
        t1.col3,
        t.c.value('@value', 'int') as value
    from table1 as t1
        -- table1.col1 is xml iike <Data @Value="...">...</Data>
        outer apply t1.col1.nodes('Data') as t(c) 
    

    From my expirience, apply is very useful when you have to make some precalculation:

    select
        t1.col3,
        a1.col1,  --calculated value
        a2.col1   -- another calculated value, first one was used
    from table1 as t1
        outer apply (select t1.col1 * 5 as col1) as a1
        outer apply (select a1.col1 - 4 as col1) as a2
    

    another example of using apply is unpivot operation:

    select
        t1.col1, c.name, c.value
    from table1 as t1
        outer apply (
            select 'col1', t1.col1 union all
            select 'col2', t1.col2
        ) as c(name, value)
    

    finally, here's your query implemented in terms of SQL 2005 without using apply:

    ;with cte as (
        select
            y.Name, 
            y.hoursWorked,
            x.game,
            x.NumBets,
            row_number() over(partition by x.Name order by x.NumBets) as row_num
        from y
            left outer join x on x.Name = y.Name
    )
    select Name, hoursWorked, game, NumBets
    from cte
    where row_num <= 2
    order by Name, NumBets desc
    

    see sql fiddle example