SnowConvert AI - Oracle - Joins

A join is a query that combines rows from two or more tables, views, or materialized views. Oracle Database performs a join whenever multiple tables appear in the FROM clause of the query. (Oracle SQL Language Reference JOINS)

Antijoin

Note

Some parts in the output code are omitted for clarity reasons.

Description

An antijoin returns rows from the left side of the predicate for which there are no corresponding rows on the right side of the predicate. It returns rows that fail to match (NOT IN) the subquery on the right side. Antijoin transformation cannot be done if the subquery is on an OR branch of the WHERE clause. (Oracle SQL Language Reference Anti Join).

No special transformation is performed for this kind of Join since Snowflake supports the same syntax.

Sample Source Patterns

Note

Order by clause added because the result order may vary between Oracle and Snowflake.

Note

Since the result set is too large, Row Limiting Clause was added. You can remove it to retrieve the entire result set.

Note

Check this section to set up the sample database.

Where Not In

Oracle

SELECT e.employee_id, e.first_name, e.last_name FROM hr.employees e
WHERE e.department_id NOT IN

    (SELECT h.department_id FROM hr.departments h WHERE location_id = 1700)

ORDER BY e.last_name
FETCH FIRST 10 ROWS ONLY;
Result
EMPLOYEE_IDFIRST_NAMELAST_NAME
174EllenAbel
166SundarAnde
130MozheAtkinson
105DavidAustin
204HermannBaer
167AmitBanda
172ElizabethBates
192SarahBell
151DavidBernstein
129LauraBissot
Snowflake

SELECT e.employee_id, e.first_name, e.last_name FROM
    hr.employees e
WHERE e.department_id NOT IN
        !!!RESOLVE EWI!!! /*** SSC-EWI-0108 - THE FOLLOWING SUBQUERY MATCHES AT LEAST ONE OF THE PATTERNS CONSIDERED INVALID AND MAY PRODUCE COMPILATION ERRORS ***/!!!
    (SELECT h.department_id FROM
            hr.departments h WHERE location_id = 1700)

ORDER BY e.last_name
    FETCH FIRST 10 ROWS ONLY;
Result
EMPLOYEE_IDFIRST_NAMELAST_NAME
174EllenAbel
166SundarAnde
130MozheAtkinson
105DavidAustin
204HermannBaer
167AmitBanda
172ElizabethBates
192SarahBell
151DavidBernstein
129LauraBissot

Where Not Exists

Oracle

SELECT   d.department_id, d.department_name
FROM     hr.departments d
WHERE    NOT EXISTS

         (SELECT 1 FROM hr.employees E WHERE
         e.department_id = d.department_id)

ORDER BY d.department_id
FETCH FIRST 10 ROWS ONLY;
Result
DEPARTMENT_IDDEPARTMENT_NAME
120Treasury
130Corporate Tax
140Control And Credit
150Shareholder Services
160Benefits
170Manufacturing
180Construction
190Contracting
200Operations
210IT Support
Snowflake

SELECT   d.department_id, d.department_name
FROM
         hr.departments d
WHERE    NOT EXISTS
                  !!!RESOLVE EWI!!! /*** SSC-EWI-0108 - THE FOLLOWING SUBQUERY MATCHES AT LEAST ONE OF THE PATTERNS CONSIDERED INVALID AND MAY PRODUCE COMPILATION ERRORS ***/!!!
         (SELECT 1 FROM
                           hr.employees E WHERE
         e.department_id = d.department_id)

ORDER BY d.department_id
         FETCH FIRST 10 ROWS ONLY;
Result
DEPARTMENT_IDDEPARTMENT_NAME
120Treasury
130Corporate Tax
140Control And Credit
150Shareholder Services
160Benefits
170Manufacturing
180Construction
190Contracting
200Operations
210IT Support

Known issues

1. Results ordering mismatch between languages

The result of the query will have the same content in both database engines but the order might be different if no Order By clause is defined in the query.

  1. SSC-EWI-0108: This subquery matches a pattern considered invalid and may cause compilation errors.

Band Join

Note

Some parts in the output code are omitted for clarity reasons.

Description

A band join is a special type of nonequijoin in which key values in one data set must fall within the specified range (“band”) of the second data set. The same table can serve as both the first and second data sets. (Oracle SQL Language Reference BandJoin)

In this section, we will see how a band join is executed in Snowflake and the execution plan is very similar to the improved version of Oracle.

Sample Source Patterns

Note

Order by clause added because the result order may vary between Oracle and Snowflake.

Note

Since the result set is too large, Row Limiting Clause was added. You can remove it to retrieve the entire result set.

Note

Check this section to set up the sample database.

Warning

If you migrate this code without the create tables, the converter won’t be able to load semantic information of the columns and a warning will appear on the arithmetic operations.

Basic Band Join case

Oracle

SELECT  e1.last_name ||
        ' has salary between 100 less and 100 more than ' ||
        e2.last_name AS "SALARY COMPARISON"
FROM    employees e1,
        employees e2
WHERE   e1.salary
BETWEEN e2.salary - 100
AND     e2.salary + 100
ORDER BY "SALARY COMPARISON"
FETCH FIRST 10 ROWS ONLY
Result
SALARY COMPARISON
Abel has salary between 100 less and 100 more than Abel
Abel has salary between 100 less and 100 more than Cambrault
Abel has salary between 100 less and 100 more than Raphaely
Ande has salary between 100 less and 100 more than Ande
Ande has salary between 100 less and 100 more than Mavris
Ande has salary between 100 less and 100 more than Vollman
Atkinson has salary between 100 less and 100 more than Atkinson
Atkinson has salary between 100 less and 100 more than Baida
Atkinson has salary between 100 less and 100 more than Gates
Atkinson has salary between 100 less and 100 more than Geoni
Snowflake

SELECT
                NVL(  e1.last_name :: STRING, '') ||
                ' has salary between 100 less and 100 more than ' || NVL(
                e2.last_name :: STRING, '') AS "SALARY COMPARISON"
FROM
                employees e1,
                employees e2
WHERE   e1.salary
BETWEEN
        !!!RESOLVE EWI!!! /*** SSC-EWI-OR0036 - TYPES RESOLUTION ISSUES, ARITHMETIC OPERATION '-' MAY NOT BEHAVE CORRECTLY BETWEEN unknown AND Number ***/!!! e2.salary - 100
AND
        !!!RESOLVE EWI!!! /*** SSC-EWI-OR0036 - TYPES RESOLUTION ISSUES, ARITHMETIC OPERATION '+' MAY NOT BEHAVE CORRECTLY BETWEEN unknown AND Number ***/!!!     e2.salary + 100
ORDER BY "SALARY COMPARISON"
FETCH FIRST 10 ROWS ONLY;
Result
SALARY COMPARISON
Abel has salary between 100 less and 100 more than Abel
Abel has salary between 100 less and 100 more than Cambrault
Abel has salary between 100 less and 100 more than Raphaely
Ande has salary between 100 less and 100 more than Ande
Ande has salary between 100 less and 100 more than Mavris
Ande has salary between 100 less and 100 more than Vollman
Atkinson has salary between 100 less and 100 more than Atkinson
Atkinson has salary between 100 less and 100 more than Baida
Atkinson has salary between 100 less and 100 more than Gates
Atkinson has salary between 100 less and 100 more than Geoni

Warning

Migrating some SELECT statements without the corresponding tables could generate the SSC-EWI-OR0036: Types resolution issues. To avoid this warning, include the CREATE TABLE inside the file.

The results are the same making the BAND JOIN functional equivalent.

