<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>OpenText Analytics Database 26.2.x – Inner joins</title>
    <link>/en/data-analysis/queries/joins/inner-joins/</link>
    <description>Recent content in Inner joins on OpenText Analytics Database 26.2.x</description>
    <generator>Hugo -- gohugo.io</generator>
    
	  <atom:link href="/en/data-analysis/queries/joins/inner-joins/index.xml" rel="self" type="application/rss+xml" />
    
    
      
        
      
    
    
    <item>
      <title>Data-Analysis: Equi-joins and non equi-joins</title>
      <link>/en/data-analysis/queries/joins/inner-joins/equi-joins-and-non-equi-joins/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/en/data-analysis/queries/joins/inner-joins/equi-joins-and-non-equi-joins/</guid>
      <description>
        
        
        &lt;p&gt;OpenText™ Analytics Database supports any arbitrary join expression with both matching and non-matching column values. For example:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;SELECT * FROM fact JOIN dim ON fact.x = dim.x;
SELECT * FROM fact JOIN dim ON fact.x &amp;gt; dim.y;
SELECT * FROM fact JOIN dim ON fact.x &amp;lt;= dim.y;
SELECT * FROM fact JOIN dim ON fact.x &amp;lt;&amp;gt; dim.y;
SELECT * FROM fact JOIN dim ON fact.x &amp;lt;=&amp;gt; dim.y;
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;alert admonition note&#34; role=&#34;alert&#34;&gt;
&lt;h4 class=&#34;admonition-head&#34;&gt;Note&lt;/h4&gt;

Operators &lt;code&gt;=&lt;/code&gt; and &lt;code&gt;&amp;lt;=&amp;gt;&lt;/code&gt; generally run the fastest.

&lt;/div&gt;
&lt;p&gt;Equi-joins are based on equality (matching column values). This equality is indicated with an equal sign (&lt;code&gt;=&lt;/code&gt;), which functions as the comparison operator in the &lt;code&gt;ON&lt;/code&gt; clause using SQL-92 syntax or the &lt;code&gt;WHERE&lt;/code&gt; clause using older join syntax.&lt;/p&gt;
&lt;p&gt;The first example below uses SQL-92 syntax and the &lt;code&gt;ON&lt;/code&gt; clause to join the online sales table with the call center table using the call center key; the query then returns the sale date key that equals the value 156:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT sale_date_key, cc_open_date FROM online_sales.online_sales_fact
   INNER JOIN online_sales.call_center_dimension
   ON (online_sales.online_sales_fact.call_center_key =
    online_sales.call_center_dimension.call_center_key
   AND sale_date_key = 156);
 sale_date_key | cc_open_date
---------------+--------------
           156 | 2005-08-12
(1 row)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The second example uses older join syntax and the &lt;code&gt;WHERE&lt;/code&gt; clause to join the same tables to get the same results:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT sale_date_key, cc_open_date
    FROM online_sales.online_sales_fact, online_sales.call_center_dimension
   WHERE online_sales.online_sales_fact.call_center_key =
      online_sales.call_center_dimension.call_center_key
   AND sale_date_key = 156;
 sale_date_key | cc_open_date
---------------+--------------
           156 | 2005-08-12
(1 row)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The database also permits tables with compound (multiple-column) primary and foreign keys. For example, to create a pair of tables with multi-column keys:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; CREATE TABLE dimension(pk1 INTEGER NOT NULL, pk2 INTEGER NOT NULL);=&amp;gt; ALTER TABLE dimension ADD PRIMARY KEY (pk1, pk2);
=&amp;gt; CREATE TABLE fact (fk1 INTEGER NOT NULL, fk2 INTEGER NOT NULL);
=&amp;gt; ALTER TABLE fact ADD FOREIGN KEY (fk1, fk2) REFERENCES dimension (pk1, pk2);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To join tables using compound keys, you must connect two &lt;a href=&#34;../../../../../en/sql-reference/language-elements/predicates/interpolate/join-predicate/&#34;&gt;join predicates&lt;/a&gt; with a Boolean &lt;code&gt;AND&lt;/code&gt; operator. For example:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT * FROM fact f JOIN dimension d ON f.fk1 = d.pk1 AND f.fk2 = d.pk2;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can write queries with expressions that contain the &lt;code&gt;&amp;lt;=&amp;gt;&lt;/code&gt; operator for &lt;code&gt;NULL=NULL&lt;/code&gt; joins.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT * FROM fact JOIN dim ON fact.x &amp;lt;=&amp;gt; dim.y;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;&amp;lt;=&amp;gt;&lt;/code&gt; operator performs an equality comparison like the &lt;code&gt;=&lt;/code&gt; operator, but it returns true, instead of &lt;code&gt;NULL&lt;/code&gt;, if both operands are &lt;code&gt;NULL&lt;/code&gt;, and false, instead of &lt;code&gt;NULL&lt;/code&gt;, if one operand is &lt;code&gt;NULL&lt;/code&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT 1 &amp;lt;=&amp;gt; 1, NULL &amp;lt;=&amp;gt; NULL, 1 &amp;lt;=&amp;gt; NULL;
 ?column? | ?column? | ?column?
