mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Merge remote-tracking branch 'upstream/master' into fix23
This commit is contained in:
commit
86d9876221
@ -498,6 +498,15 @@ bool DataTypeArray::equals(const IDataType & rhs) const
|
||||
}
|
||||
|
||||
|
||||
size_t DataTypeArray::getNumberOfDimensions() const
|
||||
{
|
||||
const DataTypeArray * nested_array = typeid_cast<const DataTypeArray *>(nested.get());
|
||||
if (!nested_array)
|
||||
return 1;
|
||||
return 1 + nested_array->getNumberOfDimensions(); /// Every modern C++ compiler optimizes tail recursion.
|
||||
}
|
||||
|
||||
|
||||
static DataTypePtr create(const ASTPtr & arguments)
|
||||
{
|
||||
if (!arguments || arguments->children.size() != 1)
|
||||
|
@ -112,6 +112,9 @@ public:
|
||||
}
|
||||
|
||||
const DataTypePtr & getNestedType() const { return nested; }
|
||||
|
||||
/// 1 for plain array, 2 for array of arrays and so on.
|
||||
size_t getNumberOfDimensions() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
class FunctionArrayEnumerateDenseRanked : public FunctionArrayEnumerateRankedExtended<FunctionArrayEnumerateDenseRanked>
|
||||
{
|
||||
using Base = FunctionArrayEnumerateRankedExtended<FunctionArrayEnumerateDenseRanked>;
|
||||
|
@ -1,61 +1,53 @@
|
||||
#include <algorithm>
|
||||
#include <Columns/ColumnConst.h>
|
||||
#include "arrayEnumerateRanked.h"
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
ArraysDepths getArraysDepths(const ColumnsWithTypeAndName & arguments)
|
||||
{
|
||||
const size_t num_arguments = arguments.size();
|
||||
|
||||
DepthType clear_depth = 1;
|
||||
DepthType max_array_depth = 0;
|
||||
DepthTypes depths;
|
||||
|
||||
/// function signature is the following:
|
||||
/// f(c0, arr1, c1, arr2, c2, ...)
|
||||
///
|
||||
/// c0 is something called "clear_depth" here.
|
||||
/// cN... - how deep to look into the corresponding arrN, (called "depths" here)
|
||||
/// may be omitted - then it means "look at the full depth".
|
||||
|
||||
size_t array_num = 0;
|
||||
DepthType last_array_depth = 0;
|
||||
DepthType prev_array_depth = 0;
|
||||
for (size_t i = 0; i < num_arguments; ++i)
|
||||
{
|
||||
const auto type = arguments[i].type;
|
||||
const DataTypePtr & type = arguments[i].type;
|
||||
const DataTypeArray * type_array = typeid_cast<const DataTypeArray *>(type.get());
|
||||
|
||||
if (isArray(type))
|
||||
if (type_array)
|
||||
{
|
||||
if (depths.size() < array_num && last_array_depth)
|
||||
if (depths.size() < array_num && prev_array_depth)
|
||||
{
|
||||
depths.emplace_back(last_array_depth);
|
||||
last_array_depth = 0;
|
||||
depths.emplace_back(prev_array_depth);
|
||||
prev_array_depth = 0;
|
||||
}
|
||||
|
||||
DepthType depth = 0;
|
||||
auto sub_type = type;
|
||||
do
|
||||
{
|
||||
auto sub_type_array = typeid_cast<const DataTypeArray *>(sub_type.get());
|
||||
if (!sub_type_array)
|
||||
break;
|
||||
sub_type = sub_type_array->getNestedType();
|
||||
++depth;
|
||||
} while (isArray(sub_type));
|
||||
last_array_depth = depth;
|
||||
prev_array_depth = type_array->getNumberOfDimensions();
|
||||
++array_num;
|
||||
}
|
||||
|
||||
if (!arguments[i].column)
|
||||
continue;
|
||||
|
||||
const IColumn * non_const = nullptr;
|
||||
if (auto const_array_column = typeid_cast<const ColumnConst *>(arguments[i].column.get()))
|
||||
non_const = const_array_column->getDataColumnPtr().get();
|
||||
const auto array = typeid_cast<const ColumnArray *>(non_const ? non_const : arguments[i].column.get());
|
||||
|
||||
if (!array)
|
||||
else
|
||||
{
|
||||
const auto & depth_column = arguments[i].column;
|
||||
|
||||
if (depth_column && depth_column->isColumnConst())
|
||||
{
|
||||
auto value = depth_column->getInt(0);
|
||||
if (value <= 0)
|
||||
throw Exception(
|
||||
"Arguments for function arrayEnumerateUniqRanked/arrayEnumerateDenseRanked incorrect: depth ("
|
||||
+ std::to_string(value) + ") cant be less or equal 0.",
|
||||
UInt64 value = static_cast<const ColumnConst &>(*depth_column).getValue<UInt64>();
|
||||
if (!value)
|
||||
throw Exception("Incorrect arguments for function arrayEnumerateUniqRanked or arrayEnumerateDenseRanked: depth ("
|
||||
+ std::to_string(value) + ") cannot be less or equal 0.",
|
||||
ErrorCodes::BAD_ARGUMENTS);
|
||||
|
||||
if (i == 0)
|
||||
@ -65,17 +57,15 @@ ArraysDepths getArraysDepths(const ColumnsWithTypeAndName & arguments)
|
||||
else
|
||||
{
|
||||
if (depths.size() >= array_num)
|
||||
{
|
||||
throw Exception(
|
||||
"Arguments for function arrayEnumerateUniqRanked/arrayEnumerateDenseRanked incorrect: depth ("
|
||||
+ std::to_string(value) + ") for missing array.",
|
||||
throw Exception("Incorrect arguments for function arrayEnumerateUniqRanked or arrayEnumerateDenseRanked: depth ("
|
||||
+ std::to_string(value) + ") for missing array.",
|
||||
ErrorCodes::BAD_ARGUMENTS);
|
||||
}
|
||||
if (value > last_array_depth)
|
||||
if (value > prev_array_depth)
|
||||
throw Exception(
|
||||
"Arguments for function arrayEnumerateUniqRanked/arrayEnumerateDenseRanked incorrect: depth="
|
||||
+ std::to_string(value) + " for array with depth=" + std::to_string(last_array_depth) + ".",
|
||||
+ std::to_string(value) + " for array with depth=" + std::to_string(prev_array_depth) + ".",
|
||||
ErrorCodes::BAD_ARGUMENTS);
|
||||
|
||||
depths.emplace_back(value);
|
||||
}
|
||||
}
|
||||
@ -83,25 +73,19 @@ ArraysDepths getArraysDepths(const ColumnsWithTypeAndName & arguments)
|
||||
}
|
||||
|
||||
if (depths.size() < array_num)
|
||||
{
|
||||
depths.emplace_back(last_array_depth);
|
||||
}
|
||||
|
||||
for (auto & depth : depths)
|
||||
{
|
||||
if (max_array_depth < depth)
|
||||
max_array_depth = depth;
|
||||
}
|
||||
depths.emplace_back(prev_array_depth);
|
||||
|
||||
if (depths.empty())
|
||||
throw Exception(
|
||||
"Arguments for function arrayEnumerateUniqRanked/arrayEnumerateDenseRanked incorrect: At least one array should be passed.",
|
||||
throw Exception("Incorrect arguments for function arrayEnumerateUniqRanked or arrayEnumerateDenseRanked: at least one array should be passed.",
|
||||
ErrorCodes::BAD_ARGUMENTS);
|
||||
|
||||
DepthType max_array_depth = 0;
|
||||
for (auto depth : depths)
|
||||
max_array_depth = std::max(depth, max_array_depth);
|
||||
|
||||
if (clear_depth > max_array_depth)
|
||||
throw Exception(
|
||||
"Arguments for function arrayEnumerateUniqRanked/arrayEnumerateDenseRanked incorrect: clear_depth ("
|
||||
+ std::to_string(clear_depth) + ") cant be larger than max_array_depth (" + std::to_string(max_array_depth) + ").",
|
||||
throw Exception("Incorrect arguments for function arrayEnumerateUniqRanked or arrayEnumerateDenseRanked: clear_depth ("
|
||||
+ std::to_string(clear_depth) + ") cant be larger than max_array_depth (" + std::to_string(max_array_depth) + ").",
|
||||
ErrorCodes::BAD_ARGUMENTS);
|
||||
|
||||
return {clear_depth, depths, max_array_depth};
|
||||
|
@ -12,6 +12,47 @@
|
||||
#include <Common/HashTable/ClearableHashMap.h>
|
||||
|
||||
|
||||
/** The function will enumerate distinct values of the passed multidimensional arrays looking inside at the specified depths.
|
||||
* This is very unusual function made as a special order for Yandex.Metrica.
|
||||
*
|
||||
* arrayEnumerateUniqRanked(['hello', 'world', 'hello']) = [1, 1, 2]
|
||||
* - it returns similar structured array containing number of occurence of the corresponding value.
|
||||
*
|
||||
* arrayEnumerateUniqRanked([['hello', 'world'], ['hello'], ['hello']], 1) = [1, 1, 2]
|
||||
* - look at the depth 1 by default. Elements are ['hello', 'world'], ['hello'], ['hello'].
|
||||
*
|
||||
* arrayEnumerateUniqRanked([['hello', 'world'], ['hello'], ['hello']]) = [[1,1],[2],[3]]
|
||||
* - look at the depth 2. Return similar structured array.
|
||||
* arrayEnumerateUniqRanked([['hello', 'world'], ['hello'], ['hello']], 2) = [[1,1],[2],[3]]
|
||||
* - look at the maximum depth by default.
|
||||
*
|
||||
* We may pass multiple array arguments. Their elements will be processed as zipped to tuple.
|
||||
*
|
||||
* arrayEnumerateUniqRanked(['hello', 'hello', 'world', 'world'], ['a', 'b', 'b', 'b']) = [1, 1, 1, 2]
|
||||
*
|
||||
* We may provide arrays of different depths to look at different arguments.
|
||||
*
|
||||
* arrayEnumerateUniqRanked([['hello', 'world'], ['hello'], ['world'], ['world']], ['a', 'b', 'b', 'b']) = [[1,1],[1],[1],[2]]
|
||||
* arrayEnumerateUniqRanked([['hello', 'world'], ['hello'], ['world'], ['world']], 1, ['a', 'b', 'b', 'b'], 1) = [1, 1, 1, 2]
|
||||
*
|
||||
* When depths are different, we process less deep arrays as promoted to deeper arrays of similar structure by duplicating elements.
|
||||
*
|
||||
* arrayEnumerateUniqRanked(
|
||||
* [['hello', 'world'], ['hello'], ['world'], ['world']],
|
||||
* ['a', 'b', 'b', 'b'])
|
||||
* = arrayEnumerateUniqRanked(
|
||||
* [['hello', 'world'], ['hello'], ['world'], ['world']],
|
||||
* [['a', 'a'], ['b'], ['b'], ['b']])
|
||||
*
|
||||
* Finally, we can provide extra first argument named "clear_depth" (it can be considered as 1 by default).
|
||||
* Array elements at the clear_depth will be enumerated as separate elements (enumeration counter is reset for each new element).
|
||||
*
|
||||
* SELECT arrayEnumerateUniqRanked(1, [['hello', 'world'], ['hello'], ['world'], ['world']]) = [[1,1],[2],[2],[3]]
|
||||
* SELECT arrayEnumerateUniqRanked(2, [['hello', 'world'], ['hello'], ['world'], ['world']]) = [[1,1],[1],[1],[1]]
|
||||
* SELECT arrayEnumerateUniqRanked(1, [['hello', 'world', 'hello'], ['hello'], ['world'], ['world']]) = [[1,1,2],[3],[2],[3]]
|
||||
* SELECT arrayEnumerateUniqRanked(2, [['hello', 'world', 'hello'], ['hello'], ['world'], ['world']]) = [[1,1,2],[1],[1],[1]]
|
||||
*/
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
@ -27,12 +68,21 @@ class FunctionArrayEnumerateDenseRanked;
|
||||
|
||||
using DepthType = uint32_t;
|
||||
using DepthTypes = std::vector<DepthType>;
|
||||
|
||||
struct ArraysDepths
|
||||
{
|
||||
/// Enumerate elements at the specified level separately.
|
||||
DepthType clear_depth;
|
||||
|
||||
/// Effective depth is the array depth by default or lower value, specified as a constant argument following the array.
|
||||
/// f([[1, 2], [3]]) - effective depth is 2.
|
||||
/// f([[1, 2], [3]], 1) - effective depth is 1.
|
||||
DepthTypes depths;
|
||||
|
||||
/// Maximum effective depth.
|
||||
DepthType max_array_depth;
|
||||
};
|
||||
|
||||
/// Return depth info about passed arrays
|
||||
ArraysDepths getArraysDepths(const ColumnsWithTypeAndName & arguments);
|
||||
|
||||
@ -55,7 +105,9 @@ public:
|
||||
+ ", should be at least 1.",
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
|
||||
const auto & arrays_depths = getArraysDepths(arguments);
|
||||
const ArraysDepths arrays_depths = getArraysDepths(arguments);
|
||||
|
||||
/// Return type is the array of the depth as the maximum effective depth of arguments, containing UInt32.
|
||||
|
||||
DataTypePtr type = std::make_shared<DataTypeUInt32>();
|
||||
for (DepthType i = 0; i < arrays_depths.max_array_depth; ++i)
|
||||
@ -79,15 +131,15 @@ private:
|
||||
|
||||
|
||||
/// Hash a set of keys into a UInt128 value.
|
||||
static inline UInt128 ALWAYS_INLINE hash128depths(const std::vector<size_t> & indexes, const ColumnRawPtrs & key_columns)
|
||||
static inline UInt128 ALWAYS_INLINE hash128depths(const std::vector<size_t> & indices, const ColumnRawPtrs & key_columns)
|
||||
{
|
||||
UInt128 key;
|
||||
SipHash hash;
|
||||
|
||||
for (size_t j = 0, keys_size = key_columns.size(); j < keys_size; ++j)
|
||||
{
|
||||
// Debug: const auto & field = (*key_columns[j])[indexes[j]]; DUMP(j, indexes[j], field);
|
||||
key_columns[j]->updateHashWithValue(indexes[j], hash);
|
||||
// Debug: const auto & field = (*key_columns[j])[indices[j]]; DUMP(j, indices[j], field);
|
||||
key_columns[j]->updateHashWithValue(indices[j], hash);
|
||||
}
|
||||
|
||||
hash.get128(key.low, key.high);
|
||||
@ -111,9 +163,11 @@ void FunctionArrayEnumerateRankedExtended<Derived>::executeImpl(
|
||||
for (size_t i = 0; i < arguments.size(); ++i)
|
||||
args.emplace_back(block.getByPosition(arguments[i]));
|
||||
|
||||
const auto & arrays_depths = getArraysDepths(args);
|
||||
const ArraysDepths arrays_depths = getArraysDepths(args);
|
||||
|
||||
auto get_array_column = [&](const auto & column) -> const DB::ColumnArray * {
|
||||
/// If the column is Array - return it. If the const Array - materialize it, keep ownership and return.
|
||||
auto get_array_column = [&](const auto & column) -> const DB::ColumnArray *
|
||||
{
|
||||
const ColumnArray * array = checkAndGetColumn<ColumnArray>(column);
|
||||
if (!array)
|
||||
{
|
||||
@ -146,7 +200,7 @@ void FunctionArrayEnumerateRankedExtended<Derived>::executeImpl(
|
||||
if (*offsets_by_depth[0] != array->getOffsets())
|
||||
{
|
||||
throw Exception(
|
||||
"Lengths and depths of all arrays passed to " + getName() + " must be equal.",
|
||||
"Lengths and effective depths of all arrays passed to " + getName() + " must be equal.",
|
||||
ErrorCodes::SIZES_OF_ARRAYS_DOESNT_MATCH);
|
||||
}
|
||||
}
|
||||
@ -170,7 +224,7 @@ void FunctionArrayEnumerateRankedExtended<Derived>::executeImpl(
|
||||
if (*offsets_by_depth[col_depth] != array->getOffsets())
|
||||
{
|
||||
throw Exception(
|
||||
"Lengths and depths of all arrays passed to " + getName() + " must be equal.",
|
||||
"Lengths and effective depths of all arrays passed to " + getName() + " must be equal.",
|
||||
ErrorCodes::SIZES_OF_ARRAYS_DOESNT_MATCH);
|
||||
}
|
||||
}
|
||||
@ -180,7 +234,7 @@ void FunctionArrayEnumerateRankedExtended<Derived>::executeImpl(
|
||||
{
|
||||
throw Exception(
|
||||
getName() + ": Passed array number " + std::to_string(array_num) + " depth ("
|
||||
+ std::to_string(arrays_depths.depths[array_num]) + ") more than actual array depth (" + std::to_string(col_depth)
|
||||
+ std::to_string(arrays_depths.depths[array_num]) + ") is more than the actual array depth (" + std::to_string(col_depth)
|
||||
+ ").",
|
||||
ErrorCodes::SIZES_OF_ARRAYS_DOESNT_MATCH);
|
||||
}
|
||||
@ -251,6 +305,7 @@ void FunctionArrayEnumerateRankedExtended<Derived>::executeMethodImpl(
|
||||
const ArraysDepths & arrays_depths,
|
||||
ColumnUInt32::Container & res_values)
|
||||
{
|
||||
/// Offsets at the depth we want to look.
|
||||
const size_t current_offset_depth = arrays_depths.max_array_depth;
|
||||
const auto & offsets = *offsets_by_depth[current_offset_depth - 1];
|
||||
|
||||
@ -264,22 +319,24 @@ void FunctionArrayEnumerateRankedExtended<Derived>::executeMethodImpl(
|
||||
HashTableAllocatorWithStackMemory<(1ULL << INITIAL_SIZE_DEGREE) * sizeof(UInt128)>>;
|
||||
Map indices;
|
||||
|
||||
std::vector<size_t> indexes_by_depth(arrays_depths.max_array_depth);
|
||||
std::vector<size_t> indices_by_depth(arrays_depths.max_array_depth);
|
||||
std::vector<size_t> current_offset_n_by_depth(arrays_depths.max_array_depth);
|
||||
|
||||
UInt32 rank = 0;
|
||||
|
||||
std::vector<size_t> columns_indexes(columns.size());
|
||||
std::vector<size_t> columns_indices(columns.size());
|
||||
|
||||
for (size_t off : offsets)
|
||||
{
|
||||
bool want_clear = false;
|
||||
|
||||
/// For each element at the depth we want to look.
|
||||
for (size_t j = prev_off; j < off; ++j)
|
||||
{
|
||||
for (size_t col_n = 0; col_n < columns.size(); ++col_n)
|
||||
columns_indexes[col_n] = indexes_by_depth[arrays_depths.depths[col_n] - 1];
|
||||
columns_indices[col_n] = indices_by_depth[arrays_depths.depths[col_n] - 1];
|
||||
|
||||
auto hash = hash128depths(columns_indexes, columns);
|
||||
auto hash = hash128depths(columns_indices, columns);
|
||||
|
||||
if constexpr (std::is_same_v<Derived, FunctionArrayEnumerateUniqRanked>)
|
||||
{
|
||||
@ -297,13 +354,13 @@ void FunctionArrayEnumerateRankedExtended<Derived>::executeMethodImpl(
|
||||
res_values[j] = idx;
|
||||
}
|
||||
|
||||
// Debug: DUMP(off, prev_off, j, columns_indexes, res_values[j], columns);
|
||||
// Debug: DUMP(off, prev_off, j, columns_indices, res_values[j], columns);
|
||||
|
||||
for (int depth = current_offset_depth - 1; depth >= 0; --depth)
|
||||
{
|
||||
++indexes_by_depth[depth];
|
||||
++indices_by_depth[depth];
|
||||
|
||||
if (indexes_by_depth[depth] == (*offsets_by_depth[depth])[current_offset_n_by_depth[depth]])
|
||||
if (indices_by_depth[depth] == (*offsets_by_depth[depth])[current_offset_n_by_depth[depth]])
|
||||
{
|
||||
if (static_cast<int>(arrays_depths.clear_depth) == depth + 1)
|
||||
want_clear = true;
|
||||
@ -315,6 +372,7 @@ void FunctionArrayEnumerateRankedExtended<Derived>::executeMethodImpl(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (want_clear)
|
||||
{
|
||||
want_clear = false;
|
||||
|
@ -178,5 +178,3 @@ arrayEnumerateUniq(a1, a2) =
|
||||
[1,2]
|
||||
[1,1]
|
||||
[[[[[[[[[[1]]]]]]]]]]
|
||||
[1,2,1,3]
|
||||
[1,2,1,3]
|
||||
|
@ -170,13 +170,13 @@ SELECT arrayEnumerateUniqRanked([1,2], 1, 2); -- { serverError 36 }
|
||||
SELECT arrayEnumerateUniqRanked([1,2], 1, 3, 4, 5); -- { serverError 36 }
|
||||
SELECT arrayEnumerateUniqRanked([1,2], 1, 3, [4], 5); -- { serverError 36 }
|
||||
SELECT arrayEnumerateDenseRanked([[[[[[[[[[42]]]]]]]]]]);
|
||||
SELECT arrayEnumerateUniqRanked('wat', [1,2]); -- { serverError 48 }
|
||||
SELECT arrayEnumerateUniqRanked(1, [1,2], 'boom'); -- { serverError 48 }
|
||||
SELECT arrayEnumerateDenseRanked(['\0'], -8363126); -- { serverError 36 }
|
||||
SELECT arrayEnumerateDenseRanked(-10, ['\0'], -8363126); -- { serverError 36 }
|
||||
SELECT arrayEnumerateDenseRanked(1, ['\0'], -8363126); -- { serverError 36 }
|
||||
SELECT arrayEnumerateDenseRanked(-101, ['\0']); -- { serverError 36 }
|
||||
SELECT arrayEnumerateDenseRanked(1.1, [10,20,10,30]);
|
||||
SELECT arrayEnumerateDenseRanked([10,20,10,30], 0.4); -- { serverError 36 }
|
||||
SELECT arrayEnumerateDenseRanked([10,20,10,30], 1.8);
|
||||
SELECT arrayEnumerateUniqRanked('wat', [1,2]); -- { serverError 170 }
|
||||
SELECT arrayEnumerateUniqRanked(1, [1,2], 'boom'); -- { serverError 170 }
|
||||
SELECT arrayEnumerateDenseRanked(['\0'], -8363126); -- { serverError 170 }
|
||||
SELECT arrayEnumerateDenseRanked(-10, ['\0'], -8363126); -- { serverError 170 }
|
||||
SELECT arrayEnumerateDenseRanked(1, ['\0'], -8363126); -- { serverError 170 }
|
||||
SELECT arrayEnumerateDenseRanked(-101, ['\0']); -- { serverError 170 }
|
||||
SELECT arrayEnumerateDenseRanked(1.1, [10,20,10,30]); -- { serverError 170 }
|
||||
SELECT arrayEnumerateDenseRanked([10,20,10,30], 0.4); -- { serverError 170 }
|
||||
SELECT arrayEnumerateDenseRanked([10,20,10,30], 1.8); -- { serverError 170 }
|
||||
SELECT arrayEnumerateUniqRanked(1, [], 1000000000); -- { serverError 36 }
|
||||
|
@ -31,5 +31,4 @@ For more information about queries related to partition manipulations, see the [
|
||||
|
||||
A third-party tool is available to automate this approach: [clickhouse-backup](https://github.com/AlexAkulov/clickhouse-backup).
|
||||
|
||||
|
||||
[Original article](https://clickhouse.yandex/docs/en/operations/backup/) <!--hide-->
|
||||
|
@ -14,7 +14,6 @@ ClickHouse может принимать (`INSERT`) и отдавать (`SELECT
|
||||
[CSVWithNames](#csvwithnames) | ✔ | ✔ |
|
||||
[Values](#values) | ✔ | ✔ |
|
||||
[Vertical](#vertical) | ✗ | ✔ |
|
||||
[VerticalRaw](#verticalraw) | ✗ | ✔ |
|
||||
[JSON](#json) | ✗ | ✔ |
|
||||
[JSONCompact](#jsoncompact) | ✗ | ✔ |
|
||||
[JSONEachRow](#jsoneachrow) | ✔ | ✔ |
|
||||
@ -354,10 +353,22 @@ SELECT * FROM t_null
|
||||
└───┴──────┘
|
||||
```
|
||||
|
||||
В форматах `Pretty*` строки выводятся без экранирования. Ниже приведен пример для формата [PrettyCompact](#prettycompact):
|
||||
|
||||
``` sql
|
||||
SELECT 'String with \'quotes\' and \t character' AS Escaping_test
|
||||
```
|
||||
|
||||
```
|
||||
┌─Escaping_test────────────────────────┐
|
||||
│ String with 'quotes' and character │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Для защиты от вываливания слишком большого количества данных в терминал, выводится только первые 10 000 строк. Если строк больше или равно 10 000, то будет написано "Showed first 10 000."
|
||||
Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу).
|
||||
|
||||
Формат Pretty поддерживает вывод тотальных значений (при использовании WITH TOTALS) и экстремальных значений (при настройке extremes выставленной в 1). В этих случаях, после основных данных выводятся тотальные значения, и экстремальные значения, в отдельных табличках. Пример (показан для формата PrettyCompact):
|
||||
Формат `Pretty` поддерживает вывод тотальных значений (при использовании WITH TOTALS) и экстремальных значений (при настройке extremes выставленной в 1). В этих случаях, после основных данных выводятся тотальные значения, и экстремальные значения, в отдельных табличках. Пример (показан для формата [PrettyCompact](#prettycompact)):
|
||||
|
||||
``` sql
|
||||
SELECT EventDate, count() AS c FROM test.hits GROUP BY EventDate WITH TOTALS ORDER BY EventDate FORMAT PrettyCompact
|
||||
@ -388,7 +399,7 @@ Extremes:
|
||||
|
||||
## PrettyCompact {#prettycompact}
|
||||
|
||||
Отличается от `Pretty` тем, что не рисуется сетка между строками - результат более компактный.
|
||||
Отличается от [Pretty](#pretty) тем, что не рисуется сетка между строками - результат более компактный.
|
||||
Этот формат используется по умолчанию в клиенте командной строки в интерактивном режиме.
|
||||
|
||||
## PrettyCompactMonoBlock {#prettycompactmonoblock}
|
||||
@ -433,6 +444,7 @@ FixedString представлены просто как последовате
|
||||
Array представлены как длина в формате varint (unsigned [LEB128](https://en.wikipedia.org/wiki/LEB128)), а затем элементы массива, подряд.
|
||||
|
||||
Для поддержки [NULL](../query_language/syntax.md#null-literal) перед каждым значением типа [Nullable](../data_types/nullable.md
|
||||
|
||||
## Values
|
||||
|
||||
Выводит каждую строку в скобках. Строки разделены запятыми. После последней строки запятой нет. Значения внутри скобок также разделены запятыми. Числа выводятся в десятичном виде без кавычек. Массивы выводятся в квадратных скобках. Строки, даты, даты-с-временем выводятся в кавычках. Правила экранирования и особенности парсинга аналогичны формату [TabSeparated](#tabseparated). При форматировании, лишние пробелы не ставятся, а при парсинге - допустимы и пропускаются (за исключением пробелов внутри значений типа массив, которые недопустимы). [NULL](../query_language/syntax.md) представляется как `NULL`.
|
||||
@ -459,34 +471,20 @@ x: 1
|
||||
y: ᴺᵁᴸᴸ
|
||||
```
|
||||
|
||||
Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу).
|
||||
В формате `Vertical` строки выводятся без экранирования. Например:
|
||||
|
||||
## VerticalRaw {#verticalraw}
|
||||
|
||||
Отличается от формата `Vertical` тем, что строки выводятся без экранирования.
|
||||
Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу).
|
||||
|
||||
Примеры:
|
||||
``` sql
|
||||
SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT Vertical
|
||||
```
|
||||
:) SHOW CREATE TABLE geonames FORMAT VerticalRaw;
|
||||
Row 1:
|
||||
──────
|
||||
statement: CREATE TABLE default.geonames ( geonameid UInt32, date Date DEFAULT CAST('2017-12-08' AS Date)) ENGINE = MergeTree(date, geonameid, 8192)
|
||||
|
||||
:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT VerticalRaw;
|
||||
```
|
||||
Row 1:
|
||||
──────
|
||||
test: string with 'quotes' and with some special
|
||||
test: string with 'quotes' and with some special
|
||||
characters
|
||||
```
|
||||
|
||||
Для сравнения - формат Vertical:
|
||||
```
|
||||
:) SELECT 'string with \'quotes\' and \t with some special \n characters' AS test FORMAT Vertical;
|
||||
Row 1:
|
||||
──────
|
||||
test: string with \'quotes\' and \t with some special \n characters
|
||||
```
|
||||
Этот формат подходит только для вывода результата выполнения запроса, но не для парсинга (приёма данных для вставки в таблицу).
|
||||
|
||||
## XML {#xml}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user