Execution plan

As extra information, the special thing about the band joins is the execution plan.

The following image shows the enhanced execution plan (implemented since Oracle 12c) for the test query:

And in the following image, we will see the execution plan in Snowflake:

Note

The execution plan in Snowflake is very similar to Oracle’s optimized version. The final duration and performance of the query will be affected by many other factors and are completely dependent on each DBMS internal functionality.

Known Issues

1. Results ordering mismatch between languages

The query result will have the same content in both database engines but the order might be different if no Order By clause is defined in the query.

  • SSC-EWI-OR0036: Types resolution issues, the arithmetic operation may not behave correctly between string and date.

Cartesian Products

Note

Some parts in the output code are omitted for clarity reasons.

If two tables in a join query have no join condition, then Oracle Database returns their Cartesian product. Oracle combines each row of one table with each row of the other. (Oracle SQL Reference Cartesian Products Subsection)

Oracle and Snowflake are also compatible with the ANSI Cross Join syntax that has the same behavior of a cartesian product.

No special transformation is performed for this kind of Join since Snowflake supports the same syntax.

Sample Source Patterns

Note

Order by clause was added because the result order may vary between Oracle and Snowflake.

Note

Since the result set is too large, Row Limiting Clause was added. You can remove it to retrieve the entire result set.

Note

Check this section to set up the sample database.

Implicit Syntax

Oracle

-- Resulting rows
SELECT * FROM hr.employees, hr.departments
ORDER BY first_name
FETCH FIRST 5 ROWS ONLY;

-- Resulting total rows
SELECT COUNT(*) FROM hr.employees, hr.departments;
Result 1
EMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTMANAGER_IDDEPARTMENT_IDDEPARTMENT_IDDEPARTMENT_NAMEMANAGER_IDLOCATION_ID
121AdamFrippAFRIPP650.123.22342005-04-10 00:00:00.000ST_MAN82001005010Administration2001700
121AdamFrippAFRIPP650.123.22342005-04-10 00:00:00.000ST_MAN82001005050Shipping1211500
121AdamFrippAFRIPP650.123.22342005-04-10 00:00:00.000ST_MAN82001005040Human Resources2032400
121AdamFrippAFRIPP650.123.22342005-04-10 00:00:00.000ST_MAN82001005030Purchasing1141700
121AdamFrippAFRIPP650.123.22342005-04-10 00:00:00.000ST_MAN82001005020Marketing2011800
Result 2
COUNT(*)
2889
Snowflake

-- Resulting rows
SELECT * FROM
hr.employees,
hr.departments
ORDER BY first_name
FETCH FIRST 5 ROWS ONLY;

-- Resulting total rows
SELECT COUNT(*) FROM
hr.employees,
hr.departments;
Result 1
EMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTMANAGER_IDDEPARTMENT_IDDEPARTMENT_IDDEPARTMENT_NAMEMANAGER_IDLOCATION_ID
121AdamFrippAFRIPP650.123.22342005-04-10ST_MAN8200.001005040Human Resources2032400
121AdamFrippAFRIPP650.123.22342005-04-10ST_MAN8200.001005020Marketing2011800
121AdamFrippAFRIPP650.123.22342005-04-10ST_MAN8200.001005010Administration2001700
121AdamFrippAFRIPP650.123.22342005-04-10ST_MAN8200.001005050Shipping1211500
121AdamFrippAFRIPP650.123.22342005-04-10ST_MAN8200.001005030Purchasing1141700
Result 2
COUNT(*)
2889

Cross Join Syntax

Oracle

-- Resulting rows
SELECT * FROM hr.employees CROSS join hr.departments
ORDER BY first_name
FETCH FIRST 5 ROWS ONLY;

-- Resulting total rows
SELECT COUNT(*) FROM hr.employees CROSS join hr.departments;
Result 1
EMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTMANAGER_IDDEPARTMENT_IDDEPARTMENT_IDDEPARTMENT_NAMEMANAGER_IDLOCATION_ID
121AdamFrippAFRIPP650.123.22342005-04-10 00:00:00.000ST_MAN82001005010Administration2001700
121AdamFrippAFRIPP650.123.22342005-04-10 00:00:00.000ST_MAN82001005050Shipping1211500
121AdamFrippAFRIPP650.123.22342005-04-10 00:00:00.000ST_MAN82001005040Human Resources2032400
121AdamFrippAFRIPP650.123.22342005-04-10 00:00:00.000ST_MAN82001005030Purchasing1141700
121AdamFrippAFRIPP650.123.22342005-04-10 00:00:00.000ST_MAN82001005020Marketing2011800
Result 2
COUNT(*)
2889
Snowflake
:force:
-- Resulting rows
SELECT * FROM
hr.employees
CROSS join hr.departments
ORDER BY first_name
FETCH FIRST 5 ROWS ONLY;

-- Resulting total rows
SELECT COUNT(*) FROM
hr.employees
CROSS join hr.departments;

Known issues

1. Results ordering mismatch between languages

The result of the query will have the same content in both database engines but the order might be different if no Order By clause is defined in the query.

No related EWIs.

Equijoin

Note

Some parts in the output code are omitted for clarity reasons.

Description

An equijoin is an implicit form of the join with a join condition containing an equality operator. For more information, see the Oracle Equijoin documentation.

No special transformation is performed for this kind of Join since Snowflake supports the same syntax.

Sample Source Patterns

Note

Order by clause added because the result order may vary between Oracle and Snowflake.

Note

Since the result set is too large, the Row Limiting Clause was added. You can remove it to retrieve the entire result set.

Note

Check this section to set up the sample database.

Basic Equijoin case

Oracle
 SELECT last_name, job_id, hr.departments.department_id, department_name
FROM hr.employees, hr.departments
WHERE hr.employees.department_id = hr.departments.department_id
ORDER BY last_name
FETCH FIRST 5 ROWS ONLY;
Result
LAST_NAMEJOB_IDDEPARTMENT_IDDEPARTMENT_NAME
AbelSA_REP80Sales
AndeSA_REP80Sales
AtkinsonST_CLERK50Shipping
AustinIT_PROG60IT
BaerPR_REP70Public Relations
Snowflake
 SELECT last_name, job_id, hr.departments.department_id, department_name
FROM
hr.employees,
hr.departments
WHERE hr.employees.department_id = hr.departments.department_id
ORDER BY last_name
FETCH FIRST 5 ROWS ONLY;
Result
LAST_NAMEJOB_IDDEPARTMENT_IDDEPARTMENT_NAME
AbelSA_REP80Sales
AndeSA_REP80Sales
AtkinsonST_CLERK50Shipping
AustinIT_PROG60IT
BaerPR_REP70Public Relations

Known issues

1. Results ordering mismatch between languages

The result of the query will have the same content in both database engines but the order might be different if no Order By clause is defined in the query.

No related EWIs.

Inner Join

Note

Some parts in the output code are omitted for clarity reasons.

Description

An inner join (sometimes called a simple join) is a join of two or more tables that returns only those rows that satisfy the join condition. (Oracle SQL Reference Inner Join Subsection).

{ [ INNER ] JOIN table_reference
 { ON condition
 | USING (column [, column ]...)
 }
| { CROSS
 | NATURAL [ INNER ]
 }
 JOIN table_reference
}

Sample Source Patterns

Note

Order by clause added because the result order may vary between Oracle and Snowflake.

Note

Since the result set is too large, Row Limiting Clause was added. You can remove this clause to retrieve the entire result set.

Note

Check this section to set up the sample database.

Basic Inner Join

