APPLYの活用方法 APPLYはSQL Serverにおける強力な機能の一つで、サブクエリやテーブル値関数の結果を各行に対して動的に結び付けるために使用できる。この記事では、APPLYの使い方と、具体的なユースケースまでを解説します。 APPLYには2種類ありOUTER APPLYとCROSS APPLYがある。それぞれOUTER APPLYはLEFT JOINのように動作しOUTER APPLYはINNER JOINのように動作する。OUTER APPLYとは?OUTER APPLYは、LEFT JOINのように動作し、外部クエリの各行に対してサブクエリやテーブル値関数の結果を結び付けます。OUTER APPLYは、外部クエリの行がサブクエリと結びつかない場合でも、その行を結果セットに含めます。CROSS APPLYとは?CROSS APPLYは、INNER JOINのように動作し、外部クエリの各行に対してサブクエリやテーブル値関数の結果を 結び付けます。CROSS APPLYは、外部クエリの行がサブクエリと結びつかない場合、その行は結果セットに含まれません。CROSS APPLYは、サブクエリが結果を返す場合にのみ行を結びつけ、結果セットに追加します。Employeesテーブルと、売上情報を持つSalesテーブルを用意します。EmployeesIDが売上表から削除されていないことです。| EmployeeID | FirstName | LastName | DepartmentID | HireDate |
|---|---|---|---|---|
| 1 | John | Doe | 1 | 2020-01-15 |
| 2 | Jane | Smith | 1 | 2021-06-01 |
| 3 | Mike | Brown | 2 | 2019-08-23 |
| 4 | Linda | Johnson | 3 | 2020-11-11 |
| 5 | Emily | Davis | 4 | 2018-03-19 |
| 6 | Michael | Taylor | 2 | 2022-05-14 |
| 7 | Sarah | Wilson | 3 | 2021-09-07 |
| 8 | David | Anderson | 1 | 2020-12-25 |
| SaleID | EmployeeID | SaleDate | Amount |
|---|---|---|---|
| 1 | 1 | 2023-01-10 | 1500.00 |
| 2 | 1 | 2023-03-15 | 2000.00 |
| 3 | 2 | 2023-02-05 | 1800.00 |
| 4 | 2 | 2023-06-18 | 2200.00 |
| 5 | 8 | 2023-05-20 | 1700.00 |
| 6 | 8 | 2023-07-22 | 2000.00 |
| 7 | 9 | 2023-07-22 | 1900.00 |
| 8 | 10 | 2022-06-20 | 2200.00 |
| 9 | 11 | 2021-05-19 | 2300.00 |
| 10 | 12 | 2020-04-01 | 4000.00 |
| 11 | 13 | 2019-03-02 | 3900.00 |
| 12 | 14 | 2018-02-17 | 6000.00 |
| 13 | 15 | 2018-01-18 | 9000.00 |
| 14 | 16 | 2018-12-19 | 1000.00 |
SELECT
e.EmployeeID,
e.FirstName,
e.LastName,
s.LatestSaleDate,
s.LatestAmount,
s.SaleRank
FROM
Employees e
INNER JOIN (
SELECT
*
FROM(
SELECT
EmployeeID,
SaleDate AS LatestSaleDate,
Amount AS LatestAmount,
RANK() OVER (PARTITION BY EmployeeID ORDER BY SaleDate DESC) AS SaleRank
FROM
Sales
) s
WHERE SaleRank = 1
) s ON e.EmployeeID = s.EmployeeID;| EmployeeID | FirstName | LastName | LatestSaleDate | LatestAmount | SaleRank |
|---|---|---|---|---|---|
| 1 | John | Doe | 2023-03-15 | 2000.00 | 1 |
| 2 | Jane | Smith | 2023-06-18 | 2200.00 | 1 |
| 8 | David | Anderson | 2023-07-22 | 2000.00 | 1 |

