Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Къде да използвате Outer Apply

LEFT JOIN трябва да се замени с OUTER APPLY в следните ситуации.

1. Ако искаме да обединим две маси въз основа на TOP n резултатите

Помислете дали трябва да изберем Id и Name от Master и последните две дати за всеки Id от Details таблица.

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

Това ще доведе до грешни резултати, т.е. ще изведе само данни за последните две дати от Details таблица независимо от Id въпреки че се присъединяваме с Id . Така че правилното решение е използването на 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

Ето как работи:В LEFT JOIN , TOP 2 датите ще бъдат присъединени към MASTER само след изпълнение на заявката вътре в извлечената таблица D . В OUTER APPLY , той използва присъединяване WHERE M.ID=D.ID вътре в OUTER APPLY , така че всеки ID в Master ще бъдат обединени с TOP 2 дати, които ще доведат до следния резултат.

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 JOIN функционалност с помощта на functions .

OUTER APPLY може да се използва като заместител с LEFT JOIN когато трябва да получим резултат от Master таблица и function .

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 [email protected]
)

което генерира следния резултат

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

3. Запазете 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

Когато използвате UNPIVOT да донесе FROMDATE И TODATE към една колона, това ще елиминира 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

В такива случаи APPLY може да се използва (или CROSS APPLY или OUTER APPLY , който е взаимозаменяем).

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

което формира следния резултат и запазва 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 |
  |  3   |     NULL    |
  x------x-------------x


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Разлика между sys.objects, sys.system_objects и sys.all_objects в SQL Server

  2. Внедряване на индикатор за производителност на SQL Server за заявки, съхранени процедури и тригери

  3. Преобразуването не бе успешно при преобразуване на стойността на varchar 'simple' в тип данни int

  4. Сума на подзаявки на SQL Server

  5. Как да добавите ограничение за първичен ключ към колони за идентичност към всички таблици в базата данни на SQL Server - SQL Server / TSQL Урок, част 63