In the Inner Join clause “INNER” is an optional keyword, the following queries have two selects that retrieve the same data set.

Oracle
 SELECT
    *
FROM
    hr.employees
INNER JOIN hr.departments ON
    hr.departments.department_id = hr.employees.department_id
ORDER BY employee_id
FETCH NEXT 10 ROWS ONLY;

SELECT
    *
FROM
    hr.employees
JOIN hr.departments ON
    hr.departments.department_id = hr.employees.department_id
ORDER BY employee_id
FETCH NEXT 10 ROWS ONLY;
Result
EMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTMANAGER_IDDEPARTMENT_IDDEPARTMENT_IDDEPARTMENT_NAMEMANAGER_IDLOCATION_ID
100StevenKingSKING515.123.45672003-06-17 00:00:00.000AD_PRES240009090Executive1001700
101NeenaKochharNKOCHHAR515.123.45682005-09-21 00:00:00.000AD_VP170001009090Executive1001700
102LexDe HaanLDEHAAN515.123.45692001-01-13 00:00:00.000AD_VP170001009090Executive1001700
103AlexanderHunoldAHUNOLD590.423.45672006-01-03 00:00:00.000IT_PROG90001026060IT1031400
104BruceErnstBERNST590.423.45682007-05-21 00:00:00.000IT_PROG60001036060IT1031400
105DavidAustinDAUSTIN590.423.45692005-06-25 00:00:00.000IT_PROG48001036060IT1031400
106ValliPataballaVPATABAL590.423.45602006-02-05 00:00:00.000IT_PROG48001036060IT1031400
107DianaLorentzDLORENTZ590.423.55672007-02-07 00:00:00.000IT_PROG42001036060IT1031400
108NancyGreenbergNGREENBE515.124.45692002-08-17 00:00:00.000FI_MGR12008101100100Finance1081700
109DanielFavietDFAVIET515.124.41692002-08-16 00:00:00.000FI_ACCOUNT9000108100100Finance1081700
Snowflake
 SELECT
    *
FROM
hr.employees
INNER JOIN
    hr.departments
    ON
    hr.departments.department_id = hr.employees.department_id
ORDER BY employee_id
FETCH NEXT 10 ROWS ONLY;

SELECT
    *
FROM
    hr.employees
JOIN
    hr.departments
    ON
    hr.departments.department_id = hr.employees.department_id
ORDER BY employee_id
FETCH NEXT 10 ROWS ONLY;
Result
EMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTMANAGER_IDDEPARTMENT_IDDEPARTMENT_IDDEPARTMENT_NAMEMANAGER_IDLOCATION_ID
100StevenKingSKING515.123.45672003-06-17AD_PRES24000.009090Executive1001700
101NeenaKochharNKOCHHAR515.123.45682005-09-21AD_VP17000.001009090Executive1001700
102LexDe HaanLDEHAAN515.123.45692001-01-13AD_VP17000.001009090Executive1001700
103AlexanderHunoldAHUNOLD590.423.45672006-01-03IT_PROG9000.001026060IT1031400
104BruceErnstBERNST590.423.45682007-05-21IT_PROG6000.001036060IT1031400
105DavidAustinDAUSTIN590.423.45692005-06-25IT_PROG4800.001036060IT1031400
106ValliPataballaVPATABAL590.423.45602006-02-05IT_PROG4800.001036060IT1031400
107DianaLorentzDLORENTZ590.423.55672007-02-07IT_PROG4200.001036060IT1031400
108NancyGreenbergNGREENBE515.124.45692002-08-17FI_MGR12008.00101100100Finance1081700
109DanielFavietDFAVIET515.124.41692002-08-16FI_ACCOUNT9000.00108100100Finance1081700

Inner Join with using clause

Oracle

SELECT
    *
FROM
    hr.employees
INNER JOIN hr.departments
    USING(department_id)
ORDER BY employee_id
FETCH NEXT 10 ROWS ONLY;
Result
DEPARTMENT_IDEMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTMANAGER_IDDEPARTMENT_NAMEMANAGER_IDLOCATION_ID
90100StevenKingSKING515.123.45672003-06-17 00:00:00.000AD_PRES24000Executive1001700
90101NeenaKochharNKOCHHAR515.123.45682005-09-21 00:00:00.000AD_VP17000100Executive1001700
90102LexDe HaanLDEHAAN515.123.45692001-01-13 00:00:00.000AD_VP17000100Executive1001700
60103AlexanderHunoldAHUNOLD590.423.45672006-01-03 00:00:00.000IT_PROG9000102IT1031400
60104BruceErnstBERNST590.423.45682007-05-21 00:00:00.000IT_PROG6000103IT1031400
60105DavidAustinDAUSTIN590.423.45692005-06-25 00:00:00.000IT_PROG4800103IT1031400
60106ValliPataballaVPATABAL590.423.45602006-02-05 00:00:00.000IT_PROG4800103IT1031400
60107DianaLorentzDLORENTZ590.423.55672007-02-07 00:00:00.000IT_PROG4200103IT1031400
100108NancyGreenbergNGREENBE515.124.45692002-08-17 00:00:00.000FI_MGR12008101Finance1081700
100109DanielFavietDFAVIET515.124.41692002-08-16 00:00:00.000FI_ACCOUNT9000108Finance1081700
Snowflake

SELECT
    *
FROM
hr.employees
INNER JOIN
    hr.departments
    USING(department_id)
ORDER BY employee_id
FETCH NEXT 10 ROWS ONLY;
Result
DEPARTMENT_IDEMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTMANAGER_IDDEPARTMENT_NAMEMANAGER_IDLOCATION_ID
90100StevenKingSKING515.123.45672003-06-17AD_PRES24000.00Executive1001700
90101NeenaKochharNKOCHHAR515.123.45682005-09-21AD_VP17000.00100Executive1001700
90102LexDe HaanLDEHAAN515.123.45692001-01-13AD_VP17000.00100Executive1001700
60103AlexanderHunoldAHUNOLD590.423.45672006-01-03IT_PROG9000.00102IT1031400
60104BruceErnstBERNST590.423.45682007-05-21IT_PROG6000.00103IT1031400
60105DavidAustinDAUSTIN590.423.45692005-06-25IT_PROG4800.00103IT1031400
60106ValliPataballaVPATABAL590.423.45602006-02-05IT_PROG4800.00103IT1031400
60107DianaLorentzDLORENTZ590.423.55672007-02-07IT_PROG4200.00103IT1031400
100108NancyGreenbergNGREENBE515.124.45692002-08-17FI_MGR12008.00101Finance1081700
100109DanielFavietDFAVIET515.124.41692002-08-16FI_ACCOUNT9000.00108Finance1081700

Cross Inner Join

Oracle

SELECT
    *
FROM
    hr.employees
CROSS JOIN hr.departments
ORDER BY department_name, employee_id
FETCH NEXT 10 ROWS ONLY;
Result
EMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTMANAGER_IDDEPARTMENT_IDDEPARTMENT_IDDEPARTMENT_NAMEMANAGER_IDLOCATION_ID
100StevenKingSKING515.123.45672003-06-17 00:00:00.000AD_PRES2400090110Accounting2051700
101NeenaKochharNKOCHHAR515.123.45682005-09-21 00:00:00.000AD_VP1700010090110Accounting2051700
102LexDe HaanLDEHAAN515.123.45692001-01-13 00:00:00.000AD_VP1700010090110Accounting2051700
103AlexanderHunoldAHUNOLD590.423.45672006-01-03 00:00:00.000IT_PROG900010260110Accounting2051700
104BruceErnstBERNST590.423.45682007-05-21 00:00:00.000IT_PROG600010360110Accounting2051700
105DavidAustinDAUSTIN590.423.45692005-06-25 00:00:00.000IT_PROG480010360110Accounting2051700
106ValliPataballaVPATABAL590.423.45602006-02-05 00:00:00.000IT_PROG480010360110Accounting2051700
107DianaLorentzDLORENTZ590.423.55672007-02-07 00:00:00.000IT_PROG420010360110Accounting2051700
108NancyGreenbergNGREENBE515.124.45692002-08-17 00:00:00.000FI_MGR12008101100110Accounting2051700
109DanielFavietDFAVIET515.124.41692002-08-16 00:00:00.000FI_ACCOUNT9000108100110Accounting2051700
Snowflake
 SELECT
    *
