Project: ClickHouse (App Definition and Development / Database)
File: join.md

slug: /en/sql-reference/statements/select/join sidebar_label: Joining Tables Join produces a new table by combining columns from one or multiple tables by using values common to each. It is a common operation in databases with SQL support, which corresponds to join. The special case of one table join is often referred to as self-join. Syntax ``` sql SELECT <expr_list> FROM <left_table> [GLOBAL] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI|ANY|ALL|ASOF] JOIN <right_table> (ON <exprlist>)|(USING <columnlist>) ... ``` Expressions from `ON` clause and columns from `USING` clause are called join keys. Unless otherwise stated, join produces a from rows with matching join keys, which might produce results with much more rows than the source tables. Blog: Blog: Blog: Blog: All standard ) types are supported: `INNER JOIN`, only matching rows are returned. `LEFT OUTER JOIN`, non-matching rows from left table are returned in addition to matching rows. `RIGHT OUTER JOIN`, non-matching rows from right table are returned in addition to matching rows. `FULL OUTER JOIN`, non-matching rows from both tables are returned in addition to matching rows. `CROSS JOIN`, produces cartesian product of whole tables, join keys are not specified. `JOIN` without specified type implies `INNER`. Keyword `OUTER` can be safely omitted. Alternative syntax for `CROSS JOIN` is specifying multiple tables in separated by commas. Additional join types available in ClickHouse: `LEFT SEMI JOIN` and `RIGHT SEMI JOIN`, a whitelist on join keys, without producing a cartesian product. `LEFT ANTI JOIN` and `RIGHT ANTI JOIN`, a blacklist on join keys, without producing a cartesian product. `LEFT ANY JOIN`, `RIGHT ANY JOIN` and `INNER ANY JOIN`, partially (for opposite side of `LEFT` and `RIGHT`) or completely (for `INNER` and `FULL`) disables the cartesian product for standard `JOIN` types. `ASOF JOIN` and `LEFT ASOF JOIN`, joining sequences with a non-exact match. `ASOF JOIN` usage is described below. `PASTE JOIN`, performs a horizontal concatenation of two tables. :::note When is set to `partial_merge`, `RIGHT JOIN` and `FULL JOIN` are supported only with `ALL` strictness (`SEMI`, `ANTI`, `ANY`, and `ASOF` are not supported). ::: The default join type can be overridden using setting. The behavior of ClickHouse server for `ANY JOIN` operations depends on the setting. See also Use the `crosstoinnerjoinrewrite` setting to define the behavior when ClickHouse fails to rewrite a `CROSS JOIN` as an `INNER JOIN`. The default value is `1`, which allows the join to continue but it will be slower. Set `crosstoinnerjoinrewrite` to `0` if you want an error to be thrown, and set it to `2` to not run the cross joins but instead force a rewrite of all comma/cross joins. If the rewriting fails when the value is `2`, you will receive an error message stating "Please, try to simplify `WHERE` section". An `ON` section can contain several conditions combined using the `AND` and `OR` operators. Conditions specifying join keys must refer both left and right tables and must use the equality operator. Other conditions may use other logical operators but they must refer either the left or the right table of a query. Rows are joined if the whole complex condition is

