䟋ずしおMS SQL Server方蚀を䜿甚したSQL蚀語チュヌトリアルDDL、DML。 パヌト4

前のパヌツ







この郚分では、考慮したす



マルチテヌブルク゚リ



サブク゚リを䜿甚する





いく぀かの新しいデヌタを远加したす。



デモンストレヌションのために、いく぀かの郚門ず投皿を远加したす。



SET IDENTITY_INSERT Departments ON INSERT Departments(ID,Name) VALUES(4,N'  ') INSERT Departments(ID,Name) VALUES(5,N'') SET IDENTITY_INSERT Departments OFF
      
      







 SET IDENTITY_INSERT Positions ON INSERT Positions(ID,Name) VALUES(5,N'') INSERT Positions(ID,Name) VALUES(6,N'') INSERT Positions(ID,Name) VALUES(7,N'') SET IDENTITY_INSERT Positions OFF
      
      







JOIN接続-氎平デヌタ接続操䜜



ここでは、デヌタベヌス構造の知識、すなわち その䞭にあるテヌブル、これらのテヌブルに保存されおいるデヌタ、およびテヌブルのどのフィヌルドが関連しおいるか。 たず、デヌタベヌスの構造を垞に培底的に研究したす。 通垞のク゚リは、どこから来たのかがわかっおいる堎合にのみ蚘述できたす。 私たちの構造は、埓業員、郚眲、圹職の3぀のテヌブルで構成されおいたす。 これが最初の郚分の図です







RDBの本質が分割しお埁服するこずである堎合、ア゜シ゚ヌションの操䜜の本質は、テヌブルで分割されたデヌタを再び接着するこずです。 それらを人間の圢に戻したす。



簡単に蚀えば、テヌブルを他のテヌブルず氎平方向に結合する操䜜は、そこから欠萜しおいるデヌタを取埗するために䜿甚されたす。 埓業員衚からの芁求に応じお、最終結果を取埗するためにDepartments衚にDepartment Nameフィヌルドがなかった堎合の、ディレクタヌの週次レポヌトの䟋を思い出しおください。



理論から始めたしょう。 接続には5぀のタむプがありたす。

  1. JOIN -left_table JOIN right_table ON join_condition
  2. LEFT JOIN -left_table LEFT JOIN right_table ON join_conditions
  3. RIGHT JOIN -left_table RIGHT JOIN right_table ON join_conditions
  4. FULL JOIN -left_table FULL JOIN right_table ON join_condition
  5. CROSS JOIN -left_table CROSS JOIN right_table


短い構文 完党な構文 説明これは誰もがすぐに明確になるずは限りたせん。したがっお、明確でない堎合は、䟋を確認しおからここに戻っおください。
参加する むンナヌゞョむン left_tableおよびright_tableの行から、結合条件を返す行のみが結合されたす。
巊から参加 巊倖郚結合 left_tableのすべおの行が返されたすキヌワヌドLEFT。 右テヌブルのデヌタは、join_条件が満たされおいる巊テヌブルの行によっおのみ補完されたす。 欠萜デヌタの堎合、right_table行の代わりにNULL倀が挿入されたす。
正しい参加 右アりタヌゞョむン right_tableのすべおの行が返されたすキヌワヌドRIGHT。 join_条件が満たされおいる巊偎のテヌブル行のみが巊偎のテヌブルデヌタで補完されたす。 欠萜デヌタの堎合、left_table行の代わりにNULL倀が挿入されたす。
完党参加 フルアりタヌゞョむン left_tableおよびright_tableのすべおの行が返されたす。 left_tableおよびright_tableの行に぀いおjoin_条件が満たされる堎合、それらは1぀の行に結合されたす。 join_条件が満たされない行の堎合、行内のどのテヌブルのデヌタが利甚できないかに応じお、left_tableの堎所たたはright_tableの堎所にNULL倀が挿入されたす。
クロスゞョむン - left_tableの各行を、right_tableのすべおの行ず組み合わせたす。 このタむプの化合物は、デカルト積ず呌ばれるこずもありたす。


衚からわかるように、短い構文の完党な構文は、INNERたたはOUTERずいう単語の存圚のみが異なりたす。



個人的には、ク゚リを䜜成するずきは垞に次の理由で短い構文のみを䜿甚したす。

  1. これは短く、䞍芁な単語でク゚リを詰たらせたせん。
  2. LEFT、RIGHT、FULLおよびCROSSによるず、JOINの堎合、どのような接続に぀いお話しおいるのかが明確です。
  3. この堎合のINNERずOUTERずいう蚀葉は、初心者をより混乱させる䞍必芁な初歩的なものだず思いたす。


しかし、もちろん、これは私の個人的な奜みであり、おそらく誰かが長い間曞くのが奜きで、圌はこれに圌の魅力を芋おいたす。



各タむプの接続を理解するこずは非垞に重芁です。なぜなら、 特定のタむプのアプリケヌションでは、ク゚リ結果が異なる堎合がありたす。 別の皮類の接続を䜿甚しお同じク゚リの結果を比范し、今のずころ違いを確認しお先に進みたすここに戻りたす。



 -- JOIN  5  SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp JOIN Departments dep ON emp.DepartmentID=dep.ID
      
      





ID お名前 DepartmentID ID お名前
1000 むワノフI.I. 1 1 運営
1001 ペトロフP.P. 3 3 IT
1002 シドロフS.S. 2 2 簿蚘
1003 アンドレ゚フA.A. 3 3 IT
1004 ニコラ゚フN.N. 3 3 IT


 -- LEFT JOIN  6  SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp LEFT JOIN Departments dep ON emp.DepartmentID=dep.ID
      
      





ID お名前 DepartmentID ID お名前
1000 むワノフI.I. 1 1 運営
1001 ペトロフP.P. 3 3 IT
1002 シドロフS.S. 2 2 簿蚘
1003 アンドレ゚フA.A. 3 3 IT
1004 ニコラ゚フN.N. 3 3 IT
1005 アレクサンドロフA.A. ヌル ヌル ヌル


 -- RIGHT JOIN  7  SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp RIGHT JOIN Departments dep ON emp.DepartmentID=dep.ID
      
      





ID お名前 DepartmentID ID お名前
1000 むワノフI.I. 1 1 運営
1002 シドロフS.S. 2 2 簿蚘
1001 ペトロフP.P. 3 3 IT
1003 アンドレ゚フA.A. 3 3 IT
1004 ニコラ゚フN.N. 3 3 IT
ヌル ヌル ヌル 4 マヌケティングず広告
ヌル ヌル ヌル 5 物流


 -- FULL JOIN  8  SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp FULL JOIN Departments dep ON emp.DepartmentID=dep.ID
      
      





ID お名前 DepartmentID ID お名前
1000 むワノフI.I. 1 1 運営
1001 ペトロフP.P. 3 3 IT
1002 シドロフS.S. 2 2 簿蚘
1003 アンドレ゚フA.A. 3 3 IT
1004 ニコラ゚フN.N. 3 3 IT
1005 アレクサンドロフA.A. ヌル ヌル ヌル
ヌル ヌル ヌル 4 マヌケティングず広告
ヌル ヌル ヌル 5 物流


 -- CROSS JOIN  30  - (6   Employees) * (5   Departments) SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp CROSS JOIN Departments dep
      
      





ID お名前 DepartmentID ID お名前
1000 むワノフI.I. 1 1 運営
1001 ペトロフP.P. 3 1 運営
1002 シドロフS.S. 2 1 運営
1003 アンドレ゚フA.A. 3 1 運営
1004 ニコラ゚フN.N. 3 1 運営
1005 アレクサンドロフA.A. ヌル 1 運営
1000 むワノフI.I. 1 2 簿蚘
1001 ペトロフP.P. 3 2 簿蚘
1002 シドロフS.S. 2 2 簿蚘
1003 アンドレ゚フA.A. 3 2 簿蚘
1004 ニコラ゚フN.N. 3 2 簿蚘
1005 アレクサンドロフA.A. ヌル 2 簿蚘
1000 むワノフI.I. 1 3 IT
1001 ペトロフP.P. 3 3 IT
1002 シドロフS.S. 2 3 IT
1003 アンドレ゚フA.A. 3 3 IT
1004 ニコラ゚フN.N. 3 3 IT
1005 アレクサンドロフA.A. ヌル 3 IT
1000 むワノフI.I. 1 4 マヌケティングず広告
1001 ペトロフP.P. 3 4 マヌケティングず広告
1002 シドロフS.S. 2 4 マヌケティングず広告
1003 アンドレ゚フA.A. 3 4 マヌケティングず広告
1004 ニコラ゚フN.N. 3 4 マヌケティングず広告
1005 アレクサンドロフA.A. ヌル 4 マヌケティングず広告
1000 むワノフI.I. 1 5 物流
1001 ペトロフP.P. 3 5 物流
1002 シドロフS.S. 2 5 物流
1003 アンドレ゚フA.A. 3 5 物流
1004 ニコラ゚フN.N. 3 5 物流
1005 アレクサンドロフA.A. ヌル 5 物流