FROM
hr.employees
CROSS JOIN hr.departments
ORDER BY department_name, employee_id
FETCH NEXT 10 ROWS ONLY;
Result
EMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTMANAGER_IDDEPARTMENT_IDDEPARTMENT_IDDEPARTMENT_NAMEMANAGER_IDLOCATION_ID
100StevenKingSKING515.123.45672003-06-17AD_PRES24000.0090110Accounting2051700
101NeenaKochharNKOCHHAR515.123.45682005-09-21AD_VP17000.0010090110Accounting2051700
102LexDe HaanLDEHAAN515.123.45692001-01-13AD_VP17000.0010090110Accounting2051700
103AlexanderHunoldAHUNOLD590.423.45672006-01-03IT_PROG9000.0010260110Accounting2051700
104BruceErnstBERNST590.423.45682007-05-21IT_PROG6000.0010360110Accounting2051700
105DavidAustinDAUSTIN590.423.45692005-06-25IT_PROG4800.0010360110Accounting2051700
106ValliPataballaVPATABAL590.423.45602006-02-05IT_PROG4800.0010360110Accounting2051700
107DianaLorentzDLORENTZ590.423.55672007-02-07IT_PROG4200.0010360110Accounting2051700
108NancyGreenbergNGREENBE515.124.45692002-08-17FI_MGR12008.00101100110Accounting2051700
109DanielFavietDFAVIET515.124.41692002-08-16FI_ACCOUNT9000.00108100110Accounting2051700

Natural Inner Join

Oracle

SELECT
    *
FROM
    hr.employees
NATURAL JOIN hr.departments
ORDER BY employee_id
FETCH NEXT 10 ROWS ONLY;
Result
MANAGER_IDDEPARTMENT_IDEMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTDEPARTMENT_NAMELOCATION_ID
10090101NeenaKochharNKOCHHAR515.123.45682005-09-21 00:00:00.000AD_VP17000Executive1700
10090102LexDe HaanLDEHAAN515.123.45692001-01-13 00:00:00.000AD_VP17000Executive1700
10360104BruceErnstBERNST590.423.45682007-05-21 00:00:00.000IT_PROG6000IT1400
10360105DavidAustinDAUSTIN590.423.45692005-06-25 00:00:00.000IT_PROG4800IT1400
10360106ValliPataballaVPATABAL590.423.45602006-02-05 00:00:00.000IT_PROG4800IT1400
10360107DianaLorentzDLORENTZ590.423.55672007-02-07 00:00:00.000IT_PROG4200IT1400
108100109DanielFavietDFAVIET515.124.41692002-08-16 00:00:00.000FI_ACCOUNT9000Finance1700
108100110JohnChenJCHEN515.124.42692005-09-28 00:00:00.000FI_ACCOUNT8200Finance1700
108100111IsmaelSciarraISCIARRA515.124.43692005-09-30 00:00:00.000FI_ACCOUNT7700Finance1700
108100112Jose ManuelUrmanJMURMAN515.124.44692006-03-07 00:00:00.000FI_ACCOUNT7800Finance1700
Snowflake

SELECT
    *
FROM
hr.employees
NATURAL JOIN
    hr.departments
ORDER BY employee_id
FETCH NEXT 10 ROWS ONLY;
Result
MANAGER_IDDEPARTMENT_IDEMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTDEPARTMENT_NAMELOCATION_ID
10090101NeenaKochharNKOCHHAR515.123.45682005-09-21AD_VP17000.00Executive1700
10090102LexDe HaanLDEHAAN515.123.45692001-01-13AD_VP17000.00Executive1700
10360104BruceErnstBERNST590.423.45682007-05-21IT_PROG6000.00IT1400
10360105DavidAustinDAUSTIN590.423.45692005-06-25IT_PROG4800.00IT1400
10360106ValliPataballaVPATABAL590.423.45602006-02-05IT_PROG4800.00IT1400
10360107DianaLorentzDLORENTZ590.423.55672007-02-07IT_PROG4200.00IT1400
108100109DanielFavietDFAVIET515.124.41692002-08-16FI_ACCOUNT9000.00Finance1700
108100110JohnChenJCHEN515.124.42692005-09-28FI_ACCOUNT8200.00Finance1700
108100111IsmaelSciarraISCIARRA515.124.43692005-09-30FI_ACCOUNT7700.00Finance1700
108100112Jose ManuelUrmanJMURMAN515.124.44692006-03-07FI_ACCOUNT7800.00Finance1700

Cross Natural Join

Oracle

SELECT
    *
FROM
    hr.employees
CROSS NATURAL JOIN hr.departments
ORDER BY employee_id
FETCH NEXT 10 ROWS ONLY;
Result
MANAGER_IDDEPARTMENT_IDEMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTDEPARTMENT_NAMELOCATION_ID
10090101NeenaKochharNKOCHHAR515.123.45682005-09-21 00:00:00.000AD_VP17000Executive1700
10090102LexDe HaanLDEHAAN515.123.45692001-01-13 00:00:00.000AD_VP17000Executive1700
10360104BruceErnstBERNST590.423.45682007-05-21 00:00:00.000IT_PROG6000IT1400
10360105DavidAustinDAUSTIN590.423.45692005-06-25 00:00:00.000IT_PROG4800IT1400
10360106ValliPataballaVPATABAL590.423.45602006-02-05 00:00:00.000IT_PROG4800IT1400
10360107DianaLorentzDLORENTZ590.423.55672007-02-07 00:00:00.000IT_PROG4200IT1400
108100109DanielFavietDFAVIET515.124.41692002-08-16 00:00:00.000FI_ACCOUNT9000Finance1700
108100110JohnChenJCHEN515.124.42692005-09-28 00:00:00.000FI_ACCOUNT8200Finance1700
108100111IsmaelSciarraISCIARRA515.124.43692005-09-30 00:00:00.000FI_ACCOUNT7700Finance1700
108100112Jose ManuelUrmanJMURMAN515.124.44692006-03-07 00:00:00.000FI_ACCOUNT7800Finance1700
Snowflake

SELECT
    *
FROM
    hr.employees
    NATURAL JOIN
        hr.departments
ORDER BY employee_id
FETCH NEXT 10 ROWS ONLY;
Result
MANAGER_IDDEPARTMENT_IDEMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTDEPARTMENT_NAMELOCATION_ID
10090101NeenaKochharNKOCHHAR515.123.45682005-09-21AD_VP17000.00Executive1700
10090102LexDe HaanLDEHAAN515.123.45692001-01-13AD_VP17000.00Executive1700
10360104BruceErnstBERNST590.423.45682007-05-21IT_PROG6000.00IT1400
10360105DavidAustinDAUSTIN590.423.45692005-06-25IT_PROG4800.00IT1400
10360106ValliPataballaVPATABAL590.423.45602006-02-05IT_PROG4800.00IT1400
10360107DianaLorentzDLORENTZ590.423.55672007-02-07IT_PROG4200.00IT1400
108100109DanielFavietDFAVIET515.124.41692002-08-16FI_ACCOUNT9000.00Finance1700
108100110JohnChenJCHEN515.124.42692005-09-28FI_ACCOUNT8200.00Finance1700
108100111IsmaelSciarraISCIARRA515.124.43692005-09-30FI_ACCOUNT7700.00Finance1700
108100112Jose ManuelUrmanJMURMAN515.124.44692006-03-07FI_ACCOUNT7800.00Finance1700

