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);