----------+----------+----------
 t        | t        | f
(1 row)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Compare the &amp;lt;=&amp;gt; operator to the = operator:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT 1 = 1, NULL = NULL, 1 = NULL;
 ?column? | ?column? | ?column?
----------+----------+----------
 t        |          |
(1 row)
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&#34;alert admonition note&#34; role=&#34;alert&#34;&gt;
&lt;h4 class=&#34;admonition-head&#34;&gt;Note&lt;/h4&gt;

Writing &lt;code&gt;NULL=NULL&lt;/code&gt; joins on primary key/foreign key combinations is not an optimal choice because PK/FK columns are usually defined as &lt;code&gt;NOT NULL&lt;/code&gt;.

&lt;/div&gt;
&lt;p&gt;When composing joins, it helps to know in advance which columns contain null values. An employee&#39;s hire date, for example, would not be a good choice because it is unlikely hire date would be omitted. An hourly rate column, however, might work if some employees are paid hourly and some are salaried. If you are unsure about the value of columns in a given table and want to check, type the command:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT COUNT(*) FROM &lt;span class=&#34;code-variable&#34;&gt;tablename&lt;/span&gt; WHERE &lt;span class=&#34;code-variable&#34;&gt;columnname&lt;/span&gt; IS NULL;
&lt;/code&gt;&lt;/pre&gt;
      </description>
    </item>
    
    <item>
      <title>Data-Analysis: Natural joins</title>
      <link>/en/data-analysis/queries/joins/inner-joins/natural-joins/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/en/data-analysis/queries/joins/inner-joins/natural-joins/</guid>
      <description>
        
        
        &lt;p&gt;A natural join is just a join with an implicit join predicate. Natural joins can be inner, left outer, right outer, or full outer joins and take the following form:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;SELECT &lt;span class=&#34;code-variable&#34;&gt;column-list&lt;/span&gt; FROM &lt;span class=&#34;code-variable&#34;&gt;left-join-table&lt;/span&gt;
NATURAL [ INNER | LEFT OUTER | RIGHT OUTER | FULL OUTER ] JOIN &lt;span class=&#34;code-variable&#34;&gt;right-join-table&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Natural joins are, by default, natural inner joins; however, there can also be natural left/right/full outer joins. The primary difference between an inner and natural join is that inner joins have an explicit join condition, whereas the natural join’s conditions are formed by matching all pairs of columns in the tables that have the same name and compatible data types, making natural joins equi-joins because join condition are equal between common columns. (If the data types are incompatible, the database returns an error.)

&lt;div class=&#34;alert admonition note&#34; role=&#34;alert&#34;&gt;
&lt;h4 class=&#34;admonition-head&#34;&gt;Note&lt;/h4&gt;

The &lt;a href=&#34;../../../../../en/sql-reference/data-types/data-type-coercion-chart/#&#34;&gt;Data type coercion chart&lt;/a&gt; lists the data types that can be cast to other data types. If one data type can be cast to the other, those two data types are compatible.

&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;The following query is a simple natural join between tables T1 and T2 when the T2 column &lt;code&gt;val&lt;/code&gt; is greater than 5:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT * FROM T1 NATURAL JOIN T2 WHERE T2.val &amp;gt; 5;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;store_sales_fact&lt;/code&gt; table and the &lt;code&gt;product_dimension&lt;/code&gt; table have two columns that share the same name and data type: &lt;code&gt;product_key&lt;/code&gt; and &lt;code&gt;product_version&lt;/code&gt;. The following example creates a natural join between those two tables at their shared columns:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT product_description, sales_quantity FROM store.store_sales_fact
   NATURAL JOIN public.product_dimension;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The following three queries return the same result expressed as a basic query, an inner join, and a natural join. at the table expressions are equivalent only if the common attribute in the &lt;code&gt;store_sales_fact&lt;/code&gt; table and the &lt;code&gt;store_dimension&lt;/code&gt; table is &lt;code&gt;store_key&lt;/code&gt;. If both tables have a column named &lt;code&gt;store_key&lt;/code&gt;, then the natural join would also have a &lt;code&gt;store_sales_fact.store_key = store_dimension.store_key&lt;/code&gt; join condition. Since the results are the same in all three instances, they are shown in the first (basic) query only:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT store_name FROM store.store_sales_fact, store.store_dimension
   WHERE store.store_sales_fact.store_key = store.store_dimension.store_key
   AND store.store_dimension.store_state = &amp;#39;MA&amp;#39; ORDER BY store_name;
 store_name