Natural Cross Join

Oracle

SELECT
    *
FROM
    hr.employees
NATURAL CROSS JOIN hr.departments
ORDER BY employee_id
FETCH NEXT 10 ROWS ONLY;
Result
EMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTMANAGER_IDDEPARTMENT_IDDEPARTMENT_IDDEPARTMENT_NAMEMANAGER_IDLOCATION_ID
100StevenKingSKING515.123.45672003-06-17 00:00:00.000AD_PRES240009010Administration2001700
100StevenKingSKING515.123.45672003-06-17 00:00:00.000AD_PRES2400090100Finance1081700
100StevenKingSKING515.123.45672003-06-17 00:00:00.000AD_PRES240009090Executive1001700
100StevenKingSKING515.123.45672003-06-17 00:00:00.000AD_PRES240009080Sales1452500
100StevenKingSKING515.123.45672003-06-17 00:00:00.000AD_PRES240009070Public Relations2042700
100StevenKingSKING515.123.45672003-06-17 00:00:00.000AD_PRES240009060IT1031400
100StevenKingSKING515.123.45672003-06-17 00:00:00.000AD_PRES240009050Shipping1211500
100StevenKingSKING515.123.45672003-06-17 00:00:00.000AD_PRES240009040Human Resources2032400
100StevenKingSKING515.123.45672003-06-17 00:00:00.000AD_PRES240009030Purchasing1141700
100StevenKingSKING515.123.45672003-06-17 00:00:00.000AD_PRES240009020Marketing2011800
Snowflake

SELECT
    *
FROM
    hr.employees
    CROSS JOIN hr.departments
ORDER BY employee_id
FETCH NEXT 10 ROWS ONLY;
Result
EMPLOYEE_IDFIRST_NAMELAST_NAMEEMAILPHONE_NUMBERHIRE_DATEJOB_IDSALARYCOMMISSION_PCTMANAGER_IDDEPARTMENT_IDDEPARTMENT_IDDEPARTMENT_NAMEMANAGER_IDLOCATION_ID
100StevenKingSKING515.123.45672003-06-17AD_PRES24000.009080Sales1452500
100StevenKingSKING515.123.45672003-06-17AD_PRES24000.009020Marketing2011800
100StevenKingSKING515.123.45672003-06-17AD_PRES24000.009060IT1031400
100StevenKingSKING515.123.45672003-06-17AD_PRES24000.009070Public Relations2042700
100StevenKingSKING515.123.45672003-06-17AD_PRES24000.009090Executive1001700
100StevenKingSKING515.123.45672003-06-17AD_PRES24000.009030Purchasing1141700
100StevenKingSKING515.123.45672003-06-17AD_PRES24000.009010Administration2001700
100StevenKingSKING515.123.45672003-06-17AD_PRES24000.0090100Finance1081700
100StevenKingSKING515.123.45672003-06-17AD_PRES24000.009050Shipping1211500
100StevenKingSKING515.123.45672003-06-17AD_PRES24000.009040Human Resources2032400

Known issues

1. Results ordering mismatch between languages

The result of the query will have the same content in both database engines but the order might be different if no Order By clause is defined in the query.

No related EWIs.

Outer Join

Note

Some parts in the output code are omitted for clarity reasons.

Description

An outer join extends the result of a simple join. An outer join returns all rows that satisfy the join condition and returns some or all those rows from one table for which no rows from the other satisfy the join condition. (Oracle SQL Language Reference Outer Joins Subsection).

Oracle ANSI syntax


[ query_partition_clause ] [ NATURAL ]
outer_join_type JOIN table_reference
 [ query_partition_clause ]
 [ ON condition
 | USING ( column [, column ]...)
 ]

outer_join_type
{ FULL | LEFT | RIGHT } [ OUTER ]

Oracle also supports the (+) operator that can be used to do outer joins. This operator is added to a column expression in the WHERE clause.


column_expression (+)

Snowflake ANSI syntax

Snowflake also supports the ANSI syntax for OUTER JOINS, just like Oracle. However, the behavior when using the (+) operator might be different depending on the usage. For more information, see the Snowflake JOIN documentation.

The Snowflake grammar is one of the following:


SELECT ...
FROM <object_ref1> [
                     {
                       INNER
                       | { LEFT | RIGHT | FULL } [ OUTER ]
                     }
                   ]
                   JOIN <object_ref2>
  [ ON <condition> ]
[ ... ]

SELECT *
FROM <object_ref1> [
                     {
                       INNER
                       | { LEFT | RIGHT | FULL } [ OUTER ]
                     }
                   ]
                   JOIN <object_ref2>
  [ USING( <column_list> ) ]
[ ... ]

SELECT ...
FROM <object_ref1> [
                     {
                       | NATURAL [ { LEFT | RIGHT | FULL } [ OUTER ] ]
                       | CROSS
                     }
                   ]
                   JOIN <object_ref2>
[ ... ]

Sample Source Patterns

Note

Order by clause added because the result order may vary between Oracle and Snowflake.

Note

Since the result set is too large, Row Limiting Clause was added. You can remove it to retrieve the entire result set.

Note

Check this section to set up the sample database.

Note

For the following examples, these inserts and alter statements were executed to distinguish better the result for each kind of JOIN:


INSERT INTO hr.regions VALUES (5, 'Oceania');
ALTER TABLE hr.countries DROP CONSTRAINT countr_reg_fk;
INSERT INTO hr.countries VALUES ('--', 'Unknown Country', 0);

1. ANSI syntax

Snowflake fully supports the ANSI syntax for SQL JOINS. The behavior is the same for both database engines.

Left Outer Join On

Oracle

SELECT * FROM
hr.countries c
LEFT OUTER JOIN hr.regions r ON c.region_id = r.region_id
ORDER BY country_id
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_IDREGION_NAME
Unknown Country0
ARArgentina22Americas
AUAustralia33Asia
BEBelgium11Europe
BRBrazil22Americas
CACanada22Americas
CHSwitzerland11Europe
CNChina33Asia
DEGermany11Europe
DKDenmark11Europe
Snowflake

SELECT * FROM
hr.countries c
LEFT OUTER JOIN
hr.regions r ON c.region_id = r.region_id
ORDER BY country_id
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_IDREGION_NAME
Unknown Country0.0000000000000000000
ARArgentina2.00000000000000000002.0000000000000000000Americas
AUAustralia3.00000000000000000003.0000000000000000000Asia
BEBelgium1.00000000000000000001.0000000000000000000Europe
BRBrazil2.00000000000000000002.0000000000000000000Americas
CACanada2.00000000000000000002.0000000000000000000Americas
CHSwitzerland1.00000000000000000001.0000000000000000000Europe
CNChina3.00000000000000000003.0000000000000000000Asia
DEGermany1.00000000000000000001.0000000000000000000Europe
DKDenmark1.00000000000000000001.0000000000000000000Europe

Right Outer Join On

Oracle