テヌブルの゚むリアスを芚えるずきです



2番目のパヌトの冒頭で説明したテヌブルの゚むリアスに぀いお思い出しおください。



マルチテヌブルク゚リでは、゚むリアスはフィヌルドの取埗元のテヌブルを明瀺的に瀺すのに圹立ちたす。 䟋を芋おみたしょう



 SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp JOIN Departments dep ON emp.DepartmentID=dep.ID
      
      







埓業員ず郚門の䞡方のテヌブルに、IDずNameずいう名前のフィヌルドが含たれおいたす。 そしおそれらを区別するために、フィヌルド名の前に゚むリアスずドットを付けたす。 「Emp.ID」、「emp.Name」、「dep.ID」、「dep.Name」。



゚むリアスがなければ、リク゚ストは次のようになるため、短い゚むリアスを䜿甚する方が䟿利な理由を思い出しおください。



 SELECT Employees.ID,Employees.Name,Employees.DepartmentID,Departments.ID,Departments.Name FROM Employees JOIN Departments ON Employees.DepartmentID=Departments.ID
      
      







私にずっおは、読むのが非垞に長く、悪くなっおいたす。 フィヌルド名は、重耇するテヌブル名の間で芖芚的に倱われたす。



マルチテヌブルク゚リでは、゚むリアスなしで名前を指定できたすが、2番目のテヌブルで名前が重耇しおいない堎合は、接続の堎合は垞に゚むリアスを䜿甚するこずをお勧めしたす。 同じ名前のフィヌルドが時間の経過ずずもに2番目のテヌブルに远加されないこずを誰も保蚌せず、ク゚リは単玔に壊れ、このフィヌルドがどのテヌブルを参照しおいるのか理解できないず誓いたす。



゚むリアスのみを䜿甚するず、テヌブルをそれ自䜓に結合できたす。 タスクは、各埓業員の盎前に受け入れられた埓業員のデヌタを取埗するこずであったず想定したす埓業員番号は1枛りたす。 埓業員番号が順番に発行され、穎が空いおいない堎合、およそ次のようにこれを実行できたす。



 SELECT e1.ID EmpID1, e1.Name EmpName1, e2.ID EmpID2, e2.Name EmpName2 FROM Employees e1 LEFT JOIN Employees e2 ON e1.ID=e2.ID+1 --    
      
      







぀たり ここにEmployeesの1぀のテヌブルがあり、゚むリアス「e1」ず2番目の「e2」を指定したした。



各タむプの氎平接続を分解したす



この目的のために、LeftTableおよびRightTableず呌ばれる2぀の小さな抜象テヌブルを怜蚎したす。



 CREATE TABLE LeftTable( LCode int, LDescr varchar(10) ) GO CREATE TABLE RightTable( RCode int, RDescr varchar(10) ) GO INSERT LeftTable(LCode,LDescr)VALUES (1,'L-1'), (2,'L-2'), (3,'L-3'), (5,'L-5') INSERT RightTable(RCode,RDescr)VALUES (2,'B-2'), (3,'B-3'), (4,'B-4')
      
      







これらの衚の内容を芋おみたしょう。



 SELECT * FROM LeftTable
      
      





LCode LDescr
1 L-1
2 L-2
3 L-3
5 L-5


 SELECT * FROM RightTable
      
      





RCode RDescr
2 B-2
3 B-3
4 B-4




参加する



 SELECT l.*,r.* FROM LeftTable l JOIN RightTable r ON l.LCode=r.RCode
      
      





LCode LDescr RCode RDescr
2 L-2 2 B-2
3 L-3 3 B-3


ここでは、条件が満たされた文字列結合が返されたしたl.LCode = r.RCode







巊から参加



 SELECT l.*,r.* FROM LeftTable l LEFT JOIN RightTable r ON l.LCode=r.RCode
      
      





LCode LDescr RCode RDescr
1 L-1 ヌル ヌル
2 L-2 2 B-2
3 L-3 3 B-3
5 L-5 ヌル ヌル


ここでは、LeftTableのすべおの行が返され、条件が満たされたRightTableからの行デヌタによっお補完されたしたl.LCode = r.RCode







正しい参加



 SELECT l.*,r.* FROM LeftTable l RIGHT JOIN RightTable r ON l.LCode=r.RCode
      
      





LCode LDescr RCode RDescr
2 L-2 2 B-2
3 L-3 3 B-3
ヌル ヌル 4 B-4


ここでは、条件が満たされたLeftTableの行デヌタで補完されたすべおのRightTable行が返されたしたl.LCode = r.RCode







実際、LeftTableずRightTableを適切に再配眮するず、巊結合を䜿甚しお同様の結果が埗られたす。



 SELECT l.*,r.* FROM RightTable r LEFT JOIN LeftTable l ON l.LCode=r.RCode
      
      





LCode LDescr RCode RDescr
2 L-2 2 B-2
3 L-3 3 B-3
ヌル ヌル 4 B-4


LEFT JOIN、぀たり 最初に、どのテヌブルデヌタが私にずっお重芁であるかを考え、次にどのテヌブルが補完テヌブルの圹割を果たすかを考えたす。



FULL JOINは、本質的にLEFT JOINずRIGHT JOINの同時参加です。



 SELECT l.*,r.* FROM LeftTable l FULL JOIN RightTable r ON l.LCode=r.RCode
      
      





LCode LDescr RCode RDescr
1 L-1 ヌル ヌル
2 L-2 2 B-2
3 L-3 3 B-3
5 L-5 ヌル ヌル
ヌル ヌル 4 B-4


LeftTableずRightTableのすべおの行が返されたす。 条件が満たされる行l.LCode = r.RCodeは、1行に結合されたした。 巊偎たたは右偎の欠萜デヌタにはNULL倀が入力されたす。







クロスゞョむン



 SELECT l.*,r.* FROM LeftTable l CROSS JOIN RightTable r
      
      





LCode LDescr RCode RDescr
1 L-1 2 B-2
2 L-2 2 B-2
3 L-3 2 B-2
5 L-5 2 B-2
1 L-1 3 B-3
2 L-2 3 B-3
3 L-3 3 B-3
5 L-5 3 B-3
1 L-1 4 B-4
2 L-2 4 B-4
3 L-3 4 B-4
5 L-5 4 B-4


LeftTableの各行は、RightTableのすべおの行のデヌタに接続されおいたす。







EmployeesおよびDepartmentsテヌブルに戻りたす



氎平方向のゞョむントがどのように機胜するかを理解しおください。 この堎合は、「JOIN接続-氎平方向のデヌタ接続操䜜」セクションの最初に戻っお、EmployeesテヌブルずDepartmentsテヌブルを自分で結合した䟋を理解しおから、ここに戻っお議論しおください。



各リク゚ストの抂芁を芁玄しおみたしょう。

リク゚スト たずめ
 -- JOIN  5  SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp JOIN Departments dep ON emp.DepartmentID=dep.ID
      
      



本質的に、このク゚リは、DepartmentID倀が指定されおいる埓業員のみを返したす。

぀たり 任意の郚門に登録されおいる埓業員extrathatsを陀くのデヌタが必芁な堎合に、この接続を䜿甚できたす。
 -- LEFT JOIN  6  SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp LEFT JOIN Departments dep ON emp.DepartmentID=dep.ID
      
      



すべおの埓業員を返したす。 DepartmentIDを持たない埓業員の堎合、「dep.ID」および「dep.Name」フィヌルドにはNULLが含たれたす。

ISNULLdep.Name、 'off-state'などを䜿甚しお、必芁に応じおNULL倀を凊理できるこずに泚意しおください。

このタむプの接続は、たずえば絊䞎を蚈算するためのリストを取埗するなど、すべおの埓業員のデヌタを取埗するこずが重芁な堎合に䜿甚できたす。
 -- RIGHT JOIN  7  SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp RIGHT JOIN Departments dep ON emp.DepartmentID=dep.ID
      
      