SELECT
e.EmployeeID,
e.FirstName,
e.LastName,
--d.DepartmentName,
samary.LatestSaleDate,
samary.LatestAmount,
samary.SaleRank
FROM
Employees e
CROSS APPLY (
SELECT * FROM (
SELECT
SaleDate AS LatestSaleDate,
Amount AS LatestAmount,
RANK() OVER (PARTITION BY s.EmployeeID ORDER BY s.SaleDate DESC) AS SaleRank
FROM
Sales s
WHERE
s.EmployeeID = e.EmployeeID
) s
WHERE s.SaleRank = 1
) samary
;| EmployeeID | FirstName | LastName | LatestSaleDate | LatestAmount | SaleRank |
|---|---|---|---|---|---|
| 1 | John | Doe | 2023-03-15 | 2000.00 | 1 |
| 2 | Jane | Smith | 2023-06-18 | 2200.00 | 1 |
| 8 | David | Anderson | 2023-07-22 | 2000.00 | 1 |

LATERALを使用する。
若干クエリ内容は違いますが下記に手を加えていけば同じ結果が得られます。SELECT e.EmployeeID, e.FirstName, e.LastName, s.LatestSaleDate, s.LatestAmount
FROM Employees e
LEFT JOIN LATERAL (
SELECT SaleDate AS LatestSaleDate, Amount AS LatestAmount
FROM Sales s
WHERE s.EmployeeID = e.EmployeeID
ORDER BY SaleDate DESC
LIMIT 1
) s ON true;SELECT e.EmployeeID, e.FirstName, e.LastName, s.LatestSaleDate, s.LatestAmount
FROM Employees e
LEFT JOIN (
SELECT EmployeeID, SaleDate AS LatestSaleDate, Amount AS LatestAmount
FROM (
SELECT s.EmployeeID, s.SaleDate, s.Amount,
ROW_NUMBER() OVER (PARTITION BY s.EmployeeID ORDER BY s.SaleDate DESC) as rn
FROM Sales s
)
WHERE rn = 1
) s ON e.EmployeeID = s.EmployeeID;-- 社員テーブルの作成
CREATE TABLE Employees (
EmployeeID INT PRIMARY KEY,
FirstName VARCHAR(50),
LastName VARCHAR(50),
DepartmentID INT,
HireDate DATE
);
-- 売上テーブルの作成
CREATE TABLE Sales (
SaleID INT PRIMARY KEY,
EmployeeID INT,
SaleDate DATE,
Amount DECIMAL(10, 2)
);
-- サンプルデータの投入
-- 社員データの挿入
INSERT INTO Employees (EmployeeID, FirstName, LastName, DepartmentID, HireDate) VALUES
(1, 'John', 'Doe', 1, '2020-01-15'),
(2, 'Jane', 'Smith', 1, '2021-06-01'),
(3, 'Mike', 'Brown', 2, '2019-08-23'),
(4, 'Linda', 'Johnson', 3, '2020-11-11'),
(5, 'Emily', 'Davis', 4, '2018-03-19'),
(6, 'Michael', 'Taylor', 2, '2022-05-14'),
(7, 'Sarah', 'Wilson', 3, '2021-09-07'),
(8, 'David', 'Anderson', 1, '2020-12-25');
-- 売上データの挿入
INSERT INTO Sales (SaleID, EmployeeID, SaleDate, Amount) VALUES
(1, 1, '2023-01-10', 1500.00),
(2, 1, '2023-03-15', 2000.00),
(3, 2, '2023-02-05', 1800.00),
(4, 2, '2023-06-18', 2200.00),
(5, 8, '2023-05-20', 1700.00),
(6, 8, '2023-07-22', 2000.00),
(7, 9, '2023-07-22', 1900.00),
(8, 10, '2022-06-20', 2200.00),
(9, 11, '2021-05-19', 2300.00),
(10,12, '2020-04-01', 4000.00),
(11,13, '2019-03-02', 3900.00),
(12,14, '2018-02-17', 6000.00),
(13,15, '2018-01-18', 9000.00),
(14,16, '2018-12-19', 1000.00);