If the conditions are not met, still rows may be included in the result depending on the `JOIN` type. Note that if the same conditions are placed in a `WHERE` section and they are not met, then rows are always filtered out from the result. The `OR` operator inside the `ON` clause works using the hash join algorithm for each `OR` argument with join keys for `JOIN`, a separate hash table is created, so memory consumption and query execution time grow linearly with an increase in the number of expressions `OR` of the `ON` clause. :::note If a condition refers columns from different tables, then only the equality operator (`=`) is supported so far. ::: Example Consider `table1` and `table2`: ``` Idname Idtextscores 1 A 1 Text A 10 2 B 1 Another text A 12 3 C 2 Text B 15 ``` Query with one join key condition and an additional condition for `table_2`: ``` sql SELECT name, text FROM table1 LEFT OUTER JOIN table2 ON table1.Id = table2.Id AND startsWith(table_2.text, 'Text'); ``` Note that the result contains the row with the name `C` and the empty text column. It is included into the result because an `OUTER` type of a join is used. ``` nametext A Text A B Text B C ``` Query with `INNER` type of a join and multiple conditions: ``` sql SELECT name, text, scores FROM table1 INNER JOIN table2 ON table1.Id = table2.Id AND table2.scores > 10 AND startsWith(table2.text, 'Text'); ``` Result: ``` nametextscores B Text B 15 ``` Query with `INNER` type of a join and condition with `OR`: ``` sql CREATE TABLE t1 (`a` Int64, `b` Int64) ENGINE = MergeTree() ORDER BY a; CREATE TABLE t2 (`key` Int32, `val` Int64) ENGINE = MergeTree() ORDER BY key; INSERT INTO t1 SELECT number as a, -a as b from numbers(5); INSERT INTO t2 SELECT if(number % 2 == 0, toInt64(number), -number) as key, number as val from numbers(5); SELECT a, b, val FROM t1 INNER JOIN t2 ON t1.a = t2.key OR t1.b = t2.key; ``` Result: ``` abval 0 0 0 1 -1 1 2 -2 2 3 -3 3 4 -4 4 ``` Query with `INNER` type of a join and conditions with `OR` and `AND`: :::note By default, non-equal conditions are supported as long as they use columns from the same table. For example, `t1.a = t2.key AND t1.b > 0 AND t2.b > t2.c`, because `t1.b > 0` uses columns only from `t1` and `t2.b > t2.c` uses columns only from `t2`. However, you can try experimental support for conditions like `t1.a = t2.key AND t1.b > t2.key`, check out section below for more details. ::: ``` sql SELECT a, b, val FROM t1 INNER JOIN t2 ON t1.a = t2.key OR t1.b = t2.key AND t2.val > 3; ``` Result: ``` abval 0 0 0 2 -2 2 4 -4 4 ``` :::note This feature is experimental. To use it, set `allowexperimentaljoin_condition` to 1 in your configuration files or by using the `SET` command: ```sql SET allowexperimentaljoin_condition=1 ``` Otherwise, you'll get `INVALIDJOINON_EXPRESSION`. ::: Clickhouse currently supports `ALL INNER/LEFT/RIGHT/FULL JOIN` with inequality conditions in addition to equality