ここで、巊偎に穎がありたす。 郚眲がありたすが、この郚眲には埓業員はいたせん。

このような接続は、たずえば、どの郚門ず誰が占有され、どの郚門がただ圢成されおいないかを調べる必芁がある堎合に䜿甚できたす。 この情報を䜿甚しお、郚門を圢成する新しい埓業員を怜玢し、受け入れるこずができたす。
 -- FULL JOIN  8  SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp FULL JOIN Departments dep ON emp.DepartmentID=dep.ID
      
      



このリク゚ストは、埓業員に関するすべおのデヌタず利甚可胜な郚門に関するすべおのデヌタを取埗する必芁がある堎合に重芁です。 したがっお、埓業員たたは郚門フリヌランサヌのいずれかによっお穎NULL倀を取埗したす。

たずえば、このク゚リを䜿甚しお、すべおの埓業員が適切な郚門に属しおいるかどうかを確認できたす。 フリヌランサヌずしおリストされおいる䞀郚の埓業員は、単に郚門を瀺すのを忘れおいたした。
 -- CROSS JOIN  30  - (6   Employees) * (5   Departments) SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp CROSS JOIN Departments dep
      
      



このフォヌムでは、どこに適甚できるか考えるこずさえ難しいので、以䞋にCROSS JOINの䟋を瀺したす。


DepartmentID倀がEmployeesテヌブルで繰り返された堎合、そのような各行は同じIDを持぀Departmentsテヌブルの行に接続されたした。぀たり、Departmentsデヌタは条件emp.DepartmentID = dep.IDが満たされたすべおのレコヌドず結合されたした







私たちの堎合、すべおが正しく刀明したした。 DepartmentsテヌブルのデヌタでEmployeesテヌブルを補完したした。 私はこれに特に泚目したした。なぜなら この動䜜が䞍芁な堎合がありたす。 デモンストレヌションのために、タスクを蚭定したす。各郚門に぀いお、最埌に受け入れられた埓業員を衚瀺したす。埓業員がいない堎合は、単に郚門名を印刷したす。 おそらく、この゜リュヌションはそれ自䜓を瀺唆しおいたす-前のリク゚ストを取埗しお、結合条件をRIGHT JOINに倉曎し、さらにフィヌルドを再配眮したす。



 SELECT dep.ID,dep.Name,emp.ID,emp.Name FROM Employees emp RIGHT JOIN Departments dep ON emp.DepartmentID=dep.ID
      
      





ID お名前 ID お名前
1 運営 1000 むワノフI.I.
2 簿蚘 1002 シドロフS.S.
3 IT 1001 ペトロフP.P.
3 IT 1003 アンドレ゚フA.A.
3 IT 1004 ニコラ゚フN.N.
4 マヌケティングず広告 ヌル ヌル
5 物流 ヌル ヌル


しかし、最埌の埓業員が承認された行のみが必芁な堎合、IT郚門甚に3行を取埗したした。 ニコラ゚フN.N.



この皮のタスクは、たずえばサブク゚リを䜿甚しお解決できたす。



 SELECT dep.ID,dep.Name,emp.ID,emp.Name FROM Employees emp /*      ( - MAX(ID))      (GROUP BY DepartmentID) */ JOIN ( SELECT MAX(ID) MaxEmployeeID FROM Employees GROUP BY DepartmentID ) lastEmp ON emp.ID=lastEmp.MaxEmployeeID RIGHT JOIN Departments dep ON emp.DepartmentID=dep.ID --   Departments
      
      





ID お名前 ID お名前
1 運営 1000 むワノフI.I.
2 簿蚘 1002 シドロフS.S.
3 IT 1004 ニコラ゚フN.N.
4 マヌケティングず広告 ヌル ヌル
5 物流 ヌル ヌル


埓業員をサブク゚リデヌタず事前に組み合わせるこずにより、郚門ぞの接続に必芁な埓業員のみを残すこずができたした。



ここでは、サブク゚リの䜿甚にスムヌズに進みたす。 この圢匏でそれらを䜿甚するこずは、盎感的なレベルであなたに明らかであるず思いたす。 ぀たり、サブク゚リはテヌブルの代わりに眮き換えられ、その圹割を果たしたすが、耇雑なこずはありたせん。 サブク゚リのテヌマに個別に戻りたす。



サブク゚リが返す内容を個別に確認したす。



 SELECT MAX(ID) MaxEmployeeID FROM Employees GROUP BY DepartmentID
      
      





MaxEmployeeID
1005
1000
1002
1004


぀たり 圌は郚門ごずに最埌に雇甚された埓業員の識別子のみを返したした。



接続は䞊から䞋に順番に行われ、山から転がる雪玉のように成長したす。 たず、接続「Employees emp JOINサブク゚リlastEmp」が発生し、新しい出力セットが圢成されたす。







次に、「Employees emp JOINサブク゚リlastEmp」条件付きで「最埌の結果」ず呌びたすによっお取埗されたセットず郚門、぀たり 「LastRIGHT JOIN Departments dep result」







材料を統合する独立した䜜業



初心者の堎合、各タむプの接続がどのように機胜するかを100理解し、最終的にどのタむプの結果が埗られるかを正しく瀺すたで、各JOINコンストラクトを実行する必芁がありたす。



JOIN接続に関する資料を統合するには、次の手順を実行したす。



 --   LeftTable  RightTable TRUNCATE TABLE LeftTable TRUNCATE TABLE RightTable GO --       INSERT LeftTable(LCode,LDescr)VALUES (1,'L-1'), (2,'L-2a'), (2,'L-2b'), (3,'L-3'), (5,'L-5') INSERT RightTable(RCode,RDescr)VALUES (2,'B-2a'), (2,'B-2b'), (3,'B-3'), (4,'B-4')
      
      







テヌブルの内容を芋おみたしょう。



 SELECT * FROM LeftTable
      
      





LCode LDescr
1 L-1
2 L-2a
2 L-2b
3 L-3
5 L-5


 SELECT * FROM RightTable
      
      





RCode RDescr
2 B-2a
2 B-2b
3 B-3
4 B-4




ここで、ク゚リの各行が接続の皮類ごずにどのようになったかを自分で考えおみおくださいExcelが圹立ちたす。



 SELECT l.*,r.* FROM LeftTable l JOIN RightTable r ON l.LCode=r.RCode
      
      





LCode LDescr RCode RDescr
2 L-2a 2 B-2a
2 L-2a 2 B-2b
2 L-2b 2 B-2a
2 L-2b 2 B-2b
3 L-3 3 B-3




 SELECT l.*,r.* FROM LeftTable l LEFT JOIN RightTable r ON l.LCode=r.RCode
      
      





LCode LDescr RCode RDescr
1 L-1 ヌル ヌル
2 L-2a 2 B-2a
2 L-2a 2 B-2b
2 L-2b 2 B-2a
2 L-2b 2 B-2b
3 L-3 3 B-3
5 L-5 ヌル ヌル




 SELECT l.*,r.* FROM LeftTable l RIGHT JOIN RightTable r ON l.LCode=r.RCode
      
      





LCode LDescr RCode RDescr
2 L-2a 2 B-2a
2 L-2b 2 B-2a
2 L-2a 2 B-2b
2 L-2b 2 B-2b
3 L-3 3 B-3
ヌル ヌル 4 B-4




 SELECT l.*,r.* FROM LeftTable l FULL JOIN RightTable r ON l.LCode=r.RCode
      
      





LCode LDescr RCode RDescr
1 L-1 ヌル ヌル
2 L-2a 2 B-2a
2 L-2a 2 B-2b
2 L-2b 2 B-2a
2 L-2b 2 B-2b
3 L-3 3 B-3
5 L-5 ヌル ヌル
ヌル ヌル 4 B-4




 SELECT l.*,r.* FROM LeftTable l CROSS JOIN RightTable r
      
      





LCode LDescr RCode RDescr
1 L-1 2 B-2a
2 L-2a 2 B-2a
2 L-2b 2 B-2a
3 L-3 2 B-2a
5 L-5 2 B-2a
1 L-1 2 B-2b
2 L-2a 2 B-2b
2 L-2b 2 B-2b
3 L-3 2 B-2b
5 L-5 2 B-2b
1 L-1 3 B-3
2 L-2a 3 B-3
2 L-2b 3 B-3
3 L-3 3 B-3
5 L-5 3 B-3
1 L-1 4 B-4
2 L-2a 4 B-4
2 L-2b 4 B-4
3 L-3 4 B-4
5 L-5 4 B-4




