LinqToSQLが作成するSQLコードを調べると、APPLYという興味深いSQLステートメントに出会いました。
MSDNが言うように、このコマンドは次のことを行います。
http://technet.microsoft.com/en-us/library/ms175156.aspx
APPLYステートメントを使用すると、外部のテーブルクエリ式によって返される各行に対してテーブルを返す関数を呼び出すことができます。 テーブル値を返す関数は右入力として機能し、外部テーブル式は左入力として機能します。 右側の入力は左側の入力から各行に対して評価され、生成された行は最終的な出力のために結合されます。 APPLYステートメントによって作成される列のリストは、左側の入力の列のセットと、それに続く右側の入力によって返される列のリストです。
判明したように、APPLYは問題の解決に非常に適しています。
例を見てみましょう:
タスク:各顧客の最新の10件の注文を選択します。
次の単純なデータベース構造を考えてみましょう。
CREATE TABLE Customer ( CustomerID INT PRIMARY KEY, CustomerName NVARCHAR(30) NOT NULL ) CREATE TABLE Nomenclature ( NomenclatureID INT PRIMARY KEY, NomenclatureName NVARCHAR(30) NOT NULL, Price MONEY NOT NULL ) CREATE TABLE Deal ( DealID INT IDENTITY(1, 1) PRIMARY KEY, CustomerID INT NOT NULL, NomenclatureID INT NOT NULL, [Count] DECIMAL(8,2) NOT NULL, DealDate DATETIME NOT NULL )
次に、各顧客の最新の10件の注文を選択する必要があります。 以前は、次のアプローチを使用していました。最初に、各顧客について、10件の注文がある日付から選択し、この日付からすべての注文を選択しました。
SELECT d.DealDate, c.CustomerName, n.NomenclatureName, n.Price, d.Count FROM Customer c JOIN Deal d ON d.CustomerID = c.CustomerID JOIN (SELECT c.CustomerID, (SELECT MIN(lastDeals.DealDate) FROM (SELECT TOP 10 d1.DealDate FROM Deal d1 WHERE d1.CustomerID = c.CustomerID ORDER BY d1.DealDate DESC) LastDeals) LastDealDate FROM Customer c) ld ON ld.CustomerID = c.CustomerID JOIN Nomenclature n ON n.NomenclatureID = d.NomenclatureID WHERE d.DealDate >= ld.LastDealDate ORDER BY c.CustomerName, d.DealDate DESC
*簡単にするために、同時に2つの注文はできないと明確に仮定しました。
APPLY SQLを使用すると、コードが読みやすくなりました。
SELECT d.DealDate, c.CustomerName, n.NomenclatureName, n.Price, d.Count FROM Customer c OUTER APPLY (SELECT TOP 10 d1.* FROM Deal d1 Where d1.CustomerID = c.CustomerID ORDER BY d1.DealDate DESC) d INNER JOIN Nomenclature n ON n.NomenclatureID = d.NomenclatureID ORDER BY c.CustomerName, d.DealDate DESC
必要なすべてのインデックスを使用したリクエストの計画と実行時間も、この機能が複数回役立つことへの自信を促します。
インデックス作成データベースファイル : CreateDB.txt
SQLクエリファイル: Queries.txt