Join (SQL)

동일 조인

동일 조인(Equi-Join)은 특별한 유형의 비교자 기반의 조인이며, 이것은 조인 구문에서 동등비교만을 사용한다. 다른 비교 연산자(<와 같은)를 사용하는 것은 동일 조인으로서의 조인의 자격을 박탈하는 것이다. 위에서 보여준 쿼리는 이미 동일 조인의 예시가 제시되었다.
SELECT *FROM employee JOIN department
  ON employee.DepartmentID = department.DepartmentID;
우리는 동일 조인을 아래와 같이 쓸 수 있다.
SELECT *FROM employee, departmentWHERE employee.DepartmentID = department.DepartmentID;
만약 동일 조인 내에 있는 컬럼들이 동일한 이름을 가지고 있다면, SQL-92는 USING을 추가함으로써 동일 조인을 표현하기 위한 속기적  개념을 선택적으로 제공한다 :
SELECT *FROM employee INNER JOIN department USING (DepartmentID);
USING 구문은 단순한 설탕구문이지만, 결과 값이 명시적 구문에 의한 결과 값과는 다르다. 특히 USING 목록 속에 언급된 어떤 컬럼들은 조인에서 각 테이블에 한번 등장하기 보다는, 권한이 없는 이름으로 단 한번만 등장할 것이다. 위의 사례에서, 단인 DepartmentID 컬럼이 해당하고, employee.DepartmentID 또는 department.DepartmentID은 해당되지 않는다.
USING 구문은 MS SQL Server와 Sybase에서는 지원하지 않는다.

자가 조인

자가 조인(self-join)은 한 테이블에서 자기 자신에 조인을 시키는 것이다.

MySQL

SELECT DepartmentID, group_concat(LastName) as LastNamesFROM employeeGROUP BY DepartmentID;

Oracle 11g R2

SELECT DepartmentID,
  listagg(LastName, ', ') WITHIN GROUP (ORDER BY LastName) as LastNamesFROM employeeGROUP BY DepartmentID;

CUBRID

SELECT DepartmentID,
  GROUP_CONCAT(LastName ORDER BY LastName SEPARATOR ',') as LastNamesFROM employeeGROUP BY DepartmentID;

PostgreSQL

우선 질의를 하기 전 함수 _group_concat 과 집합 group_concat이 생성되어야 한다.
CREATE OR REPLACE FUNCTION _group_concat(text, text)RETURNS text AS $$SELECT CASEWHEN $2 IS NULL THEN $1WHEN $1 IS NULL THEN $2ELSE $1 operator(pg_catalog.||) ', ' operator(pg_catalog.||) $2END$$ IMMUTABLE LANGUAGE SQL;error// Join SQLCREATE AGGREGATE group_concat (BASETYPE = text,SFUNC = _group_concat,STYPE = text);SELECT DepartmentID, group_concat(LastName) as LastNamesFROM employeeGROUP BY DepartmentID;
9.0 버전에서는:
SELECT DepartmentID, string_agg(LastName, ', ') as LastNamesFROM employeeGROUP BY DepartmentID;

Microsoft T-SQL

Microsoft SQL Server 2005 이전 버전에서, group_concat 함수는 그러한 쿼리를 날리기 전에 사용자 정의 집합 함수로 만들어져야 한다. 아래에 C#으로 만든 예제가 있다.
using System;using System.Collections.Generic;using System.Data.SqlTypes;using System.IO;using Microsoft.SqlServer.Server;[Serializable][SqlUserDefinedAggregate(Format.UserDefined, MaxByteSize=8000)]public struct group_concat : IBinarySerialize{
 private List values;

 public void Init() {
  this.values = new List();
 }

 public void Accumulate(SqlString value) {
  this.values.Add(value.Value);
 }

 public void Merge(strconcat value) {
  this.values.AddRange(value.values.ToArray());
 }

 public SqlString Terminate() {
  return new SqlString(string.Join(", ", this.values.ToArray()));
 }

 public void Read(BinaryReader r) {
  int itemCount = r.ReadInt32();
  this.values = new List(itemCount);
  for (int i = 0; i < itemCount; i++) {
   this.values.Add(r.ReadString());
  }
 }

 public void Write(BinaryWriter w) {
  w.Write(this.values.Count);
  foreach (string s in this.values) {
   w.Write(s);
  }
 }}
그러면 다음과 같은 쿼리를 이용할 수 있다:
SELECT DepartmentID, dbo.group_concat(LastName) as LastNamesFROM employeeGROUP BY DepartmentID;
2005 버전에서는, 이 작업을 FOR XML PATH를 사용하면 된다:
SELECT DepartmentID, STUFF( (SELECT ',' + LastName FROM ( SELECT LastName FROM employee e2 WHERE e1.DepartmentID=e2.DepartmentID OR (e1.DepartmentID IS NULL AND e2.DepartmentID IS NULL) ) t1 ORDER BY LastName FOR XML PATH('') ) ,1,1, '' ) AS LastNamesFROM employee e1GROUP BY DepartmentID

대체

외부 조인의 결과는 또한 INNER JOIN과 조인 조건을 수행하지 않은 주요 테이블 내의 열들의 SELECT 사이에 UNION ALL을 사용함으로써 동일한 결과를 얻을 수 있다. 예제는 다음과 같다.
SELECT employee.LastName, employee.DepartmentID, department.DepartmentNameFROM employeeLEFT OUTER JOIN department ON employee.DepartmentID = department.DepartmentID;
이것은 다음과 같이 쓸 수도 있다.
SELECT employee.LastName, employee.DepartmentID, department.DepartmentNameFROM employeeINNER JOIN department ON employee.DepartmentID = department.DepartmentIDUNION ALLSELECT employee.LastName, employee.DepartmentID, cast(NULL as varchar(20))FROM employeeWHERE NOT EXISTS (
    SELECT * FROM department
             WHERE employee.DepartmentID = department.DepartmentID)