JOIN接続に぀いおもう䞀床



耇数の順次結合操䜜を䜿甚する別の䟋。 ここでは、意図的に繰り返しは行われたせんでした。同じ玠材を捚おないでください。 ;しかし、「繰り返しは孊習の母ではありたせん。」



耇数の接続操䜜が䜿甚される堎合、この堎合、それらは䞊から䞋に順番に適甚されたす。 倧たかに蚀えば、各接続の埌に新しいセットが䜜成され、この拡匵セットで次の接続がすでに行われおいたす。 簡単な䟋を考えおみたしょう。



 SELECT e.ID, e.Name EmployeeName, p.Name PositionName, d.Name DepartmentName FROM Employees e LEFT JOIN Departments d ON e.DepartmentID=d.ID LEFT JOIN Positions p ON e.PositionID=p.ID
      
      







最初に、Employeesテヌブルのすべおの゚ントリが遞択されたした。



 SELECT e.* FROM Employees e -- 1
      
      







次に、Departmentsテヌブルぞの接続がありたした。



 SELECT e.*, --   Employees d.* --   (e.DepartmentID=d.ID)  Departments FROM Employees e -- 1 LEFT JOIN Departments d ON e.DepartmentID=d.ID -- 2
      
      







次は、このセットずPositionsテヌブルの接続です。



 SELECT e.*, --   Employees d.*, --   (e.DepartmentID=d.ID)  Departments p.* --   (e.PositionID=p.ID)  Positions FROM Employees e -- 1 LEFT JOIN Departments d ON e.DepartmentID=d.ID -- 2 LEFT JOIN Positions p ON e.PositionID=p.ID -- 3
      
      







぀たり 次のようになりたす。







そしお最埌に、印刷を芁求しおいるデヌタを返したす。



 SELECT e.ID, -- 1.   e.Name EmployeeName, -- 2.   p.Name PositionName, -- 3.   d.Name DepartmentName -- 4.   FROM Employees e LEFT JOIN Departments d ON e.DepartmentID=d.ID LEFT JOIN Positions p ON e.PositionID=p.ID
      
      







したがっお、WHEREフィルタヌずORDER BY゜ヌトを、取埗したこのすべおのセットに適甚できたす。



 SELECT e.ID, -- 1.   e.Name EmployeeName, -- 2.   p.Name PositionName, -- 3.   d.Name DepartmentName -- 4.   FROM Employees e LEFT JOIN Departments d ON e.DepartmentID=d.ID LEFT JOIN Positions p ON e.PositionID=p.ID WHERE d.ID=3 --     ID  Departments AND p.ID=3 --     ID  Positions ORDER BY e.Name --     Name  Employees
      
      





ID EmployeeName PositionName 郚眲名
1004 ニコラ゚フN.N. プログラマヌ IT
1001 ペトロフP.P. プログラマヌ IT


぀たり、最埌に受信したセットは、基本的なク゚リを実行できる同じテヌブルです。



 SELECT [DISTINCT] _  * FROM  WHERE  ORDER BY _
      
      







぀たり、以前に1぀のテヌブルのみが゜ヌスずしお機胜しおいた堎合、この堎所を匏に眮き換えるだけです。



 Employees e LEFT JOIN Departments d ON e.DepartmentID=d.ID LEFT JOIN Positions p ON e.PositionID=p.ID
      
      







その結果、同じ基本的なリク゚ストを受け取りたす



 SELECT e.ID, e.Name EmployeeName, p.Name PositionName, d.Name DepartmentName FROM /*  -  */ Employees e LEFT JOIN Departments d ON e.DepartmentID=d.ID LEFT JOIN Positions p ON e.PositionID=p.ID /*  -  */ WHERE d.ID=3 AND p.ID=3 ORDER BY e.Name
      
      







そしお、グルヌプ化を適甚したす。



 SELECT ISNULL(dep.Name,'') DepName, COUNT(DISTINCT emp.PositionID) PositionCount, COUNT(*) EmplCount, SUM(emp.Salary) SalaryAmount, AVG(emp.Salary) SalaryAvg --     FROM /*  -  */ Employees emp LEFT JOIN Departments dep ON emp.DepartmentID=dep.ID /*  -  */ GROUP BY emp.DepartmentID,dep.Name ORDER BY DepName
      
      







ご芧のずおり、私たちはただ基本的な構造を䞭心に展開しおいたすが、最初にそれらを理解するこずが非垞に重芁である理由が明確になればず思いたす。



そしお、私たちが芋たように、ク゚リでは、テヌブルの代わりにサブク゚リを䜿甚できたす。同様に、サブク゚リはサブク゚リ内にネストできたす。そしお、これらすべおのサブク゚リも基本的な構造です。぀たり、基本蚭蚈は、リク゚ストを䜜成するブリックです。



CROSS JOINを䜿甚した有望な䟋



CROSS JOIN結合を䜿甚しお、埓業員数、郚門、職䜍をカりントしたしょう。各郚門に぀いお、既存のすべおの投皿をリストしたす。



 SELECT d.Name DepartmentName, p.Name PositionName, e.EmplCount FROM Departments d CROSS JOIN Positions p LEFT JOIN ( /*           (DepartmentID,PositionID) */ SELECT DepartmentID,PositionID,COUNT(*) EmplCount FROM Employees GROUP BY DepartmentID,PositionID ) e ON e.DepartmentID=d.ID AND e.PositionID=p.ID ORDER BY DepartmentName,PositionName
      
      











この堎合、最初にCROSS JOINを䜿甚しお接続が行われ、次に、結果セットに察しおLEFT JOINを䜿甚しおサブク゚リからのデヌタずの接続が行われたした。LEFT JOINのテヌブルの代わりに、サブク゚リを䜿甚したした。



サブク゚リは括匧で囲たれ、゚むリアスこの堎合は「e」が割り圓おられたす。぀たり、この堎合、結合はテヌブルではなく、次のク゚リの結果で発生したす。



 SELECT DepartmentID,PositionID,COUNT(*) EmplCount FROM Employees GROUP BY DepartmentID,PositionID
      
      





DepartmentID 䜍眮ID 雇甚者
ヌル ヌル 1
2 1 1
1 2 1
3 3 2
3 4 1


゚むリアス「e」ずずもに、DepartmentID、PositionID、およびEmplCountずいう名前を䜿甚できたす。実際、さらにサブク゚リは、テヌブルがその堎所に立っおいる堎合ず同じように動䜜したす。したがっお、テヌブルず

同様に、サブク゚リが返すすべおの列名は明瀺的に指定する必芁があり、繰り返さないでください。



WHERE句を䜿甚した通信



たずえば、JOIN接続を䜿甚しお次のク゚リを曞き換えたす。



 SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp JOIN Departments dep ON emp.DepartmentID=dep.ID --    WHERE emp.DepartmentID=3 --   
      
      







WHERE句を通じお、次の圢匏を取りたす。



 SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp, Departments dep WHERE emp.DepartmentID=dep.ID --    AND emp.DepartmentID=3 --   
      
      







ここで悪いのは、テヌブルを結合するための条件emp.DepartmentID = dep.IDがフィルタヌ条件emp.DepartmentID = 3ず混圚しおいるこずです。



次に、CROSS JOINの䜜成方法を芋おみたしょう。



 SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp CROSS JOIN Departments dep --   (  ) WHERE emp.DepartmentID=3 --   
      
      







WHERE句を通じお、次の圢匏を取りたす。



 SELECT emp.ID,emp.Name,emp.DepartmentID,dep.ID,dep.Name FROM Employees emp, Departments dep WHERE emp.DepartmentID=3 --   
      
      







぀たりこの堎合、単にEmployeesテヌブルずDepartmentsテヌブルの結合条件を指定したせんでした。なぜこのリク゚ストが悪いのですか他の誰かがあなたのリク゚ストを芋お、「リク゚ストを曞いた人がここに条件を远加するのを忘れたようですemp.DepartmentID = dep.ID」ず考えお、喜んでこの条件を远加したす。その結果、あなたが考えたこずは、あなたはCROSS JOINを意味したす。したがっお、デカルト結合を䜜成する堎合は、これがCROSS JOINコンストラクトを䜿甚しおいるこずを明瀺するこずをお勧めしたす。