SELECT * FROM
hr.countries c
RIGHT OUTER JOIN hr.regions r ON c.region_id = r.region_id
ORDER BY country_id DESC
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_IDREGION_NAME
5Oceania
ZWZimbabwe44Middle East and Africa
ZMZambia44Middle East and Africa
USUnited States of America22Americas
UKUnited Kingdom11Europe
SGSingapore33Asia
NLNetherlands11Europe
NGNigeria44Middle East and Africa
MXMexico22Americas
MLMalaysia33Asia
Snowflake

SELECT * FROM
hr.countries c
RIGHT OUTER JOIN
hr.regions r ON c.region_id = r.region_id
ORDER BY country_id DESC
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_IDREGION_NAME
5.0000000000000000000Oceania
ZWZimbabwe4.00000000000000000004.0000000000000000000Middle East and Africa
ZMZambia4.00000000000000000004.0000000000000000000Middle East and Africa
USUnited States of America2.00000000000000000002.0000000000000000000Americas
UKUnited Kingdom1.00000000000000000001.0000000000000000000Europe
SGSingapore3.00000000000000000003.0000000000000000000Asia
NLNetherlands1.00000000000000000001.0000000000000000000Europe
NGNigeria4.00000000000000000004.0000000000000000000Middle East and Africa
MXMexico2.00000000000000000002.0000000000000000000Americas
MLMalaysia3.00000000000000000003.0000000000000000000Asia

Full Outer Join On

Oracle

SELECT * FROM
hr.countries c
FULL OUTER JOIN hr.regions r ON c.region_id = r.region_id
ORDER BY r.region_name DESC, c.country_id
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_IDREGION_NAME
Unknown Country0
5Oceania
EGEgypt44Middle East and Africa
ILIsrael44Middle East and Africa
KWKuwait44Middle East and Africa
NGNigeria44Middle East and Africa
ZMZambia44Middle East and Africa
ZWZimbabwe44Middle East and Africa
BEBelgium11Europe
CHSwitzerland11Europe
Snowflake

SELECT * FROM
hr.countries c
FULL OUTER JOIN
hr.regions r ON c.region_id = r.region_id
ORDER BY r.region_name DESC, c.country_id
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_IDREGION_NAME
Unknown Country0.0000000000000000000
5.0000000000000000000Oceania
EGEgypt4.00000000000000000004.0000000000000000000Middle East and Africa
ILIsrael4.00000000000000000004.0000000000000000000Middle East and Africa
KWKuwait4.00000000000000000004.0000000000000000000Middle East and Africa
NGNigeria4.00000000000000000004.0000000000000000000Middle East and Africa
ZMZambia4.00000000000000000004.0000000000000000000Middle East and Africa
ZWZimbabwe4.00000000000000000004.0000000000000000000Middle East and Africa
BEBelgium1.00000000000000000001.0000000000000000000Europe
CHSwitzerland1.00000000000000000001.0000000000000000000Europe

2. Natural Outer Join

Both Oracle and Snowflake support the Natural Outer Join and they behave the same.

A NATURAL JOIN is identical to an explicit JOIN on the common columns of the two tables, except that the common columns are included only once in the output. (A natural join assumes that columns with the same name, but in different tables, contain corresponding data.)(Snowflake SQL Language Reference JOIN)

Natural Left Outer Join

Oracle

SELECT * FROM
hr.countries c
NATURAL LEFT OUTER JOIN hr.regions r
ORDER BY country_id
FETCH FIRST 10 ROWS ONLY;
Result
REGION_IDCOUNTRY_IDCOUNTRY_NAMEREGION_NAME
0Unknown Country
2ARArgentinaAmericas
3AUAustraliaAsia
1BEBelgiumEurope
2BRBrazilAmericas
2CACanadaAmericas
1CHSwitzerlandEurope
3CNChinaAsia
1DEGermanyEurope
1DKDenmarkEurope
Snowflake

SELECT * FROM
hr.countries c
NATURAL LEFT OUTER JOIN
hr.regions r
ORDER BY country_id
FETCH FIRST 10 ROWS ONLY;
Result
REGION_IDCOUNTRY_IDCOUNTRY_NAMEREGION_NAME
0.0000000000000000000Unknown Country
2.0000000000000000000ARArgentinaAmericas
3.0000000000000000000AUAustraliaAsia
1.0000000000000000000BEBelgiumEurope
2.0000000000000000000BRBrazilAmericas
2.0000000000000000000CACanadaAmericas
1.0000000000000000000CHSwitzerlandEurope
3.0000000000000000000CNChinaAsia
1.0000000000000000000DEGermanyEurope
1.0000000000000000000DKDenmarkEurope

Natural Right Outer Join

Oracle

SELECT * FROM
hr.countries c
NATURAL RIGHT OUTER JOIN hr.regions r
ORDER BY country_id DESC
FETCH FIRST 10 ROWS ONLY;
Result
REGION_IDCOUNTRY_IDCOUNTRY_NAMEREGION_NAME
5Oceania
4ZWZimbabweMiddle East and Africa
4ZMZambiaMiddle East and Africa
2USUnited States of AmericaAmericas
1UKUnited KingdomEurope
3SGSingaporeAsia
1NLNetherlandsEurope
4NGNigeriaMiddle East and Africa
2MXMexicoAmericas
3MLMalaysiaAsia
Snowflake

SELECT * FROM
hr.countries c
NATURAL RIGHT OUTER JOIN
hr.regions r
ORDER BY country_id DESC
FETCH FIRST 10 ROWS ONLY;
Result
REGION_IDCOUNTRY_IDCOUNTRY_NAMEREGION_NAME
5.0000000000000000000Oceania
4.0000000000000000000ZWZimbabweMiddle East and Africa
4.0000000000000000000ZMZambiaMiddle East and Africa
2.0000000000000000000USUnited States of AmericaAmericas
1.0000000000000000000UKUnited KingdomEurope
3.0000000000000000000SGSingaporeAsia
1.0000000000000000000NLNetherlandsEurope
4.0000000000000000000NGNigeriaMiddle East and Africa
2.0000000000000000000MXMexicoAmericas
3.0000000000000000000MLMalaysiaAsia

3. Basic Outer Join with USING

Table columns can be joined using the USING keyword. The results will be the same as a basic OUTER JOIN with the ON keyword.

Left Outer Join Using

Oracle

SELECT * FROM
hr.countries c
LEFT OUTER JOIN hr.regions r USING (region_id)
ORDER BY country_id
FETCH FIRST 10 ROWS ONLY;
Result
REGION_IDCOUNTRY_IDCOUNTRY_NAMEREGION_NAME
0Unknown Country
2ARArgentinaAmericas
3AUAustraliaAsia
1BEBelgiumEurope
2BRBrazilAmericas
2CACanadaAmericas
1CHSwitzerlandEurope
3CNChinaAsia
1DEGermanyEurope
1DKDenmarkEurope
Snowflake

SELECT * FROM
hr.countries c
LEFT OUTER JOIN
hr.regions r USING (region_id)
ORDER BY country_id
FETCH FIRST 10 ROWS ONLY;
Result
REGION_IDCOUNTRY_IDCOUNTRY_NAMEREGION_NAME
0.0000000000000000000Unknown Country
2.0000000000000000000ARArgentinaAmericas
3.0000000000000000000AUAustraliaAsia
1.0000000000000000000BEBelgiumEurope
2.0000000000000000000BRBrazilAmericas
2.0000000000000000000CACanadaAmericas
1.0000000000000000000CHSwitzerlandEurope
3.0000000000000000000CNChinaAsia
1.0000000000000000000DEGermanyEurope
1.0000000000000000000DKDenmarkEurope

