暗黙結合 (矢印構文)
InterSystems SQL には、関連するテーブルから値を取得するための省略手段として、特殊な –> 演算子があります。これにより、特定のケースで、明示的に JOIN を指定するという複雑な作業を省くことができます。この矢印構文を明示的な結合構文の代わりに使用したり、明示的な結合構文と組み合わせて使用したりできます。矢印構文は左外部結合を実行します。
矢印構文は、クラスのプロパティまたは親テーブルのリレーションシップ・プロパティの参照に使用できます。その他のタイプのリレーションシップおよび外部キーでは矢印構文はサポートされません。ON 節では矢印構文 (–>) を使用できません。
シャード・テーブルが関与するクエリでは、矢印構文を使用できます。
詳細は、"InterSystems SQL リファレンス" の "JOIN" のページを参照してください。
プロパティの参照
“参照されたテーブル” から値を取得するための省略手段として、–> 演算子を使用できます。
例えば、Company と Employee という 2 つのクラスを定義するとします。
Class Sample.Company Extends %Persistent [DdlAllowed]
{
/// The Company name
Property Name As %String;
}
また、Employee は以下のように定義します。
Class Sample.Employee Extends %Persistent [DdlAllowed]
{
/// The Employee name
Property Name As %String;
/// The Company this Employee works for
Property Company As Company;
}
Employee クラスは、Company オブジェクトへの参照のプロパティを含みます。オブジェクト・ベースのアプリケーションでは、ドット構文を使用してこの参照を表すことができます。例えば、会社員 (employee) が所属する会社 (company) を見つけるには、以下を使用します。
Set name = employee.Company.Name
SQL 文で同じ作業を実行するには、OUTER JOIN により Employee と Company のテーブルを結合します。
SELECT Sample.Employee.Name, Sample.Company.Name AS CompName
FROM Sample.Employee LEFT OUTER JOIN Sample.Company
ON Sample.Employee.Company = Sample.Company.ID
–> 演算子を使用すると、同様の OUTER JOIN 操作をより簡潔に実行できます。
SELECT Name, Company->Name AS CompName
FROM Sample.Employee
テーブルに参照列がある場合はいつでも –> 演算子を使用できます。この列の値は、参照されたテーブルの ID です (本来は、外部キーの特殊なケースです)。この場合は、Sample.Employee の Company フィールドには、Sample.Company テーブル内のレコードの ID が含まれています。クエリで列の式を使用できる場所であれば、どこでも –> 演算子を使用できます。例えば、以下の WHERE 節を考えます。
SELECT Name,Company AS CompID,Company->Name AS CompName
FROM Sample.Employee
WHERE Company->Name %STARTSWITH 'G'
これは以下と同じです。
SELECT E.Name,E.Company AS CompID,C.Name AS CompName
FROM Sample.Employee AS E, Sample.Company AS C
WHERE E.Company = C.ID AND C.Name %STARTSWITH 'G'
この場合、対応するクエリは INNER JOIN を使用しています。
以下の例では、矢印構文を使用して Sample.Person 内の Spouse フィールドにアクセスします。この例で示されるように、Sample.Employee 内の Spouse フィールドには、Sample.Person 内のレコードの ID が含まれています。この例では、従業員の Home_State または Office_State とその従業員の配偶者の Home_State が同じであるレコードを返します。
SELECT Name,Spouse,Home_State,Office_State,Spouse->Home_State AS SpouseState
FROM Sample.Employee
WHERE Home_State=Spouse->Home_State OR Office_State=Spouse->Home_State
GROUP BY 節で –> 演算子を使用できます。
SELECT Name,Company->Name AS CompName
FROM Sample.Employee
GROUP BY Company->Name
ORDER BY 節で –> 演算子を使用できます。
SELECT Name,Company->Name AS CompName
FROM Sample.Employee
ORDER BY Company->Name
または、ORDER BY 節で –> 演算子列の列エイリアスを参照します。
SELECT Name,Company->Name AS CompName
FROM Sample.Employee
ORDER BY CompName
以下の例で示すように、複合矢印構文がサポートされています。この例では、Cinema.Review テーブルには Film フィールドが含まれており、それには Cinema.Film テーブルの行 ID が含まれています。Cinema.Film テーブルには Category フィールドが含まれており、それには Cinema.Category テーブルの行 ID が含まれています。したがって、ReviewScore がある各フィルムの CategoryName を返すには、Film->Category->CategoryName によってこれら 3 つのテーブルにアクセスします。
SELECT ReviewScore,Film,Film->Title,Film->Category,Film->Category->CategoryName
FROM Cinema.Review
ORDER BY ReviewScore
子テーブルの参照
–> 演算子を使用して、子テーブルを参照できます。例えば、LineItems が Orders テーブルの子テーブルであるとき、以下を指定できます。
SELECT LineItems->amount
FROM Orders
Orders には、LineItems というプロパティはありません。LineItems は、amount フィールドが含まれる子テーブルの名前です。このクエリによって、各 Order 列の結果セットに複数の行が生成されます。これは、以下と同等です。
SELECT L.amount
FROM Orders O LEFT JOIN LineItems L ON O.id=L.custorder
ここで、custorder は、LineItems テーブルの親参照フィールドです。
矢印構文の特権
矢印構文を使用する場合、両方のテーブルの参照対象データに対する SELECT 特権が必要です。テーブルレベルの SELECT 特権、または参照対象列に対する列レベルの SELECT 特権が必要です。列レベルの特権では、参照対象テーブルの ID および参照対象列に対する SELECT 特権が必要です。
以下の例は、必要な列レベルの特権を示しています。
SELECT Name,Company->Name AS CompanyName
FROM Sample.Employee
GROUP BY Company->Name
ORDER BY Company->Name
上記の例では、Sample.Employee.Name、Sample.Company.Name、および Sample.Company.ID に対して列レベルの SELECT 特権が必要です。
SET tStatement = ##class(%SQL.Statement).%New()
SET privchk1="%CHECKPRIV SELECT (Name,ID) ON Sample.Company"
SET privchk2="%CHECKPRIV SELECT (Name) ON Sample.Employee"
CompanyPrivTest
SET qStatus = tStatement.%Prepare(privchk1)
IF qStatus'=1 {WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT}
SET rset = tStatement.%Execute()
IF rset.%SQLCODE=0 {WRITE !,"have Company privileges",! }
ELSE { WRITE !,"No privilege: SQLCODE=",rset.%SQLCODE,! }
EmployeePrivTest
SET qStatus = tStatement.%Prepare(privchk2)
IF qStatus'=1 {WRITE "%Prepare failed:" DO $System.Status.DisplayError(qStatus) QUIT}
SET rset = tStatement.%Execute()
IF rset.%SQLCODE=0 {WRITE !,"have Employee privilege",! }
ELSE { WRITE !,"No privilege: SQLCODE=",rset.%SQLCODE }