------------
 Store11
 Store128
 Store178
 Store66
 Store8
 Store90
(6 rows)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The query written as an inner join:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT store_name FROM store.store_sales_fact
   INNER JOIN store.store_dimension
   ON (store.store_sales_fact.store_key = store.store_dimension.store_key)
   WHERE store.store_dimension.store_state = &amp;#39;MA&amp;#39; ORDER BY store_name;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the case of the natural join, the join predicate appears implicitly by comparing all of the columns in both tables that are joined by the same column name. The result set contains only one column representing the pair of equally-named columns.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT store_name FROM store.store_sales_fact
   NATURAL JOIN store.store_dimension
   WHERE store.store_dimension.store_state = &amp;#39;MA&amp;#39; ORDER BY store_name;
&lt;/code&gt;&lt;/pre&gt;
      </description>
    </item>
    
    <item>
      <title>Data-Analysis: Cross joins</title>
      <link>/en/data-analysis/queries/joins/inner-joins/cross-joins/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      
      <guid>/en/data-analysis/queries/joins/inner-joins/cross-joins/</guid>
      <description>
        
        
        &lt;p&gt;Cross joins are the simplest joins to write, but they are not usually the fastest to run because they consist of all possible combinations of two tables’ records. Cross joins contain no join condition and return what is known as a Cartesian product, where the number of rows in the result set is equal to the number of rows in the first table multiplied by the number of rows in the second table.&lt;/p&gt;
&lt;p&gt;The following query returns all possible combinations from the promotion table and the store sales table:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT * FROM promotion_dimension CROSS JOIN store.store_sales_fact;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Because this example returns over 600 million records, many cross join results can be extremely large and difficult to manage. Cross joins can be useful, however, such as when you want to return a single-row result set.

&lt;div class=&#34;alert admonition tip&#34; role=&#34;alert&#34;&gt;
&lt;h4 class=&#34;admonition-head&#34;&gt;Tip&lt;/h4&gt;

&lt;p&gt;Filter out unwanted records in a cross with &lt;code&gt;WHERE&lt;/code&gt; clause join predicates:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT * FROM promotion_dimension p   CROSS JOIN store.store_sales_fact f
   WHERE p.promotion_key LIKE f.promotion_key;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;&lt;/p&gt;
&lt;h2 id=&#34;implicit-versus-explicit-joins&#34;&gt;Implicit versus explicit joins&lt;/h2&gt;
&lt;p&gt;OpenText recommends that you do not write implicit cross joins (comma-separated tables in the &lt;code&gt;FROM&lt;/code&gt; clause). These queries can imply accidental omission of a join predicate.&lt;/p&gt;
&lt;p&gt;The following query implicitly cross joins tables &lt;code&gt;promotion_dimension&lt;/code&gt;&lt;strong&gt;&lt;code&gt; and&lt;/code&gt;&lt;/strong&gt; &lt;code&gt;store.store_sales_fact&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT * FROM promotion_dimension&lt;span class=&#34;code-input&#34;&gt;,&lt;/span&gt; store.store_sales_fact;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It is better practice to express this cross join explicitly, as follows:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; SELECT * FROM promotion_dimension &lt;span class=&#34;code-input&#34;&gt;CROSS JOIN&lt;/span&gt; store.store_sales_fact;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;examples&#34;&gt;Examples&lt;/h2&gt;
&lt;p&gt;The following example creates two small tables and their superprojections and then runs a cross join on the tables:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;=&amp;gt; CREATE TABLE employee(employee_id INT, employee_fname VARCHAR(50));
=&amp;gt; CREATE TABLE department(dept_id INT, dept_name VARCHAR(50));
=&amp;gt; INSERT INTO employee VALUES (1, &amp;#39;Andrew&amp;#39;);
=&amp;gt; INSERT INTO employee VALUES (2, &amp;#39;Priya&amp;#39;);
=&amp;gt; INSERT INTO employee VALUES (3, &amp;#39;Michelle&amp;#39;);
=&amp;gt; INSERT INTO department VALUES (1, &amp;#39;Engineering&amp;#39;);
=&amp;gt; INSERT INTO department VALUES (2, &amp;#39;QA&amp;#39;);
=&amp;gt; SELECT * FROM employee CROSS JOIN department;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the result set, the cross join retrieves records from the first table and then creates a new row for every row in the 2nd table. It then does the same for the next record in the first table, and so on.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt; employee_id | employee_name | dept_id | dept_name
 -------------+---------------+---------+-----------
           1 | Andrew        |       1 |  Engineering
           2 | Priya         |       1 |  Engineering
           3 | Michelle      |       1 |  Engineering
           1 | Andrew        |       2 |  QA
           2 | Priya         |       2 |  QA
           3 | Michelle      |       2 |  QA
(6 rows)
&lt;/code&gt;&lt;/pre&gt;
      </description>
    </item>
    
  </channel>
</rss>
