提交 b8d464aa 编写于 作者: C chertus

new consistent ANY JOIN (LEFT, INNER, RIGHT)

上级 2cafe933
......@@ -367,7 +367,7 @@ namespace
};
template <typename Map, typename KeyGetter>
struct Inserter<ASTTableJoin::Strictness::Any, Map, KeyGetter>
struct Inserter<ASTTableJoin::Strictness::RightAny, Map, KeyGetter>
{
static ALWAYS_INLINE void insert(const Join & join, Map & map, KeyGetter & key_getter, Block * stored_block, size_t i, Arena & pool)
{
......@@ -427,7 +427,16 @@ namespace
if (has_null_map && (*null_map)[i])
continue;
if constexpr (STRICTNESS == ASTTableJoin::Strictness::Asof)
if constexpr (STRICTNESS == ASTTableJoin::Strictness::Any)
{
constexpr bool mapped_one = std::is_same_v<typename Map::mapped_type, JoinStuff::MappedOne> ||
std::is_same_v<typename Map::mapped_type, JoinStuff::MappedOneFlagged>;
if constexpr (mapped_one)
Inserter<ASTTableJoin::Strictness::RightAny, Map, KeyGetter>::insert(join, map, key_getter, stored_block, i, pool);
else
Inserter<ASTTableJoin::Strictness::All, Map, KeyGetter>::insert(join, map, key_getter, stored_block, i, pool);
}
else if constexpr (STRICTNESS == ASTTableJoin::Strictness::Asof)
Inserter<STRICTNESS, Map, KeyGetter>::insert(join, map, key_getter, stored_block, i, pool, asof_column);
else
Inserter<STRICTNESS, Map, KeyGetter>::insert(join, map, key_getter, stored_block, i, pool);
......@@ -690,18 +699,25 @@ void addNotFoundRow(AddedColumns & added [[maybe_unused]], IColumn::Offset & cur
/// Joins right table columns which indexes are present in right_indexes using specified map.
/// Makes filter (1 if row presented in right table) and returns offsets to replicate (for ALL JOINS).
template <ASTTableJoin::Strictness STRICTNESS, bool _add_missing, typename KeyGetter, typename Map, bool _has_null_map>
template <ASTTableJoin::Kind KIND, ASTTableJoin::Strictness STRICTNESS, typename KeyGetter, typename Map, bool _has_null_map>
void NO_INLINE joinRightColumns(const Map & map, AddedColumns & added_columns)
{
constexpr bool is_any_join = STRICTNESS == ASTTableJoin::Strictness::Any;
constexpr bool is_all_join = STRICTNESS == ASTTableJoin::Strictness::All;
constexpr bool is_asof_join = STRICTNESS == ASTTableJoin::Strictness::Asof;
constexpr bool left_or_full = static_in_v<KIND, ASTTableJoin::Kind::Left, ASTTableJoin::Kind::Full>;
constexpr bool right = KIND == ASTTableJoin::Kind::Right;
constexpr bool _add_missing = left_or_full;
constexpr bool need_replication = is_all_join || (is_any_join && right);
size_t rows = added_columns.rows_to_add;
if constexpr (STRICTNESS == ASTTableJoin::Strictness::All)
added_columns.offsets_to_replicate = std::make_unique<IColumn::Offsets>(rows);
IColumn::Filter & filter = added_columns.filter;
Arena pool;
const IColumn * asof_column [[maybe_unused]] = nullptr;
if constexpr (STRICTNESS == ASTTableJoin::Strictness::Asof)
if constexpr (is_asof_join)
asof_column = extractAsofColumn(added_columns.key_columns);
auto key_getter = createKeyGetter<KeyGetter, STRICTNESS>(added_columns.key_columns, added_columns.key_sizes);
......@@ -721,13 +737,13 @@ void NO_INLINE joinRightColumns(const Map & map, AddedColumns & added_columns)
if (find_result.isFound())
{
auto & mapped = find_result.getMapped();
filter[i] = 1;
if constexpr (STRICTNESS == ASTTableJoin::Strictness::Asof)
if constexpr (is_asof_join)
{
const Join & join = added_columns.join;
if (const RowRef * found = mapped.findAsof(join.getAsofType(), join.getAsofInequality(), asof_column, i))
{
filter[i] = 1;
mapped.setUsed();
added_columns.appendFromBlock(*found->block, found->row_num);
}
......@@ -737,13 +753,37 @@ void NO_INLINE joinRightColumns(const Map & map, AddedColumns & added_columns)
addNotFoundRow<_add_missing>(added_columns, current_offset);
}
}
else if constexpr (STRICTNESS == ASTTableJoin::Strictness::All)
else if constexpr (is_all_join)
{
filter[i] = 1;
mapped.setUsed();
addFoundRowAll<Map>(mapped, added_columns, current_offset);
}
else
else if constexpr (is_any_join && right)
{
/// Use first appered left key + it needs left columns replication
if (mapped.setUsedOnce())
{
filter[i] = 1;
addFoundRowAll<Map>(mapped, added_columns, current_offset);
}
}
else if constexpr (is_any_join && KIND == ASTTableJoin::Kind::Inner)
{
/// Use first appered left key only
if (mapped.setUsedOnce())
{
filter[i] = 1;
added_columns.appendFromBlock(*mapped.block, mapped.row_num);
}
}
else if constexpr (is_any_join && KIND == ASTTableJoin::Kind::Full)
{
/// TODO
}
else /// ANY LEFT + old ANY (RightAny)
{
filter[i] = 1;
mapped.setUsed();
added_columns.appendFromBlock(*mapped.block, mapped.row_num);
}
......@@ -752,7 +792,7 @@ void NO_INLINE joinRightColumns(const Map & map, AddedColumns & added_columns)
addNotFoundRow<_add_missing>(added_columns, current_offset);
}
if constexpr (STRICTNESS == ASTTableJoin::Strictness::All)
if constexpr (need_replication)
(*added_columns.offsets_to_replicate)[i] = current_offset;
}
......@@ -762,12 +802,10 @@ void NO_INLINE joinRightColumns(const Map & map, AddedColumns & added_columns)
template <ASTTableJoin::Kind KIND, ASTTableJoin::Strictness STRICTNESS, typename KeyGetter, typename Map>
void joinRightColumnsSwitchNullability(const Map & map, AddedColumns & added_columns)
{
constexpr bool left_or_full = static_in_v<KIND, ASTTableJoin::Kind::Left, ASTTableJoin::Kind::Full>;
if (added_columns.null_map)
joinRightColumns<STRICTNESS, left_or_full, KeyGetter, Map, true>(map, added_columns);
joinRightColumns<KIND, STRICTNESS, KeyGetter, Map, true>(map, added_columns);
else
joinRightColumns<STRICTNESS, left_or_full, KeyGetter, Map, false>(map, added_columns);
joinRightColumns<KIND, STRICTNESS, KeyGetter, Map, false>(map, added_columns);
}
template <ASTTableJoin::Kind KIND, ASTTableJoin::Strictness STRICTNESS, typename Maps>
......@@ -799,6 +837,16 @@ void Join::joinBlockImpl(
const Block & block_with_columns_to_add,
const Maps & maps_) const
{
constexpr bool is_any_join = STRICTNESS == ASTTableJoin::Strictness::Any;
constexpr bool is_all_join = STRICTNESS == ASTTableJoin::Strictness::All;
constexpr bool is_asof_join = STRICTNESS == ASTTableJoin::Strictness::Asof;
constexpr bool right = KIND == ASTTableJoin::Kind::Right;
constexpr bool inner_or_right = static_in_v<KIND, ASTTableJoin::Kind::Inner, ASTTableJoin::Kind::Right>;
constexpr bool right_or_full = static_in_v<KIND, ASTTableJoin::Kind::Right, ASTTableJoin::Kind::Full>;
constexpr bool need_filter = (!is_all_join && inner_or_right) && !(is_any_join && right);
constexpr bool need_replication = is_all_join || (is_any_join && right);
/// Rare case, when keys are constant. To avoid code bloat, simply materialize them.
Columns materialized_columns;
ColumnRawPtrs key_columns = JoinCommon::temporaryMaterializeColumns(block, key_names_left, materialized_columns);
......@@ -813,7 +861,6 @@ void Join::joinBlockImpl(
* Because if they are constants, then in the "not joined" rows, they may have different values
* - default values, which can differ from the values of these constants.
*/
constexpr bool right_or_full = static_in_v<KIND, ASTTableJoin::Kind::Right, ASTTableJoin::Kind::Full>;
if constexpr (right_or_full)
{
materializeBlockInplace(block);
......@@ -828,25 +875,24 @@ void Join::joinBlockImpl(
* For ASOF, the last column is used as the ASOF column
*/
ColumnsWithTypeAndName extras;
if constexpr (STRICTNESS == ASTTableJoin::Strictness::Asof)
if constexpr (is_asof_join)
extras.push_back(right_table_keys.getByName(key_names_right.back()));
AddedColumns added_columns(sample_block_with_columns_to_add, block_with_columns_to_add, block, saved_block_sample,
extras, *this, key_columns, key_sizes, null_map);
if constexpr (need_replication)
added_columns.offsets_to_replicate = std::make_unique<IColumn::Offsets>(block.rows());
switchJoinRightColumns<KIND, STRICTNESS>(maps_, added_columns, type);
IColumn::Filter & row_filter = added_columns.filter;
for (size_t i = 0; i < added_columns.size(); ++i)
block.insert(added_columns.moveColumn(i));
/// Filter & insert missing rows
constexpr bool is_all_join = STRICTNESS == ASTTableJoin::Strictness::All;
constexpr bool inner_or_right = static_in_v<KIND, ASTTableJoin::Kind::Inner, ASTTableJoin::Kind::Right>;
std::vector<size_t> right_keys_to_replicate [[maybe_unused]];
if constexpr (!is_all_join && inner_or_right)
if constexpr (need_filter)
{
/// If ANY INNER | RIGHT JOIN - filter all the columns except the new ones.
for (size_t i = 0; i < existing_columns; ++i)
......@@ -883,16 +929,14 @@ void Join::joinBlockImpl(
ColumnPtr thin_column = filterWithBlanks(col.column, filter);
block.insert(correctNullability({thin_column, col.type, right_key.name}, is_nullable, null_map_filter));
if constexpr (is_all_join)
if constexpr (need_replication)
right_keys_to_replicate.push_back(block.getPositionByName(right_key.name));
}
}
if constexpr (is_all_join)
if constexpr (need_replication)
{
std::unique_ptr<IColumn::Offsets> & offsets_to_replicate = added_columns.offsets_to_replicate;
if (!offsets_to_replicate)
throw Exception("No data to filter columns", ErrorCodes::LOGICAL_ERROR);
/// If ALL ... JOIN - we replicate all the columns except the new ones.
for (size_t i = 0; i < existing_columns; ++i)
......@@ -982,7 +1026,7 @@ DataTypePtr Join::joinGetReturnType(const String & column_name) const
template <typename Maps>
void Join::joinGetImpl(Block & block, const String & column_name, const Maps & maps_) const
{
joinBlockImpl<ASTTableJoin::Kind::Left, ASTTableJoin::Strictness::Any>(
joinBlockImpl<ASTTableJoin::Kind::Left, ASTTableJoin::Strictness::RightAny>(
block, {block.getByPosition(0).name}, {sample_block_with_columns_to_add.getByName(column_name)}, maps_);
}
......@@ -999,9 +1043,10 @@ void Join::joinGet(Block & block, const String & column_name) const
checkTypeOfKey(block, right_table_keys);
if (kind == ASTTableJoin::Kind::Left && strictness == ASTTableJoin::Strictness::Any)
if ((strictness == ASTTableJoin::Strictness::Any || strictness == ASTTableJoin::Strictness::RightAny) &&
kind == ASTTableJoin::Kind::Left)
{
joinGetImpl(block, column_name, std::get<MapsAny>(maps));
joinGetImpl(block, column_name, std::get<MapsOne>(maps));
}
else
throw Exception("joinGet only supports StorageJoin of type Left Any", ErrorCodes::LOGICAL_ERROR);
......@@ -1039,7 +1084,7 @@ template <ASTTableJoin::Strictness STRICTNESS, typename Mapped>
struct AdderNonJoined;
template <typename Mapped>
struct AdderNonJoined<ASTTableJoin::Strictness::Any, Mapped>
struct AdderNonJoined<ASTTableJoin::Strictness::RightAny, Mapped>
{
static void add(const Mapped & mapped, size_t & rows_added, MutableColumns & columns_right)
{
......@@ -1053,6 +1098,17 @@ struct AdderNonJoined<ASTTableJoin::Strictness::Any, Mapped>
}
};
template <typename Mapped>
struct AdderNonJoined<ASTTableJoin::Strictness::Any, Mapped>
{
static void add(const Mapped & mapped, size_t & rows_added, MutableColumns & columns_right)
{
constexpr bool mapped_one = std::is_same_v<Mapped, JoinStuff::MappedOne> || std::is_same_v<Mapped, JoinStuff::MappedOneFlagged>;
if constexpr (!mapped_one)
AdderNonJoined<ASTTableJoin::Strictness::All, Mapped>::add(mapped, rows_added, columns_right);
}
};
template <typename Mapped>
struct AdderNonJoined<ASTTableJoin::Strictness::All, Mapped>
{
......
......@@ -45,6 +45,16 @@ struct WithFlags<T, true> : T
mutable std::atomic<bool> used {};
void setUsed() const { used.store(true, std::memory_order_relaxed); } /// Could be set simultaneously from different threads.
bool getUsed() const { return used; }
bool setUsedOnce() const
{
/// fast check to prevent heavy CAS with seq_cst order
if (used.load(std::memory_order_relaxed))
return false;
bool expected = false;
return used.compare_exchange_strong(expected, true);
}
};
template <typename T>
......@@ -55,13 +65,14 @@ struct WithFlags<T, false> : T
void setUsed() const {}
bool getUsed() const { return true; }
bool setUsedOnce() const { return true; }
};
using MappedAny = WithFlags<RowRef, false>;
using MappedAll = WithFlags<RowRefList, false>;
using MappedAnyFull = WithFlags<RowRef, true>;
using MappedAllFull = WithFlags<RowRefList, true>;
using MappedAsof = WithFlags<AsofRowRefs, false>;
using MappedOne = WithFlags<RowRef, false>;
using MappedAll = WithFlags<RowRefList, false>;
using MappedOneFlagged = WithFlags<RowRef, true>;
using MappedAllFlagged = WithFlags<RowRefList, true>;
using MappedAsof = WithFlags<AsofRowRefs, false>;
}
......@@ -265,13 +276,13 @@ public:
}
};
using MapsAny = MapsTemplate<JoinStuff::MappedAny>;
using MapsOne = MapsTemplate<JoinStuff::MappedOne>;
using MapsAll = MapsTemplate<JoinStuff::MappedAll>;
using MapsAnyFull = MapsTemplate<JoinStuff::MappedAnyFull>;
using MapsAllFull = MapsTemplate<JoinStuff::MappedAllFull>;
using MapsOneFlagged = MapsTemplate<JoinStuff::MappedOneFlagged>;
using MapsAllFlagged = MapsTemplate<JoinStuff::MappedAllFlagged>;
using MapsAsof = MapsTemplate<JoinStuff::MappedAsof>;
using MapsVariant = std::variant<MapsAny, MapsAll, MapsAnyFull, MapsAllFull, MapsAsof>;
using MapsVariant = std::variant<MapsOne, MapsAll, MapsOneFlagged, MapsAllFlagged, MapsAsof>;
private:
friend class NonJoinedBlockInputStream;
......
......@@ -540,7 +540,7 @@ void getArrayJoinedColumns(ASTPtr & query, SyntaxAnalyzerResult & result, const
}
}
void setJoinStrictness(ASTSelectQuery & select_query, JoinStrictness join_default_strictness, ASTTableJoin & out_table_join)
void setJoinStrictness(ASTSelectQuery & select_query, JoinStrictness join_default_strictness, bool old_any, ASTTableJoin & out_table_join)
{
const ASTTablesInSelectQueryElement * node = select_query.join();
if (!node)
......@@ -560,6 +560,9 @@ void setJoinStrictness(ASTSelectQuery & select_query, JoinStrictness join_defaul
DB::ErrorCodes::EXPECTED_ALL_OR_ANY);
}
if (old_any && table_join.strictness == ASTTableJoin::Strictness::Any)
table_join.strictness = ASTTableJoin::Strictness::RightAny;
out_table_join = table_join;
}
......@@ -628,13 +631,8 @@ void checkJoin(const ASTTablesInSelectQueryElement * join)
const auto & table_join = join->table_join->as<ASTTableJoin &>();
if (table_join.strictness == ASTTableJoin::Strictness::Any)
if (table_join.kind != ASTTableJoin::Kind::Left)
throw Exception("Old ANY INNER|RIGHT|FULL JOINs are disabled by default. Their logic would be changed. "
"Old logic is many-to-one for all kinds of ANY JOINs. It's equil to apply distinct for right table keys. "
"Default bahaviour is reserved for many-to-one LEFT JOIN, one-to-many RIGHT JOIN and one-to-one INNER JOIN. "
"It would be equal to apply distinct for keys to right, left and both tables respectively. "
"Set any_join_distinct_right_table_keys=1 to enable old bahaviour.",
ErrorCodes::NOT_IMPLEMENTED);
if (table_join.kind == ASTTableJoin::Kind::Full)
throw Exception("ANY FULL JOINs are not implemented.", ErrorCodes::NOT_IMPLEMENTED);
}
std::vector<const ASTFunction *> getAggregates(const ASTPtr & query)
......@@ -958,7 +956,8 @@ SyntaxAnalyzerResultPtr SyntaxAnalyzer::analyze(
/// Push the predicate expression down to the subqueries.
result.rewrite_subqueries = PredicateExpressionsOptimizer(select_query, settings, context).optimize();
setJoinStrictness(*select_query, settings.join_default_strictness, result.analyzed_join->table_join);
setJoinStrictness(*select_query, settings.join_default_strictness, settings.any_join_distinct_right_table_keys,
result.analyzed_join->table_join);
collectJoinedColumns(*result.analyzed_join, *select_query, source_columns_set, result.aliases);
}
......
......@@ -12,54 +12,33 @@
namespace DB
{
template <bool fill_right, typename ASTTableJoin::Strictness>
struct MapGetterImpl;
template <>
struct MapGetterImpl<false, ASTTableJoin::Strictness::Any>
{
using Map = Join::MapsAny;
};
template <>
struct MapGetterImpl<true, ASTTableJoin::Strictness::Any>
{
using Map = Join::MapsAnyFull;
};
template <>
struct MapGetterImpl<false, ASTTableJoin::Strictness::All>
{
using Map = Join::MapsAll;
};
template <>
struct MapGetterImpl<true, ASTTableJoin::Strictness::All>
{
using Map = Join::MapsAllFull;
};
template <bool fill_right>
struct MapGetterImpl<fill_right, ASTTableJoin::Strictness::Asof>
template <ASTTableJoin::Kind kind, typename ASTTableJoin::Strictness>
struct MapGetter;
template <> struct MapGetter<ASTTableJoin::Kind::Left, ASTTableJoin::Strictness::RightAny> { using Map = Join::MapsOne; };
template <> struct MapGetter<ASTTableJoin::Kind::Inner, ASTTableJoin::Strictness::RightAny> { using Map = Join::MapsOne; };
template <> struct MapGetter<ASTTableJoin::Kind::Right, ASTTableJoin::Strictness::RightAny> { using Map = Join::MapsOneFlagged; };
template <> struct MapGetter<ASTTableJoin::Kind::Full, ASTTableJoin::Strictness::RightAny> { using Map = Join::MapsOneFlagged; };
template <> struct MapGetter<ASTTableJoin::Kind::Left, ASTTableJoin::Strictness::Any> { using Map = Join::MapsOne; };
template <> struct MapGetter<ASTTableJoin::Kind::Inner, ASTTableJoin::Strictness::Any> { using Map = Join::MapsOneFlagged; };
template <> struct MapGetter<ASTTableJoin::Kind::Right, ASTTableJoin::Strictness::Any> { using Map = Join::MapsAllFlagged; };
template <> struct MapGetter<ASTTableJoin::Kind::Full, ASTTableJoin::Strictness::Any> { using Map = Join::MapsAllFlagged; };
template <> struct MapGetter<ASTTableJoin::Kind::Left, ASTTableJoin::Strictness::All> { using Map = Join::MapsAll; };
template <> struct MapGetter<ASTTableJoin::Kind::Inner, ASTTableJoin::Strictness::All> { using Map = Join::MapsAll; };
template <> struct MapGetter<ASTTableJoin::Kind::Right, ASTTableJoin::Strictness::All> { using Map = Join::MapsAllFlagged; };
template <> struct MapGetter<ASTTableJoin::Kind::Full, ASTTableJoin::Strictness::All> { using Map = Join::MapsAllFlagged; };
template <ASTTableJoin::Kind kind>
struct MapGetter<kind, ASTTableJoin::Strictness::Asof>
{
using Map = Join::MapsAsof;
};
template <ASTTableJoin::Kind KIND>
struct KindTrait
{
// Affects the Adder trait so that when the right part is empty, adding a default value on the left
static constexpr bool fill_left = static_in_v<KIND, ASTTableJoin::Kind::Left, ASTTableJoin::Kind::Full>;
// Affects the Map trait so that a `used` flag is attached to map slots in order to
// generate default values on the right when the left part is empty
static constexpr bool fill_right = static_in_v<KIND, ASTTableJoin::Kind::Right, ASTTableJoin::Kind::Full>;
};
template <ASTTableJoin::Kind kind, ASTTableJoin::Strictness strictness>
using Map = typename MapGetterImpl<KindTrait<kind>::fill_right, strictness>::Map;
static constexpr std::array<ASTTableJoin::Strictness, 3> STRICTNESSES = {
static constexpr std::array<ASTTableJoin::Strictness, 4> STRICTNESSES = {
ASTTableJoin::Strictness::RightAny,
ASTTableJoin::Strictness::Any,
ASTTableJoin::Strictness::All,
ASTTableJoin::Strictness::Asof
......@@ -81,7 +60,7 @@ inline bool joinDispatchInit(ASTTableJoin::Kind kind, ASTTableJoin::Strictness s
constexpr auto j = ij % STRICTNESSES.size();
if (kind == KINDS[i] && strictness == STRICTNESSES[j])
{
maps = Map<KINDS[i], STRICTNESSES[j]>();
maps = typename MapGetter<KINDS[i], STRICTNESSES[j]>::Map();
return true;
}
return false;
......@@ -103,7 +82,7 @@ inline bool joinDispatch(ASTTableJoin::Kind kind, ASTTableJoin::Strictness stric
func(
std::integral_constant<ASTTableJoin::Kind, KINDS[i]>(),
std::integral_constant<ASTTableJoin::Strictness, STRICTNESSES[j]>(),
std::get<Map<KINDS[i], STRICTNESSES[j]>>(maps));
std::get<typename MapGetter<KINDS[i], STRICTNESSES[j]>::Map>(maps));
return true;
}
return false;
......
......@@ -140,6 +140,7 @@ void ASTTableJoin::formatImplBeforeTable(const FormatSettings & settings, Format
{
case Strictness::Unspecified:
break;
case Strictness::RightAny:
case Strictness::Any:
settings.ostr << "ANY ";
break;
......
......@@ -74,7 +74,8 @@ struct ASTTableJoin : public IAST
enum class Strictness
{
Unspecified,
Any, /// If there are many suitable rows to join, use any from them (also known as unique JOIN).
RightAny, /// Right ANY. If there are many suitable rows in right table, use any from them to join.
Any, /// Semi Join with any value from filtering table. For LEFT JOIN with Any and RightAny are the same.
All, /// If there are many suitable rows to join, use all of them and replicate rows of "left" table (usual semantic of JOIN).
Asof, /// For the last JOIN column, pick the latest value
};
......
......@@ -99,7 +99,7 @@ void registerStorageJoin(StorageFactory & factory)
const String strictness_str = Poco::toLower(*opt_strictness_id);
ASTTableJoin::Strictness strictness;
if (strictness_str == "any")
strictness = ASTTableJoin::Strictness::Any;
strictness = ASTTableJoin::Strictness::RightAny;
else if (strictness_str == "all")
strictness = ASTTableJoin::Strictness::All;
else
......@@ -329,7 +329,7 @@ private:
for (; it != end; ++it)
{
if constexpr (STRICTNESS == ASTTableJoin::Strictness::Any)
if constexpr (STRICTNESS == ASTTableJoin::Strictness::RightAny)
{
for (size_t j = 0; j < columns.size(); ++j)
if (j == key_pos)
......@@ -338,6 +338,11 @@ private:
columns[j]->insertFrom(*it->getSecond().block->getByPosition(column_indices[j]).column.get(), it->getSecond().row_num);
++rows_added;
}
else if constexpr (STRICTNESS == ASTTableJoin::Strictness::Any)
{
throw Exception("New ANY join storage is not implemented yet (set any_join_distinct_right_table_keys=1 to use old one)",
ErrorCodes::NOT_IMPLEMENTED);
}
else if constexpr (STRICTNESS == ASTTableJoin::Strictness::Asof)
{
throw Exception("ASOF join storage is not implemented yet", ErrorCodes::NOT_IMPLEMENTED);
......
any left
0 a1 0
1 a2 0
2 a3 2 b1
3 a4 0
4 a5 4 b3
any left (rev)
2 a3 2 b1
2 a3 2 b2
4 a5 4 b3
4 a5 4 b4
4 a5 4 b5
4 a5 4 b6
any inner
2 a3 2 b1
4 a5 4 b3
any inner (rev)
2 a3 2 b1
4 a5 4 b3
any right
2 a3 2 b1
2 a3 2 b2
4 a5 4 b3
4 a5 4 b4
4 a5 4 b5
4 a5 4 b6
any right (rev)
0 a1 0
1 a2 0
2 a3 2 b1
3 a4 0
4 a5 4 b3
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
CREATE TABLE t1 (x UInt32, s String) engine = Memory;
CREATE TABLE t2 (x UInt32, s String) engine = Memory;
INSERT INTO t1 (x, s) VALUES (0, 'a1'), (1, 'a2'), (2, 'a3'), (3, 'a4'), (4, 'a5');
INSERT INTO t2 (x, s) VALUES (2, 'b1'), (2, 'b2'), (4, 'b3'), (4, 'b4'), (4, 'b5'), (4, 'b6');
SET join_use_nulls = 0;
SET any_join_distinct_right_table_keys = 0;
SELECT 'any left';
SELECT t1.*, t2.* FROM t1 ANY LEFT JOIN t2 USING(x) ORDER BY t1.x, t2.x;
SELECT 'any left (rev)';
SELECT t1.*, t2.* FROM t2 ANY LEFT JOIN t1 USING(x) ORDER BY t1.x, t2.x;
SELECT 'any inner';
SELECT t1.*, t2.* FROM t1 ANY INNER JOIN t2 USING(x) ORDER BY t1.x, t2.x;
SELECT 'any inner (rev)';
SELECT t1.*, t2.* FROM t2 ANY INNER JOIN t1 USING(x) ORDER BY t1.x, t2.x;
SELECT 'any right';
SELECT t1.*, t2.* FROM t1 ANY RIGHT JOIN t2 USING(x) ORDER BY t1.x, t2.x;
SELECT 'any right (rev)';
SELECT t1.*, t2.* FROM t2 ANY RIGHT JOIN t1 USING(x) ORDER BY t1.x, t2.x;
DROP TABLE t1;
DROP TABLE t2;
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册