The inequality conditions are supported only for `hash` and `gracehash` join algorithms. The inequality conditions are not supported with `joinuse_nulls`. Example Table `t1`: ``` keyattrabc key1 a 1 1 2 key1 b 2 3 2 key1 c 3 2 1 key1 d 4 7 2 key1 e 5 5 5 key2 a2 1 1 1 key4 f 2 3 4 ``` Table `t2` ``` keyattrabc key1 A 1 2 1 key1 B 2 1 2 key1 C 3 4 5 key1 D 4 1 6 key3 a3 1 1 1 key4 F 1 1 1 ``` ```sql SELECT t1., t2. from t1 LEFT JOIN t2 ON t1.key = t2.key and (t1.a < t2.a) ORDER BY (t1.key, t1.attr, t2.key, t2.attr); ``` ``` key1 a 1 1 2 key1 B 2 1 2 key1 a 1 1 2 key1 C 3 4 5 key1 a 1 1 2 key1 D 4 1 6 key1 b 2 3 2 key1 C 3 4 5 key1 b 2 3 2 key1 D 4 1 6 key1 c 3 2 1 key1 D 4 1 6 key1 d 4 7 2 0 0 \N key1 e 5 5 5 0 0 \N key2 a2 1 1 1 0 0 \N key4 f 2 3 4 0 0 \N ``` The NULL is not equal to any value, including itself. It means that if a JOIN key has a NULL value in one table, it won't match a NULL value in the other table. Example Table `A`: ``` idname 1 Alice 2 Bob Charlie ``` Table `B`: ``` idscore 1 90 3 85 88 ``` ```sql SELECT A.name, B.score FROM A LEFT JOIN B ON A.id = B.id ``` ``` namescore Alice 90 Bob 0 Charlie 0 ``` Notice that the row with `Charlie` from table `A` and the row with score 88 from table `B` are not in the result because of the NULL value in the JOIN key. In case you want to match NULL values, use the `isNotDistinctFrom` function to compare the JOIN keys. ```sql SELECT A.name, B.score FROM A LEFT JOIN B ON isNotDistinctFrom(A.id, B.id) ``` ``` namescore Alice 90 Bob 0 Charlie 88 ``` `ASOF JOIN` is useful when you need to join records that have no exact match. Algorithm requires the special column in tables. This column: Must contain an ordered sequence. Can be one of the following types: , , , , . Cant be the only column in the `JOIN` clause. Syntax `ASOF JOIN ... ON`: ``` sql SELECT expressions_list FROM table_1 ASOF LEFT JOIN table_2 ON equicond AND closestmatch_cond ``` You can use any number of equality conditions and exactly one closest match condition. For example, `SELECT count() FROM table1 ASOF LEFT JOIN table2 ON table1.a == table2.b AND table2.t <= table1.t`. Conditions supported for the closest match: `>`, `>=`, `<`, `<=`. Syntax `ASOF JOIN ... USING`: ``` sql SELECT expressions_list FROM table_1 ASOF JOIN table_2 USING (equicolumn1, ... equicolumnN, asof_column) ``` `ASOF JOIN` uses `equicolumnX` for joining on equality and `asofcolumn` for joining on the closest match with the `table1.asofcolumn >= table2.asofcolumn` condition. The `asof_column` column is always the last one in the `USING`