4. (+) Operator

Oracle and Snowflake have a (+) operator that can be used for outer joins too. In some cases, Snowflake may not work properly when using this operator.

For more information regarding this operator in Snowflake, check this.

Left Outer Join with (+) operator

Oracle

SELECT * FROM hr.countries c, hr.regions r
WHERE c.region_id = r.region_id(+)
ORDER BY country_id
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_IDREGION_NAME
Unknown Country0
ARArgentina22Americas
AUAustralia33Asia
BEBelgium11Europe
BRBrazil22Americas
CACanada22Americas
CHSwitzerland11Europe
CNChina33Asia
DEGermany11Europe
DKDenmark11Europe
Snowflake

SELECT * FROM
hr.countries c,
hr.regions r
WHERE c.region_id = r.region_id(+)
ORDER BY country_id
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_IDREGION_NAME
Unknown Country0.0000000000000000000
ARArgentina2.00000000000000000002.0000000000000000000Americas
AUAustralia3.00000000000000000003.0000000000000000000Asia
BEBelgium1.00000000000000000001.0000000000000000000Europe
BRBrazil2.00000000000000000002.0000000000000000000Americas
CACanada2.00000000000000000002.0000000000000000000Americas
CHSwitzerland1.00000000000000000001.0000000000000000000Europe
CNChina3.00000000000000000003.0000000000000000000Asia
DEGermany1.00000000000000000001.0000000000000000000Europe
DKDenmark1.00000000000000000001.0000000000000000000Europe

Right Outer Join with (+) operator

Oracle

SELECT * FROM hr.countries c, hr.regions r
WHERE c.region_id (+) = r.region_id
ORDER BY country_id DESC
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_IDREGION_NAME
5Oceania
ZWZimbabwe44Middle East and Africa
ZMZambia44Middle East and Africa
USUnited States of America22Americas
UKUnited Kingdom11Europe
SGSingapore33Asia
NLNetherlands11Europe
NGNigeria44Middle East and Africa
MXMexico22Americas
MLMalaysia33Asia
Snowflake

SELECT * FROM
hr.countries c,
hr.regions r
WHERE c.region_id (+) = r.region_id
ORDER BY country_id DESC
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_IDREGION_NAME
5.0000000000000000000Oceania
ZWZimbabwe4.00000000000000000004.0000000000000000000Middle East and Africa
ZMZambia4.00000000000000000004.0000000000000000000Middle East and Africa
USUnited States of America2.00000000000000000002.0000000000000000000Americas
UKUnited Kingdom1.00000000000000000001.0000000000000000000Europe
SGSingapore3.00000000000000000003.0000000000000000000Asia
NLNetherlands1.00000000000000000001.0000000000000000000Europe
NGNigeria4.00000000000000000004.0000000000000000000Middle East and Africa
MXMexico2.00000000000000000002.0000000000000000000Americas
MLMalaysia3.00000000000000000003.0000000000000000000Asia

Single table joined with multiple tables with (+)

In Oracle, you can join a single table with multiple tables using the (+) operator, however, Snowflake does not support this. Queries with this kind of Outer Joins will be changed to ANSI syntax.

Oracle

SELECT
c.country_id,
c.country_name,
r.region_id,
r.region_name,
l.location_id,
l.street_address,
l.postal_code,
l.city
FROM
hr.countries c, hr.regions r,  hr.locations l
WHERE
c.region_id(+) = r.region_id AND
l.country_id = c.country_id(+)
ORDER BY r.region_id, l.city
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_NAMELOCATION_IDSTREET_ADDRESSPOSTAL_CODECITY
1Europe200040-5-12 Laogianggen190518Beijing
CHSwitzerland1Europe3000Murtenstrasse 9213095Bern
1Europe21001298 Vileparle (E)490231Bombay
CHSwitzerland1Europe290020 Rue des Corps-Saints1730Geneva
1Europe13009450 Kamiya-cho6823Hiroshima
UKUnited Kingdom1Europe24008204 Arthur StLondon
1Europe3200Mariano Escobedo 999111932Mexico City
DEGermany1Europe2700Schwanthalerstr. 703180925Munich
UKUnited Kingdom1Europe2500Magdalen Centre, The Oxford Science ParkOX9 9ZBOxford
ITItaly1Europe10001297 Via Cola di Rie00989Roma
Snowflake

SELECT
c.country_id,
c.country_name,
r.region_id,
r.region_name,
l.location_id,
l.street_address,
l.postal_code,
l.city
FROM
hr.regions r
CROSS JOIN hr.locations l
LEFT OUTER JOIN
hr.countries c
ON
c.region_id = r.region_id
AND
l.country_id = c.country_id
ORDER BY r.region_id, l.city
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_NAMELOCATION_IDSTREET_ADDRESSPOSTAL_CODECITY
1.0000000000000000000Europe200040-5-12 Laogianggen190518Beijing
CHSwitzerland1.0000000000000000000Europe3000Murtenstrasse 9213095Bern
1.0000000000000000000Europe21001298 Vileparle (E)490231Bombay
CHSwitzerland1.0000000000000000000Europe290020 Rue des Corps-Saints1730Geneva
1.0000000000000000000Europe13009450 Kamiya-cho6823Hiroshima
UKUnited Kingdom1.0000000000000000000Europe24008204 Arthur StLondon
1.0000000000000000000Europe3200Mariano Escobedo 999111932Mexico City
DEGermany1.0000000000000000000Europe2700Schwanthalerstr. 703180925Munich
UKUnited Kingdom1.0000000000000000000Europe2500Magdalen Centre, The Oxford Science ParkOX9 9ZBOxford
ITItaly1.0000000000000000000Europe10001297 Via Cola di Rie00989Roma

Using (+) operator with a column from a not-joined table and a non-column value

In Oracle, you can use the (+) operator with a Column and join it with a value that is not a column from another table. Snowflake can also do this but it will fail if the table of the column was not joined with another table. To solve this issue, the (+) operator is removed from the query when this scenario happens and the result will be the same as in Oracle.

Oracle

SELECT * FROM hr.regions r
WHERE
r.region_name (+) LIKE 'A%'
ORDER BY region_id;
Result
REGION_IDREGION_NAME
2Americas
3Asia
Snowflake

SELECT * FROM
hr.regions r
WHERE
r.region_name LIKE 'A%'
ORDER BY region_id;
Result
REGION_IDREGION_NAME
2.0000000000000000000Americas
3.0000000000000000000Asia

Known issues

For all the unsupported cases, please check the related EWIs to obtain recommendations and possible workarounds.

1. Converted Outer Joins to ANSI syntax might reorder the columns

When a query with a non-ANSI Outer Join is converted to an ANSI Outer Join, it may change the order of the columns in the converted query. To fix this issue, try to select the columns in the specific order required.

Oracle

SELECT
*
FROM
hr.countries c, hr.regions r,  hr.locations l
WHERE
c.region_id(+) = r.region_id AND
l.country_id = c.country_id(+)
ORDER BY r.region_id, l.city
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_IDREGION_NAMELOCATION_IDSTREET_ADDRESSPOSTAL_CODECITYSTATE_PROVINCECOUNTRY_ID
1Europe200040-5-12 Laogianggen190518BeijingCN
CHSwitzerland11Europe3000Murtenstrasse 9213095BernBECH
1Europe21001298 Vileparle (E)490231BombayMaharashtraIN
CHSwitzerland11Europe290020 Rue des Corps-Saints1730GenevaGeneveCH
1Europe13009450 Kamiya-cho6823HiroshimaJP
UKUnited Kingdom11Europe24008204 Arthur StLondonUK
1Europe3200Mariano Escobedo 999111932Mexico CityDistrito Federal,MX
DEGermany11Europe2700Schwanthalerstr. 703180925MunichBavariaDE
UKUnited Kingdom11Europe2500Magdalen Centre, The Oxford Science ParkOX9 9ZBOxfordOxfordUK
ITItaly11Europe10001297 Via Cola di Rie00989RomaIT
Snowflake