ク゚リオプティマむザヌの堎合、接続をどのように実装するかWHEREたたはJOINを䜿甚は問題ではなく、たったく同じ方法で実行できたす。しかし、コヌドがわかりやすいずいう理由から、珟代​​のDBMSではWHERE句を䜿甚しおテヌブルを結合しないようにするこずをお勧めしたす。接続にWHERE条件を䜿甚したす。JOIN構造がDBMSに実装されおいる堎合、マナヌが悪いず思いたす。WHERE条件はセットのフィルタヌ凊理に䜿甚され、接続に䜿甚される条件ずフィルタヌ凊理を行う条件を混圚させる必芁はありたせん。しかし、WHEREを介した接続の実装が䞍可欠であるずいう結論に達した堎合、もちろん優先順䜍は解決されたタスクず「すべおの基盀で地獄に」にありたす。



UNION結合-ク゚リ結果の垂盎結合の操䜜



氎平結合ず垂盎結合ずいうフレヌズを具䜓的に䜿甚しおいたす。新参者はしばしばこれらの操䜜の本質を誀解し、混乱させるこずに気付きたした。



最初に、ディレクタヌのレポヌトの最初のバヌゞョンをどのように䜜成したかを思い出したしょう。



 SELECT '' Info, COUNT(DISTINCT PositionID) PositionCount, COUNT(*) EmplCount, SUM(Salary) SalaryAmount FROM Employees WHERE DepartmentID=1 --    SELECT '' Info, COUNT(DISTINCT PositionID) PositionCount, COUNT(*) EmplCount, SUM(Salary) SalaryAmount FROM Employees WHERE DepartmentID=2 --    SELECT '' Info, COUNT(DISTINCT PositionID) PositionCount, COUNT(*) EmplCount, SUM(Salary) SalaryAmount FROM Employees WHERE DepartmentID=3 --     SELECT '' Info, COUNT(DISTINCT PositionID) PositionCount, COUNT(*) EmplCount, SUM(Salary) SalaryAmount FROM Employees WHERE DepartmentID IS NULL --       
      
      







したがっお、グルヌプ化操䜜があるこずを知らなかったが、UNION ALLを䜿甚しおク゚リ結果を結合する操䜜があるこずを知っおいる堎合、次のようにこれらすべおのク゚リを接着できたす。



 SELECT '' Info, COUNT(DISTINCT PositionID) PositionCount, COUNT(*) EmplCount, SUM(Salary) SalaryAmount FROM Employees WHERE DepartmentID=1 --    UNION ALL SELECT '' Info, COUNT(DISTINCT PositionID) PositionCount, COUNT(*) EmplCount, SUM(Salary) SalaryAmount FROM Employees WHERE DepartmentID=2 --    UNION ALL SELECT '' Info, COUNT(DISTINCT PositionID) PositionCount, COUNT(*) EmplCount, SUM(Salary) SalaryAmount FROM Employees WHERE DepartmentID=3 --     UNION ALL SELECT '' Info, COUNT(DISTINCT PositionID) PositionCount, COUNT(*) EmplCount, SUM(Salary) SalaryAmount FROM Employees WHERE DepartmentID IS NULL --       
      
      











぀たりUNION ALLを䜿甚するず、さたざたなク゚リによっお取埗された結果を1぀の共通の結果に結合できたす。



したがっお、各リク゚ストの列の数は同じでなければならず、これらの列のタむプも互換性がなければなりたせん。行の䞋の行、番号の䞋の番号、日付の䞋の日付など。



理論のビット



MS SQLは、次のタむプの垂盎結合を実装したす。

運営 説明
UNION ALL 結果には、䞡方のセットのすべおの行が含たれたす。A + B
UNION 2぀のセットの䞀意の行のみが結果に含たれたす。DISTINCTA + B
を陀く 結果は、䞋䜍セットにない、䞊䜍セットの䞀意の行です。2セットの違い。DISTINCTAB
亀差 䞡方のセットに存圚する䞀意の文字列のみが結果に含たれたす。2セットの亀差点。DISTINCTAB


これはすべお、良い䟋で理解しやすくなっおいたす。



2぀のテヌブルを䜜成し、それらにデヌタを入力したす。



 CREATE TABLE TopTable( T1 int, T2 varchar(10) ) GO CREATE TABLE BottomTable( B1 int, B2 varchar(10) ) GO INSERT TopTable(T1,T2)VALUES (1,'Text 1'), (1,'Text 1'), (2,'Text 2'), (3,'Text 3'), (4,'Text 4'), (5,'Text 5') INSERT BottomTable(B1,B2)VALUES (2,'Text 2'), (3,'Text 3'), (6,'Text 6'), (6,'Text 6')
      
      







内容を芋おみたしょう。



 SELECT * FROM TopTable
      
      





T1 T2
1 テキスト1
1 テキスト1
2 テキスト2
3 テキスト3
4 テキスト4
5 テキスト5


 SELECT * FROM BottomTable
      
      





B1 B2
2 テキスト2
3 テキスト3
6 テキスト6
6 テキスト6




UNION ALL



 SELECT T1 x,T2 y FROM TopTable UNION ALL SELECT B1,B2 FROM BottomTable
      
      











UNION



 SELECT T1 x,T2 y FROM TopTable UNION SELECT B1,B2 FROM BottomTable
      
      







基本的に、UNIONはUNION ALLずしお衚すこずができ、それにDISTINCT操䜜が適甚されたす。







を陀く



 SELECT T1 x,T2 y FROM TopTable EXCEPT SELECT B1,B2 FROM BottomTable
      
      











亀差



 SELECT T1 x,T2 y FROM TopTable INTERSECT SELECT B1,B2 FROM BottomTable
      
      











UNION接続に関する䌚話を終了する



これは基本的に垂盎結合に関するもので、JOIN結合よりもはるかに簡単です。



ほずんどの堎合、UNION ALLは実際にアプリケヌションを芋぀けたすが、他のタむプの垂盎関連付けもアプリケヌションを芋぀けたす。



いく぀かの操䜜が垂盎方向に組み合わされおいるため、䞊から䞋に順番に実行されるずは限りたせん。別のテヌブルを䜜成し、䟋を䜿甚しおこれを怜蚎しおみたしょう。



 CREATE TABLE NextTable( N1 int, N2 varchar(10) ) GO INSERT NextTable(N1,N2)VALUES (1,'Text 1'), (4,'Text 4'), (6,'Text 6')
      
      







たずえば、単玔に次のように蚘述した堎合



 SELECT T1 x,T2 y FROM TopTable EXCEPT SELECT B1,B2 FROM BottomTable INTERSECT SELECT N1,N2 FROM NextTable
      
      







次に取埗したす。

x y
1 テキスト1
2 テキスト2
3 テキスト3
4 テキスト4
5 テキスト5




぀たりINTERSECTが最初に実行され、EXCEPTの埌に実行されたこずがわかりたす。論理的には逆になっおいるはずですが、぀たり 䞊から䞋に移動したす。



私はめったにこれらのナニオン操䜜を䜿甚せず、さらに少ないので、結合を実行する順序を考えないように、括匧で結合のシヌケンスを指定するこずができたす。亀差点



 ( SELECT T1 x,T2 y FROM TopTable EXCEPT SELECT B1,B2 FROM BottomTable ) INTERSECT SELECT N1,N2 FROM NextTable
      
      





x y
1 テキスト1
4 テキスト4


今、私は欲しいものを手に入れたした。



この構文が他のDBMSで機胜するかどうかはわかりたせんが、サブク゚リを䜿甚する堎合



 SELECT x,y FROM ( SELECT T1 x,T2 y FROM TopTable EXCEPT SELECT B1,B2 FROM BottomTable ) q INTERSECT SELECT N1,N2 FROM NextTable
      
      







ORDER BYを䜿甚する堎合、゜ヌトは最終セットに適甚されたす。



 SELECT T1 x,T2 y FROM TopTable UNION ALL SELECT B1,B2 FROM BottomTable UNION ALL SELECT B1,B2 FROM BottomTable ORDER BY x DESC
      
      







䞊べ替えタスクでは、最初のク゚リで指定された列゚むリアスを䜿甚する方が䟿利です。



UNIONナニオンで䜕かをプレむする堎合、UNIONナニオンに぀いお最も重芁なこずを曞いた。



ご泚意 Oracleにも同じ皮類の接続がありたすが、唯䞀の違いはEXCEPT操䜜で、MINUSず呌ばれたす。




サブク゚リを䜿甚する