For example, consider the following tables: table1 table2 event | evtime | userid event | evtime | userid -||- -||- ... ... event11 | 12:00 | 42 event21 | 11:59 | 42 ... event22 | 12:30 | 42 event12 | 13:00 | 42 event23 | 13:00 | 42 ... ... `ASOF JOIN` can take the timestamp of a user event from `table1` and find an event in `table2` where the timestamp is closest to the timestamp of the event from `table1` corresponding to the closest match condition. Equal timestamp values are the closest if available. Here, the `userid` column can be used for joining on equality and the `evtime` column can be used for joining on the closest match. In our example, `event11` can be joined with `event21` and `event12` can be joined with `event23`, but `event2_2` cant be joined. :::note `ASOF` join is not supported in the table engine. ::: The result of `PASTE JOIN` is a table that contains all columns from left subquery followed by all columns from the right subquery. The rows are matched based on their positions in the original tables (the order of rows should be defined). If the subqueries return a different number of rows, extra rows will be cut. Example: ```SQL SELECT * FROM ( SELECT number AS a FROM numbers(2) ) AS t1 PASTE JOIN ( SELECT number AS a FROM numbers(2) ORDER BY a DESC ) AS t2 at2.a 0 1 1 0 ``` Note: In this case result can be nondeterministic if the reading is parallel. Example: ```SQL SELECT * FROM ( SELECT number AS a FROM numbers_mt(5) ) AS t1 PASTE JOIN ( SELECT number AS a FROM numbers(10) ORDER BY a DESC ) AS t2 SETTINGS maxblocksize = 2; at2.a 2 9 3 8 at2.a 0 7 1 6 at2.a 4 5 ``` There are two ways to execute join involving distributed tables: When using a normal `JOIN`, the query is sent to remote servers. Subqueries are run on each of them in order to make the right table, and the join is performed with this table. In other words, the right table is formed on each server separately. When using `GLOBAL ... JOIN`, first the requestor server runs a subquery to calculate the right table. This temporary table is passed to each remote server, and queries are run on them using the temporary data that was transmitted. Be careful when using `GLOBAL`. For more information, see the section. `INNER JOIN`, `LEFT JOIN`, `RIGHT JOIN`, and `FULL JOIN` queries support the implicit type conversion for "join keys". However the query can not be executed, if join keys from the left and the right tables cannot be converted to a single type (for example, there is no data type that can hold all values from both `UInt64` and `Int64`, or `String` and

Example Consider the table `t_1`: ```text abtoTypeName(a)toTypeName(b) 1 1 UInt16 UInt8 2 2 UInt16 UInt8 ``` and the table `t_2`: ```text abtoTypeName(a)toTypeName(b) -1 1 Int16 Nullable(Int64) 1 -1 Int16 Nullable(Int64) 1 1 Int16 Nullable(Int64) ``` The query ```sql SELECT a, b, toTypeName(a), toTypeName(b) FROM t1 FULL JOIN t2 USING (a, b); ``` returns the set: ```text abtoTypeName(a)toTypeName(b) 1 1 Int32 Nullable(Int64) 2 2 Int32 Nullable(Int64) -1 1 Int32 Nullable(Int64) 1 -1 Int32 Nullable(Int64) ``` While joining tables, the empty cells may appear. The setting define how ClickHouse fills these cells. If the `JOIN` keys are fields, the rows where at least one of the keys has the value are not joined. The columns specified in `USING` must have the same names in both subqueries, and the other columns must be named differently. You can use aliases to change the names of columns in subqueries. The `USING` clause specifies one or more columns to join, which establishes the equality of these columns. The list of columns is set without brackets. More complex join conditions are not supported. For multiple `JOIN` clauses in a single `SELECT` query: Taking all the columns via `*` is available only if tables are joined, not subqueries. The `PREWHERE` clause is not available. The `USING` clause is not available. For `ON`, `WHERE`, and `GROUP BY` clauses: Arbitrary expressions cannot be used in `ON`, `WHERE`, and `GROUP BY` clauses, but you can define an expression in a `SELECT` clause and then use it in these clauses via an alias. When running a `JOIN`, there is no optimization of the order of execution in relation to other stages of the query. The join (a search in the right table) is run before filtering in `WHERE` and before aggregation. Each time a query is run with the same `JOIN`, the subquery is run again because the result is not cached. To avoid this, use the special table engine, which is a prepared array for joining that is always in RAM. In some cases, it is more efficient to use instead of `JOIN`. If you need a `JOIN` for joining with dimension tables (these are relatively small tables that contain dimension properties, such as names for advertising campaigns), a `JOIN` might not be very convenient due to the fact that the right table is re-accessed for every query. For such cases, there is a dictionaries feature that you should use instead of `JOIN`. For more information, see the section. By default, ClickHouse uses the algorithm. ClickHouse takes the righttable and creates a hash table for it in RAM. If `joinalgorithm = 'auto'` is enabled, then after some threshold of memory consumption, ClickHouse falls back to join algorithm. For `JOIN` algorithms description see the setting. If you need to restrict `JOIN` operation memory consumption use the following settings: Limits number of rows in the hash table. Limits size of the hash table. When any of these limits is reached, ClickHouse acts as the setting instructs. Example: ``` sql SELECT CounterID, hits, visits FROM ( SELECT CounterID, count() AS hits FROM test.hits GROUP BY CounterID ) ANY LEFT JOIN ( SELECT CounterID, sum(Sign) AS visits FROM test.visits GROUP BY CounterID ) USING CounterID ORDER BY hits DESC LIMIT 10 ``` ``` text CounterIDhitsvisits 1143050 523264 13665 731962 475698 102716 722545 337212 108187 722889 252197 10547 2237260 196036 9522 23057320 147211 7689 722818 90109 17847 48221 85379 4652 19762435 77807 7026 722884 77492 11056 ```