SELECT
*
FROM
hr.regions r
CROSS JOIN hr.locations l
LEFT OUTER JOIN
hr.countries c
ON
c.region_id = r.region_id
AND
l.country_id = c.country_id
ORDER BY r.region_id, l.city
FETCH FIRST 10 ROWS ONLY;
Result
REGION_IDREGION_NAMELOCATION_IDSTREET_ADDRESSPOSTAL_CODECITYSTATE_PROVINCECOUNTRY_IDCOUNTRY_IDCOUNTRY_NAMEREGION_ID
1.0000000000000000000Europe200040-5-12 Laogianggen190518BeijingCN
1.0000000000000000000Europe3000Murtenstrasse 9213095BernBECHCHSwitzerland1.0000000000000000000
1.0000000000000000000Europe21001298 Vileparle (E)490231BombayMaharashtraIN
1.0000000000000000000Europe290020 Rue des Corps-Saints1730GenevaGeneveCHCHSwitzerland1.0000000000000000000
1.0000000000000000000Europe13009450 Kamiya-cho6823HiroshimaJP
1.0000000000000000000Europe24008204 Arthur StLondonUKUKUnited Kingdom1.0000000000000000000
1.0000000000000000000Europe3200Mariano Escobedo 999111932Mexico CityDistrito Federal,MX
1.0000000000000000000Europe2700Schwanthalerstr. 703180925MunichBavariaDEDEGermany1.0000000000000000000
1.0000000000000000000Europe2500Magdalen Centre, The Oxford Science ParkOX9 9ZBOxfordOxfordUKUKUnited Kingdom1.0000000000000000000
1.0000000000000000000Europe10001297 Via Cola di Rie00989RomaITITItaly1.0000000000000000000
2. Outer joined between predicate with an interval with multiple tables

Between predicates can be used for non-ANSI OUTER JOINS. In Oracle, columns inside the interval can be outer joined, even if they come from different tables, however, Snowflake does not support this. For these cases, the between predicate will be commented out.

Oracle

SELECT
*
FROM
hr.countries c, hr.regions r,  hr.locations l WHERE
l.location_id  BETWEEN r.region_id(+) AND c.region_id(+)
ORDER BY r.region_id, l.city
FETCH FIRST 10 ROWS ONLY;
Result
COUNTRY_IDCOUNTRY_NAMEREGION_IDREGION_IDREGION_NAMELOCATION_IDSTREET_ADDRESSPOSTAL_CODECITYSTATE_PROVINCECOUNTRY_ID
1Europe200040-5-12 Laogianggen190518BeijingCN
1Europe3000Murtenstrasse 9213095BernBECH
1Europe21001298 Vileparle (E)490231BombayMaharashtraIN
1Europe290020 Rue des Corps-Saints1730GenevaGeneveCH
1Europe13009450 Kamiya-cho6823HiroshimaJP
1Europe24008204 Arthur StLondonUK
1Europe3200Mariano Escobedo 999111932Mexico CityDistrito Federal,MX
1Europe2700Schwanthalerstr. 703180925MunichBavariaDE
1Europe2500Magdalen Centre, The Oxford Science ParkOX9 9ZBOxfordOxfordUK
1Europe10001297 Via Cola di Rie00989RomaIT
Snowflake

SELECT
*
FROM
hr.countries c,
hr.regions r,
hr.locations l WHERE
!!!RESOLVE EWI!!! /*** SSC-EWI-OR0090 - INVALID NON-ANSI OUTER JOIN BETWEEN PREDICATE CASE FOR SNOWFLAKE. ***/!!!
l.location_id  BETWEEN r.region_id(+) AND c.region_id(+)
ORDER BY r.region_id, l.city
FETCH FIRST 10 ROWS ONLY;
  1. SSC-EWI-OR0090: Non-Ansi Outer Join has an invalid Between predicate.

Self Join

Note

Some parts in the output codes are omitted for clarity reasons.

Description

A self join is a join of a table to itself. This table appears twice in the FROM clause and is followed by table aliases that qualify column names in the join condition. (Oracle SQL Language Reference Self Join Subsection)

Sample Source Patterns

Note

Order by clause added because the result order may vary between Oracle and Snowflake.

Note

Check this section to set up the sample database.

Basic Self Join case

Oracle

SELECT e1.last_name||' works for '||e2.last_name
   "Employees and Their Managers"
   FROM hr.employees e1, hr.employees e2
   WHERE e1.manager_id = e2.employee_id
      AND e1.last_name LIKE 'R%'
   ORDER BY e1.last_name;
Result
Employees and Their Managers
Rajs works for Mourgos
Raphaely works for King
Rogers works for Kaufling
Russell works for King
Snowflake

SELECT
   NVL( e1.last_name :: STRING, '') || ' works for ' || NVL(e2.last_name :: STRING, '') "Employees and Their Managers"
FROM
   hr.employees e1,
   hr.employees e2
   WHERE e1.manager_id = e2.employee_id
      AND e1.last_name LIKE 'R%'
   ORDER BY e1.last_name;
Result
Employees and Their Managers
Rajs works for Mourgos
Raphaely works for King
Rogers works for Kaufling
Russell works for King

Note

As proved previously the self join in Oracle is functionally equivalent to Snowflake.

Known Issues

No issues were found.

No related EWIs.

Semijoin

Note

Some parts in the output code are omitted for clarity reasons.

Description

A semijoin returns rows that match an EXISTS subquery without duplicating rows from the left side of the predicate when multiple rows on the right side satisfy the criteria of the subquery. Semijoin transformation cannot be done if the subquery is on an OR branch of the WHERE clause. (Oracle SQL Language Reference Semijoin Subsection)

Sample Source Patterns

Note

Order by clause added because the result order may vary between Oracle and Snowflake.

Note

Check this section to set up the sample database.

Basic Semijoin case

Oracle

SELECT * FROM hr.departments
   WHERE EXISTS
   (SELECT * FROM hr.employees
       WHERE departments.department_id = employees.department_id
       AND employees.salary > 2500)
   ORDER BY department_name;
Result
DEPARTMENT_IDDEPARTMENT_NAMEMANAGER_IDLOCATION_ID
110Accounting2051700
10Administration2001700
90Executive1001700
100Finance1081700
40Human Resources2032400
60IT1031400
20Marketing2011800
70Public Relations2042700
30Purchasing1141700
80Sales1452500
50Shipping1211500
Snowflake

SELECT * FROM
   hr.departments
   WHERE EXISTS
   (SELECT * FROM
         hr.employees
       WHERE departments.department_id = employees.department_id
       AND employees.salary > 2500)
   ORDER BY department_name;
Result
DEPARTMENT_IDDEPARTMENT_NAMEMANAGER_IDLOCATION_ID
110Accounting2051700
10Administration2001700
90Executive1001700
100Finance1081700
40Human Resources2032400
60IT1031400
20Marketing2011800
70Public Relations2042700
30Purchasing1141700
80Sales1452500
50Shipping1211500

Note

As proved previously the semijoin in Oracle is functionally equivalent to Snowflake.

Known Issues

No issues were found.

No related EWIs.