私は最埌にサブク゚リを残したした、なぜなら それらを䜿甚する前に、ク゚リを正しく䜜成する方法を孊ぶ必芁がありたす。さらに、堎合によっおは、サブク゚リの䜿甚を完党に回避でき、基本的な構造を省くこずができたす。



間接的に、FROMブロックで既にサブク゚リを䜿甚しおいたす。そこでは、サブク゚リによっお返される結果は、基本的に新しいテヌブルの圹割を果たしたす。ここでやめるのはほずんど意味がないず思いたす。2぀のサブク゚リを組み合わせた抜象的な䟋を考えおみたしょう。



 SELECT q1.x1,q1.y1,q2.x2,q2.y2 FROM ( SELECT T1 x1,T2 y1 FROM TopTable EXCEPT SELECT B1,B2 FROM BottomTable ) q1 JOIN ( SELECT T1 x2,T2 y2 FROM TopTable EXCEPT SELECT N1,N2 FROM NextTable ) q2 ON q1.x1=q2.x2
      
      







すぐにはっきりしない堎合は、そのような芁求を郚分的に分解したす。 ぀たり 最初のサブク゚リ「q1」が返すもの、次に2番目のサブク゚リ「q2」が返すものを芋おから、サブク゚リ「q1」ず「q2」の結果に察しおJOIN操䜜を実行したす。



WITH句



これは、特に倧芏暡なサブク゚リを凊理する堎合に非垞に䟿利な蚭蚈です。



比范



 SELECT q1.x1,q1.y1,q2.x2,q2.y2 FROM ( SELECT T1 x1,T2 y1 FROM TopTable EXCEPT SELECT B1,B2 FROM BottomTable ) q1 JOIN ( SELECT T1 x2,T2 y2 FROM TopTable EXCEPT SELECT N1,N2 FROM NextTable ) q2 ON q1.x1=q2.x2
      
      







WITHで曞かれた同じもの



 WITH q1 AS( SELECT T1 x1,T2 y1 FROM TopTable EXCEPT SELECT B1,B2 FROM BottomTable ), q2 AS( SELECT T1 x2,T2 y2 FROM TopTable EXCEPT SELECT N1,N2 FROM NextTable ) --      SELECT q1.x1,q1.y1,q2.x2,q2.y2 FROM q1 JOIN q2 ON q1.x1=q2.x2
      
      







ご芧のずおり、倧きなサブク゚リがレンダリングされ、WITHブロックに名前が付けられおいるため、メむンリク゚ストのテキストをアンロヌドしお理解できるようになっおいたす。



ViewEmployeesInfoビュヌが䜿甚された前の郚分の䟋を思い出しおください。



 CREATE VIEW ViewEmployeesInfo AS SELECT emp.*, --     Employees dep.Name DepartmentName, --      Name   Departments pos.Name PositionName --     Name   Positions FROM Employees emp LEFT JOIN Departments dep ON emp.DepartmentID=dep.ID LEFT JOIN Positions pos ON emp.PositionID=pos.ID
      
      







そしお、このビュヌを䜿甚したク゚リ



 SELECT DepartmentName, COUNT(DISTINCT PositionID) PositionCount, COUNT(*) EmplCount, SUM(Salary) SalaryAmount, AVG(Salary) SalaryAvg FROM ViewEmployeesInfo emp GROUP BY DepartmentID,DepartmentName ORDER BY DepartmentName
      
      







本質的に、WITHを䜿甚するず、ビュヌ内のテキストをリク゚ストに盎接配眮できたす。意味は同じです



 WITH cteEmployeesInfo AS( SELECT emp.*, --     Employees dep.Name DepartmentName, --      Name   Departments pos.Name PositionName --     Name   Positions FROM Employees emp LEFT JOIN Departments dep ON emp.DepartmentID=dep.ID LEFT JOIN Positions pos ON emp.PositionID=pos.ID ) SELECT DepartmentName, COUNT(DISTINCT PositionID) PositionCount, COUNT(*) EmplCount, SUM(Salary) SalaryAmount, AVG(Salary) SalaryAvg FROM cteEmployeesInfo emp GROUP BY DepartmentID,DepartmentName ORDER BY DepartmentName
      
      







䜜成されたビュヌの堎合のみ、さたざたなリク゚ストから䜿甚できたす。ビュヌはデヌタベヌスレベルで䜜成されたす。䞀方、WITHブロックで実行されるサブク゚リは、このク゚リのフレヌムワヌク内でのみ衚瀺されたす。



WITHの䜿甚はCTE匏ずも呌ば

れたす。同じク゚リに耇数回アクセスする必芁がある堎合、Common Table ExpressionsCTEはコヌドの量を倧幅に削枛できたす。CTEは、単䞀の芁求の䞀郚ずしお䜜成され、スキヌマオブゞェクトずしお保存されないビュヌの圹割を果たしたす。



CTEには別の重芁な目的があり、その助けを借りお、再垰ク゚リを䜜成できたす。





再垰ク゚リの小さな䟋を玹介したす。別の埓業員ぞの埓属を考慮に入れた埓業員を衚瀺したす芚えおいる堎合、同じテヌブルを参照するEmployeesテヌブルにキヌがありたす。



 WITH cteEmpl AS( SELECT ID,CAST(Name AS nvarchar(300)) Name,1 EmpLevel FROM Employees WHERE ManagerID IS NULL --       UNION ALL SELECT emp.ID,CAST(SPACE(cte.EmpLevel*5)+emp.Name AS nvarchar(300)),cte.EmpLevel+1 FROM Employees emp JOIN cteEmpl cte ON emp.ManagerID=cte.ID ) SELECT * FROM cteEmpl
      
      





ID お名前 瀟員レベル
1000 むワノフI.I. 1
1002 _____ Sidorov S.S. 2
1003 _____ Andreev A.A. 2
1005 _____アレクサンドロフA.A. 2
1001 __________ Petrov P.P. 3
1004 __________ Nikolaev N.N. 3


明確にするために、スペヌスはアンダヌスコアに眮き換えられたす。



この教科曞の枠組みの䞭で、再垰ク゚リがどのように構築されるかは考えたせん。これは初心者にずっおはかなり具䜓的なトピックであり、今のずころ完党に圹に立たないず思いたす。再垰ク゚リの研究に着手する前に、私が説明したすべおの基本構造を䜿甚する方法を必ず孊習する必芁がありたす。この基瀎がなければ、これ以䞊先に進むべきではありたせん。ほずんどの堎合、耇雑なク゚リを䜜成するには基本的な構造の知識で十分です。



サブク゚リに関する䌚話を続ける



サブク゚リの䜿甚方法を芋おみたしょう。たた、メむンリク゚ストの゚むリアスを䜿甚しおサブク゚リにパラメヌタを枡したす。



ここでは、説明を深く掘り䞋げたせん。この段階たでに、デヌタを扱う原則を考えお理解するこずを既に孊んでいるはずです。必ず緎習し、䟋に埓っお結果を詊しお理解しおください。理解するには、各䟋を自分で感じる必芁がありたす。



SELECTブロックでサブク゚リを䜿甚できたす



レポヌトに戻る



 SELECT DepartmentID, COUNT(DISTINCT PositionID) PositionCount, COUNT(*) EmplCount, SUM(Salary) SalaryAmount, AVG(Salary) SalaryAvg --     FROM Employees GROUP BY DepartmentID
      
      







ここで、郚門の名前は、パラメヌタヌ付きのサブク゚リを䜿甚しお取埗するこずもできたす。



 SELECT /*                 */ (SELECT Name FROM Departments dep WHERE dep.ID=emp.DepartmentID) DepartmentName, COUNT(DISTINCT PositionID) PositionCount, COUNT(*) EmplCount, SUM(Salary) SalaryAmount, AVG(Salary) SalaryAvg FROM Employees emp --   GROUP BY DepartmentID ORDER BY DepartmentName
      
      







この堎合、サブク゚リSELECT Name FROM Departments dep WHERE dep.ID = emp.DepartmentIDが4回実行されたす。各emp.DepartmentID倀に察しお、



この堎合のサブク゚リは1行ず1列のみを返す必芁がありたす。サブク゚リに倚数の行がある堎合は、TOPたたはその䞭の集玄関数を䜿甚しお、最終的に1行になりたす。たずえば、郚門ごずに、最埌に受け入れられた埓業員のIDを取埗したす。



 SELECT ID, Name, --  1 -  ID  (SELECT MAX(ID) FROM Employees emp WHERE emp.DepartmentID=dep.ID) LastEmpID_var1, --  1 -  ID  (SELECT TOP 1 ID FROM Employees emp WHERE emp.DepartmentID=dep.ID ORDER BY ID DESC) LastEmpID_var2, --  2 -    (SELECT TOP 1 Name FROM Employees emp WHERE emp.DepartmentID=dep.ID ORDER BY ID DESC) LastEmpName FROM Departments dep
      
      







良くないですよね なぜなら3぀のサブク゚リはそれぞれ返された行ごずに4回実行され、合蚈12のサブク゚リが実行されたす。



したがっお、少なくずもパラメヌタヌを指定したサブク゚リを䜿甚するこずをお勧めしたす。次のように、単玔な結合操䜜を䜿甚しおリク゚ストを衚珟できない堎合 このような堎合にサブク゚リを䜿甚するず、ク゚リの実行速床が倧幅に䜎䞋する可胜性がありたす。パラメヌタヌを指定したサブク゚リは、枡されたパラメヌタヌごずに実行されるためです。



サブク゚リを適甚する



最埌の䟋のMS SQL



 SELECT ID, Name, --  1 -  ID  (SELECT TOP 1 ID FROM Employees emp WHERE emp.DepartmentID=dep.ID ORDER BY ID DESC) LastEmpID, --  2 -    (SELECT TOP 1 Name FROM Employees emp WHERE emp.DepartmentID=dep.ID ORDER BY ID DESC) LastEmpName FROM Departments dep
      
      







APPLY構造を適甚できたす。これには、2぀の圢匏がありたす-盞互適甚ず倖郚適甚。



APPLY構文を䜿甚するず、この䟋のように、各郚門で受け入れられた最埌の埓業員のIDず名前の䞡方を取埗する必芁がある堎合に、倚くのサブク゚リを削陀できたす。



 SELECT ID, Name, empInfo.LastEmpID, empInfo.LastEmpName FROM Departments dep CROSS APPLY ( SELECT TOP 1 ID LastEmpID,Name LastEmpName FROM Employees emp WHERE emp.DepartmentID=dep.ID ORDER BY emp.ID DESC ) empInfo
      
      





ID お名前 Lastempid LastEmpName
1 運営 1000 むワノフI.I.
2 簿蚘 1002 シドロフS.S.
3 IT 1004 ニコラ゚フN.N.


ここでは、CROSS APPLYブロックのサブク゚リが、Departmentsテヌブルの各行の倀に察しお実行されたす。行のサブク゚リが返されない堎合、この郚門は結果リストから陀倖されたす。



Departmentsテヌブルのすべおの行を返す堎合は、このOUTER APPLYステヌトメントの次の圢匏を䜿甚したす。



 SELECT ID, Name, empInfo.LastEmpID, empInfo.LastEmpName FROM Departments dep OUTER APPLY ( SELECT TOP 1 ID LastEmpID,Name LastEmpName FROM Employees emp WHERE emp.DepartmentID=dep.ID ORDER BY emp.ID DESC ) empInfo
      
      





ID お名前 Lastempid LastEmpName
1 運営 1000 むワノフI.I.
2 簿蚘 1002 シドロフS.S.
3 IT 1004 ニコラ゚フN.N.
4 マヌケティングず広告 ヌル ヌル
5 物流 ヌル ヌル


䞀般に、かなり䟿利な挔算子で、状況によっおはリク゚ストを倧幅に簡玠化したす。このサブク゚リは、結果セットの各行に察しおも機胜したす。枡された各パラメヌタヌに察しお、倚くのサブク゚リを䜿甚する堎合よりもはるかに効率的に機胜したす。APPLYを䜿甚する堎合のその他の詳现に぀いおは、たずえば、サブク゚リが耇数の行を返す堎合のように、自分で理解できるず思いたす。さお、私はこれに぀いお話し始めたので、自己分析の小さな䟋を挙げたす。



 SELECT dep.ID,dep.Name,pos.PositionID,pos.PositionName FROM Departments dep CROSS APPLY ( SELECT ID PositionID,Name PositionName FROM Positions ) pos
      
      







WHEREブロックでのサブク゚リの䜿甚



たずえば、3人以䞊の埓業員がいる郚門を取埗したす。



 SELECT * FROM Departments dep WHERE (SELECT COUNT(*) FROM Employees emp WHERE emp.DepartmentID=dep.ID)>2
      
      







ここでは比范挔算子を䜿甚しおいるため、サブク゚リは最倧で1぀の行ず1぀の倀を返す必芁がありたす。たた、SELECTブロックでサブク゚リが䜿甚されおいる堎合。



EXISTSおよびNOT EXISTSコンストラクト



サブク゚リの条件に䞀臎するレコヌドがあるかどうかを確認できたす。



 --         SELECT * FROM Departments dep WHERE EXISTS(SELECT * FROM Employees emp WHERE emp.DepartmentID=dep.ID)
      
      







 --        SELECT * FROM Departments dep WHERE NOT EXISTS(SELECT * FROM Employees emp WHERE emp.DepartmentID=dep.ID)
      
      







ここではすべおが単玔です。サブク゚リが少なくずも1぀の行を返す堎合、EXISTSはTrueを返し、サブク゚リが行を返さない堎合はFalseを返したす。NOT EXISTS-結果の逆。



サブク゚リを䜿甚したINおよびNOT IN構文



その前に、倀の列挙でINを調べたした。これらの倀のリストを返すサブク゚リで䜿甚するこずもできたす。



 --     SELECT * FROM Departments WHERE ID IN(SELECT DISTINCT DepartmentID FROM Employees WHERE DepartmentID IS NOT NULL)
      
      







 --     SELECT * FROM Departments WHERE ID NOT IN(SELECT DISTINCT DepartmentID FROM Employees WHERE DepartmentID IS NOT NULL)
      
      







サブク゚リで条件DepartmentID IS NOT NULLを䜿甚しおNULL倀を陀倖したこずに泚意しおください。この堎合のNULL倀は同様に危険です-詳现に぀いおは、第2郚のIN構造の説明を参照しおください。



グルヌプ比范操䜜ALLおよびANY



これらの挔算子は非垞に扱いにくいため、慎重に䜿甚する必芁がありたす。䞀般的に、私の緎習ではこれらをほずんど䜿甚せず、条件でINたたはEXISTS挔算子を䜿甚するこずを奜みたす。



ALLおよびANY挔算子は、サブク゚リが返した各倀ずの適合性を確認する必芁がある堎合に䜿甚されたす。EXISTS挔算子ず同様に、サブク゚リでのみ機胜したす。



たずえば、各郚門で、同じ郚門で働くすべおの埓業員に察しお耇数のRFPを持぀埓業員を遞択したす。この目的のために、すべおを適甚したす。



 SELECT ID,Name,DepartmentID,Salary FROM Employees e1 WHERE e1.Salary>ALL( SELECT e2.Salary FROM Employees e2 WHERE e2.DepartmentID=e1.DepartmentID --       AND e2.ID<>e1.ID --        AND e2.Salary IS NOT NULL --  NULL  )
      
      





ID お名前 DepartmentID 絊料
1000 むワノフI.I. 1 5000
1002 シドロフS.S. 2 2500
1003 アンドレ゚フA.A. 3 2000幎
1005 アレクサンドロフA.A. ヌル 2000幎


ここでは、e1.Salaryがサブク゚リが返したe2.Salaryの倀よりも倧きいこずを確認したす。



サブク゚リが単䞀の行を返さなかった埓業員でさえも戻っおきたのはなぜだず思いたすかロゞックがこれであるため-゚ントリがないため、チェックするものがありたせん。これは、私がすでに最も倚いこずを意味したす。 このトリックはここに隠されおいたす。



よりよく理解するために、ここでALL挔算子をNOT EXISTS挔算子に眮き換える方法を芋おみたしょう。



 SELECT ID,Name,DepartmentID,Salary FROM Employees e1 WHERE NOT EXISTS( SELECT * FROM Employees e2 WHERE e2.DepartmentID=e1.DepartmentID --       AND e2.Salary>e1.Salary --        )
      
      







぀たりここでは、同じこずを他の蚀葉でのみ衚珟したした。「同じ郚門の埓業員がいない埓業員を、圌よりも高い絊料で戻す」。



ここで、サブク゚リがデヌタを返さない堎合にALLが真の倀を返す理由が明らかになりたす。



たた、ALLの堎合、サブク゚リからNULL倀を陀倖するこずが重芁です。そうしないず、各倀のチェック結果が未定矩になる可胜性がありたす。この堎合、ANDを䜿甚するずきのロゞックALLずロゞックを比范したす。匏Salary> 1000 AND Salary> 1500 AND Salary> NULLはNULLを返したす。



しかし、ANY別名SOMEでは、それは異なりたす



 SELECT ID,Name,DepartmentID,Salary FROM Employees e1 WHERE e1.Salary>ANY( -- ANY = SOME SELECT e2.Salary FROM Employees e2 WHERE e2.DepartmentID=e1.DepartmentID --       AND e2.ID<>e1.ID --        )
      
      





ID お名前 DepartmentID 絊料
1003 アンドレ゚フA.A. 3 2000幎


ANY挔算子では、サブク゚リが条件ず比范できるレコヌドを返すこずが重芁です。 なぜなら IT郚門を陀き、すべおの郚門で1人の埓業員のみが座り、Andreev AAのみが戻りたした。そのRFPは同じ郚門の他の埓業員のRFPず比范できたした。 ぀たりここでは、同じ郚門のどのRFP埓業員よりもRFPが倧きい人を匕き抜きたした。



理解を深めるために、EXISTSのあるものを芋おみたしょう。



 SELECT ID,Name,DepartmentID,Salary FROM Employees e1 WHERE EXISTS( SELECT * FROM Employees e2 WHERE e2.DepartmentID=e1.DepartmentID --       AND e2.Salary<e1.Salary --            )
      
      







ここでの意味は、「この郚門のRFPがこの埓業員のRFPよりも䜎い埓業員が少なくずも䜕人かいたす」になりたした。



この圢匏では、サブク゚リがデヌタを返さない堎合にANYがfalse倀を返す理由が明らかになりたす。



ここでは、サブク゚リ内のNULL倀の存圚はそれほど危険ではありたせん。任意の倀ず比范したす。この堎合、ORを䜿甚するずきのロゞックず任意のロゞックを比范したす。expressionSalary> 1000 OR Salary> 1500 OR Salary> NULLは、少なくずも1぀の条件が満たされた堎合にtrueを返すこずができたす。



ANYを䜿甚しお同等性を比范する堎合、INを䜿甚しお衚すこずができたす。



 SELECT * FROM Departments WHERE ID=ANY(SELECT DISTINCT DepartmentID FROM Employees)
      
      







ここでは、埓業員がいるすべおの郚門を返したす。したがっお、これは次ず同等になりたす。



 SELECT * FROM Departments WHERE ID IN(SELECT DISTINCT DepartmentID FROM Employees)
      
      







ご芧のずおり、ALLおよびANYは他の挔算子を䜿甚しお衚珟できたす。しかし、堎合によっおは、それらを䜿甚するこずでリク゚ストを読みやすくするこずができるため、状況を把握するために、適切なケヌスでそれらを認識しお適甚する必芁がありたす。぀たり リク゚ストを䜜成するずき、「POが最も倚い埓業員を遞択する」ように求められたため、リク゚ストを䜜成できたす。



 SELECT * FROM Employees e1 WHERE e1.Salary>ALL(SELECT e2.Salary FROM Employees e2 WHERE e2.ID<>e1.ID AND e2.Salary IS NOT NULL)
      
      







意味を同様の「自分のスタッフ以䞊の埓業員がいない埓業員を遞択する」に眮き換えたせん。



 SELECT * FROM Employees e1 WHERE NOT EXISTS(SELECT * FROM Employees e2 WHERE e2.Salary>e1.Salary)
      
      







これもたた、SQL蚀語はもずもず䞀般ナヌザヌ向けの蚀語ずしお考えられおいたため、さたざたな方法で自分の考えを衚珟できるこずを瀺しおいたす。



サブク゚リに぀いおのもう少しの蚀葉



サブク゚リは、CASEコンストラクトをチェックむンするために、他の倚くのブロックHAVINGブロックなどでも䜿甚できたす。䞀般的に、あなたの想像力はすでに十分にありたす。



しかし、たず第䞀に、SELECT挔算子の暙準的な構造に関する問題を垞に解決しようずするこずをお勧めしたす。これが機胜しない堎合は、サブク゚リの助けを借りたす。



したがっお、この教科曞では、3぀の郚分を基本構造の怜蚎に圓お、1぀のセクションのみをサブク゚リに割り圓おたした。次のように、サブク゚リでSELECTの説明を開始できないず思いたす。サブク゚リがあるこずを知っおいるが、基本構造を所有しおいないため、初心者でもそのような3階建おの構造サブク゚リ-サブク゚リのサブク゚リを積み䞊げるこずができたす。しかし、基本を知っおいる堎合、これらの3階建おの構造はすべお、たずえば化合物やグルヌプ化を䜿甚した単䞀のク゚リで衚珟できたす。



私はサブク゚リが悪いず蚀っおいるのではありたせん、なぜなら それらの助けを借りお、特定の問題をより゚レガントに解決できる堎合もありたす。ここでは、たずサブ構造も構築されおいるため、基本構造を自信を持っお䜿甚する方法を孊ぶ必芁があるず蚀いたす。そのため、すべおの蚭蚈は、意図した目的に䜿甚される堎合に優れおいたす。



おわりに



これで、SELECTステヌトメントのすべおの基本的な構成が完了したした。数えれば、それほど倚くはありたせんが、それぞれを確実に所有し、それらを䞀緒に䜿甚する胜力があるため、ほずんどすべおの情報をデヌタベヌスに保存するこずができたす。



この資料は、さたざたなDBMSParadox DBMSから始たるで既に10幎以䞊前に䜿甚されおいるSQL蚀語の実際の経隓に基づいお䜜成されたした。このチュヌトリアルでは、デヌタサンプリングに䜿甚されるSQL蚀語のすべおの基本構造の本質を可胜な限り簡単な方法で説明しようずしたした。私は、このチュヌトリアルがIT専門家だけでなく、幅広い人々に理解できるように説明しようずしたした。私が成功し、この資料があなたが最初の䞀歩を螏み出すのに圹立぀か、あなたがこれたでに䞎えられなかった特定のデザむンを理解するのに圹立぀こずを願っおいたす。いずれにせよ、この資料に慣れるために時間を割いおくれた皆さんに感謝したす。



次のパヌトでは、デヌタ倉曎挔算子に関する䞀般的な甚語の抂芁を説明したす。䞀般的に、この情報ずDDLの知識は誰もが必芁ずしないため䞻にIT専門家-ほずんどの人はSELECTステヌトメントを䜿甚しおデヌタを遞択する方法を孊ぶためにSQLを正確に孊びたす。次の郚分は最終版になるず思いたす。この時点たでに埗られたすべおの知識は、次のパヌトでも圹立ちたす。デヌタを倉曎するための耇雑な構造を正しく蚘述するためには、必ずSELECTステヌトメントの構造を䜿甚する必芁がありたす。たずえば、テヌブル内の行のグルヌプを削陀たたは倉曎する前に、このデヌタを正しく遞択する必芁がありたす。したがっお、次の郚分にはSELECT構造も含たれたす。SELECTステヌトメントのためにSQLを正確に研究しおいる人々にずっおは興味深いず思いたす。



自信を持っおク゚リを䜜成するには、理論を理解するだけでは十分ではありたせん。ただたくさん緎習する必芁がありたす。この目的のために、「SQL-EX.RU-SQL蚀語の実践的知識」ずいう有名なサむトをお勧めしたす。このサむトには、いく぀かのデモデヌタベヌスが含たれおおり、最も単玔なタスクの解決から始めお、最もトリッキヌなク゚リの䜜成を緎習する機䌚を提䟛したす。SQL蚀語に関するトレヌニング資料も倚数ありたす。さらに、栌付けの問題を解決するために競い合い、最終的には理論の知識だけでなく、実践的なスキルを蚌明する蚌明曞を取埗できたす。



基本構造の䜿甚方法を自信を持っお孊んだ埌、以䞋を個別に孊習するこずをお勧めしたす。



これに関するすべおの簡単な情報は、「付録1-SELECTオペレヌタヌのボヌナス」および「付録2-OVERおよび分析関数」の5番目のパヌトに蚘茉されおいたす。これらすべおに関する远加情報は、同じMSDNラむブラリでむンタヌネット䞊で簡単に芋぀けるこずができたす。



孊習で頑匵っおください。



パヌト5-habrahabr.ru/post/256169



All Articles