mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-21 09:10:48 +00:00
Done
This commit is contained in:
parent
9fa0b867f1
commit
ea9cf3a62f
@ -119,9 +119,6 @@ public:
|
||||
default_values_column = block.getByPosition(arguments[2]).column;
|
||||
}
|
||||
|
||||
// Field offset_field = (*block.getByPosition(arguments[1]).column)[0];
|
||||
// auto raw_value = safeGet<UInt64>(offset_field);
|
||||
|
||||
ColumnWithTypeAndName &source_column_name_and_type = block.getByPosition(arguments[0]);
|
||||
DataTypes types = {source_column_name_and_type.type};
|
||||
if (default_values_column)
|
||||
@ -140,72 +137,74 @@ public:
|
||||
default_values_column = castColumn(block.getByPosition(arguments[2]), result_type, context);
|
||||
}
|
||||
|
||||
auto column = result_type->createColumn();
|
||||
column->reserve(input_rows_count);
|
||||
|
||||
const DataTypePtr desired_type = std::make_shared<DataTypeInt64>();
|
||||
if (!block.getByPosition(arguments[1]).type->equals(*desired_type)) {
|
||||
offset_column = castColumn(offset_structure, desired_type, context);
|
||||
}
|
||||
|
||||
// with constant offset - insertRangeFrom
|
||||
if (is_constant_offset)
|
||||
{
|
||||
Int64 offset_value = offset_column->getInt(0);
|
||||
|
||||
if (offset_value > 0)
|
||||
{
|
||||
// insert shifted value
|
||||
if ((size_t)std::abs(offset_value) <= input_rows_count) {
|
||||
column->insertRangeFrom(*source_column, offset_value, input_rows_count - offset_value);
|
||||
// insert defaults into the end
|
||||
insertDefaults(column, input_rows_count - offset_value, default_values_column, offset_value);
|
||||
}
|
||||
} else if(offset_value < 0) {
|
||||
// insert defaults up to offset_value
|
||||
insertDefaults(column, input_rows_count - std::abs(offset_value), default_values_column, std::abs(offset_value));
|
||||
// insert range, where possible
|
||||
column->insertRangeFrom(*source_column, 0, input_rows_count - std::abs(offset_value));
|
||||
} else {
|
||||
// populate column with source values
|
||||
column->insertRangeFrom(*source_column, 0, input_rows_count);
|
||||
}
|
||||
if (isColumnConst(*source_column)) {
|
||||
auto column = result_type->createColumnConst(input_rows_count, (*source_column)[0]);
|
||||
block.getByPosition(result).column = std::move(column);
|
||||
} else {
|
||||
// with dynamic offset - handle row by row
|
||||
for (size_t row = 0; row < input_rows_count; row++)
|
||||
auto column = result_type->createColumn();
|
||||
column->reserve(input_rows_count);
|
||||
// with constant offset - insertRangeFrom
|
||||
if (is_constant_offset)
|
||||
{
|
||||
Int64 offset_value = offset_column->getInt(row);
|
||||
if (offset_value == 0) {
|
||||
column->insertFrom(*source_column, row);
|
||||
} else if (offset_value > 0) {
|
||||
size_t real_offset = row + offset_value;
|
||||
if (real_offset > input_rows_count) {
|
||||
if (default_values_column) {
|
||||
column->insertFrom(*default_values_column, row);
|
||||
} else {
|
||||
column->insertDefault();
|
||||
}
|
||||
} else {
|
||||
column->insertFrom(*column, real_offset);
|
||||
Int64 offset_value = offset_column->getInt(0);
|
||||
|
||||
if (offset_value > 0)
|
||||
{
|
||||
// insert shifted value
|
||||
if ((size_t)offset_value <= input_rows_count) {
|
||||
column->insertRangeFrom(*source_column, offset_value, input_rows_count - offset_value);
|
||||
}
|
||||
size_t row_count = (size_t)offset_value > input_rows_count ? input_rows_count : offset_value;
|
||||
insertDefaults(column, row_count, default_values_column, input_rows_count - row_count);
|
||||
} else if (offset_value < 0) {
|
||||
size_t row_count = (size_t)std::abs(offset_value) > input_rows_count ? input_rows_count : std::abs(offset_value);
|
||||
// insert defaults up to offset_value
|
||||
insertDefaults(column, row_count, default_values_column, 0);
|
||||
column->insertRangeFrom(*source_column, 0, input_rows_count - row_count);
|
||||
} else {
|
||||
// out of range
|
||||
if ((size_t)std::abs(offset_value) > row)
|
||||
{
|
||||
if (default_values_column) {
|
||||
column->insertFrom(*default_values_column, row);
|
||||
// populate column with source values
|
||||
column->insertRangeFrom(*source_column, 0, input_rows_count);
|
||||
}
|
||||
} else {
|
||||
// with dynamic offset - handle row by row
|
||||
for (size_t row = 0; row < input_rows_count; row++)
|
||||
{
|
||||
Int64 offset_value = offset_column->getInt(row);
|
||||
if (offset_value == 0) {
|
||||
column->insertFrom(*source_column, row);
|
||||
} else if (offset_value > 0) {
|
||||
size_t real_offset = row + offset_value;
|
||||
if (real_offset > input_rows_count) {
|
||||
if (default_values_column) {
|
||||
column->insertFrom(*default_values_column, row);
|
||||
} else {
|
||||
column->insertDefault();
|
||||
}
|
||||
} else {
|
||||
column->insertDefault();
|
||||
column->insertFrom(*column, real_offset);
|
||||
}
|
||||
} else {
|
||||
column->insertFrom(*column, row - std::abs(offset_value));
|
||||
// out of range
|
||||
if ((size_t)std::abs(offset_value) > row)
|
||||
{
|
||||
if (default_values_column) {
|
||||
column->insertFrom(*default_values_column, row);
|
||||
} else {
|
||||
column->insertDefault();
|
||||
}
|
||||
} else {
|
||||
column->insertFrom(*column, row - std::abs(offset_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
block.getByPosition(result).column = std::move(column);
|
||||
}
|
||||
|
||||
|
||||
block.getByPosition(result).column = std::move(column);
|
||||
}
|
||||
private:
|
||||
const Context & context;
|
||||
|
42
dbms/tests/queries/0_stateless/00957_neighbour.reference
Normal file
42
dbms/tests/queries/0_stateless/00957_neighbour.reference
Normal file
@ -0,0 +1,42 @@
|
||||
Result with different type
|
||||
0 1
|
||||
1 2
|
||||
2 -10
|
||||
Offset > block
|
||||
0 0
|
||||
1 0
|
||||
2 0
|
||||
Abs(Offset) > block
|
||||
0 0
|
||||
1 0
|
||||
2 0
|
||||
Positive offset
|
||||
0 1
|
||||
1 2
|
||||
2 0
|
||||
Negative offset
|
||||
0 1
|
||||
1 2
|
||||
2 0
|
||||
Positive offset with defaults
|
||||
0 2
|
||||
1 3
|
||||
2 12
|
||||
3 13
|
||||
Negative offset with defaults
|
||||
0 10
|
||||
1 11
|
||||
2 0
|
||||
3 1
|
||||
Positive offset with const defaults
|
||||
0 1
|
||||
1 2
|
||||
2 1000
|
||||
Negative offset with const defaults
|
||||
0 1000
|
||||
1 0
|
||||
2 1
|
||||
Constant column
|
||||
0 1000
|
||||
1 1000
|
||||
2 1000
|
30
dbms/tests/queries/0_stateless/00957_neighbour.sql
Normal file
30
dbms/tests/queries/0_stateless/00957_neighbour.sql
Normal file
@ -0,0 +1,30 @@
|
||||
-- no arguments
|
||||
select neighbour(); -- { serverError 42 }
|
||||
-- single argument
|
||||
select neighbour(1); -- { serverError 42 }
|
||||
-- greater than 3 arguments
|
||||
select neighbour(1,2,3,4); -- { serverError 42 }
|
||||
-- bad default value
|
||||
select neighbour(dummy, 1, 'hello'); -- { serverError 43 }
|
||||
-- types without common supertype (UInt64 and Int8)
|
||||
select number, neighbour(number, 1, -10) from numbers(3); -- { serverError 43 }
|
||||
select 'Result with different type';
|
||||
select toInt32(number) as n, neighbour(n, 1, -10) from numbers(3);
|
||||
select 'Offset > block';
|
||||
select number, neighbour(number, 10) from numbers(3);
|
||||
select 'Abs(Offset) > block';
|
||||
select number, neighbour(number, -10) from numbers(3);
|
||||
select 'Positive offset';
|
||||
select number, neighbour(number, 1) from numbers(3);
|
||||
select 'Negative offset';
|
||||
select number, neighbour(number, 1) from numbers(3);
|
||||
select 'Positive offset with defaults';
|
||||
select number, neighbour(number, 2, number + 10) from numbers(4);
|
||||
select 'Negative offset with defaults';
|
||||
select number, neighbour(number, -2, number + 10) from numbers(4);
|
||||
select 'Positive offset with const defaults';
|
||||
select number, neighbour(number, 1, 1000) from numbers(3);
|
||||
select 'Negative offset with const defaults';
|
||||
select number, neighbour(number, -1, 1000) from numbers(3);
|
||||
select 'Constant column';
|
||||
select number, neighbour(1000, 10) from numbers(3);
|
@ -1,12 +0,0 @@
|
||||
0 1
|
||||
1 0
|
||||
0 2
|
||||
1 0
|
||||
2 0
|
||||
0 0
|
||||
1 0
|
||||
0 2
|
||||
1 3
|
||||
2 4
|
||||
3 1000
|
||||
4 1000
|
@ -1,18 +0,0 @@
|
||||
-- no arguments
|
||||
select neighbour(); -- { serverError 42 }
|
||||
-- single argument
|
||||
select neighbour(1); -- { serverError 42 }
|
||||
-- greater than 3 arguments
|
||||
select neighbour(1,2,3,4); -- { serverError 42 }
|
||||
-- bad default value
|
||||
select neighbour(dummy, 1, 'hello'); -- { serverError 43 }
|
||||
-- single argument test
|
||||
select number, neighbour(number,1) from numbers(2);
|
||||
-- filling by column's default value
|
||||
select number, neighbour(number, 2) from numbers(3);
|
||||
-- offset is greater that block - should fill everything with defaults
|
||||
select number, neighbour(number, 5) from numbers(2);
|
||||
-- substitution by constant for missing values
|
||||
select number, neighbour(number, 2, 1000) from numbers(5);
|
||||
-- substitution by expression
|
||||
-- select number, neighbour(number, 2, number % 2) from numbers(5);
|
@ -311,6 +311,49 @@ Returns the ordinal number of the row in the data block. Different data blocks a
|
||||
|
||||
Returns the ordinal number of the row in the data block. This function only considers the affected data blocks.
|
||||
|
||||
## neighbour(column, offset\[, default_value\])
|
||||
|
||||
Returns value for `column`, in `offset` distance from current row.
|
||||
This function is a partial implementation of [window functions](https://en.wikipedia.org/wiki/SQL_window_function) LEAD() and LAG().
|
||||
|
||||
The result of the function depends on the affected data blocks and the order of data in the block.
|
||||
If you make a subquery with ORDER BY and call the function from outside the subquery, you can get the expected result.
|
||||
|
||||
If `offset` value is outside block bounds, a default value for `column` returned. If `default_value` is given, then it will be used.
|
||||
This function can be used to compute year-over-year metric value:
|
||||
|
||||
``` sql
|
||||
WITH toDate('2018-01-01') AS start_date
|
||||
SELECT
|
||||
toStartOfMonth(start_date + (number * 32)) AS month,
|
||||
toInt32(month) % 100 AS money,
|
||||
neighbour(money, -12) AS prev_year,
|
||||
round(prev_year / money, 2) AS year_over_year
|
||||
FROM numbers(16)
|
||||
```
|
||||
|
||||
```
|
||||
┌──────month─┬─money─┬─prev_year─┬─year_over_year─┐
|
||||
│ 2018-01-01 │ 32 │ 0 │ 0 │
|
||||
│ 2018-02-01 │ 63 │ 0 │ 0 │
|
||||
│ 2018-03-01 │ 91 │ 0 │ 0 │
|
||||
│ 2018-04-01 │ 22 │ 0 │ 0 │
|
||||
│ 2018-05-01 │ 52 │ 0 │ 0 │
|
||||
│ 2018-06-01 │ 83 │ 0 │ 0 │
|
||||
│ 2018-07-01 │ 13 │ 0 │ 0 │
|
||||
│ 2018-08-01 │ 44 │ 0 │ 0 │
|
||||
│ 2018-09-01 │ 75 │ 0 │ 0 │
|
||||
│ 2018-10-01 │ 5 │ 0 │ 0 │
|
||||
│ 2018-11-01 │ 36 │ 0 │ 0 │
|
||||
│ 2018-12-01 │ 66 │ 0 │ 0 │
|
||||
│ 2019-01-01 │ 97 │ 32 │ 0.33 │
|
||||
│ 2019-02-01 │ 28 │ 63 │ 2.25 │
|
||||
│ 2019-03-01 │ 56 │ 91 │ 1.62 │
|
||||
│ 2019-04-01 │ 87 │ 22 │ 0.25 │
|
||||
└────────────┴───────┴───────────┴────────────────┘
|
||||
```
|
||||
|
||||
|
||||
## runningDifference(x) {#other_functions-runningdifference}
|
||||
|
||||
Calculates the difference between successive row values in the data block.
|
||||
|
@ -288,6 +288,48 @@ SELECT
|
||||
## rowNumberInAllBlocks()
|
||||
Возвращает порядковый номер строки в блоке данных. Функция учитывает только задействованные блоки данных.
|
||||
|
||||
## neighbour(column, offset\[, default_value\])
|
||||
|
||||
Функция позволяет получить доступ к значению в колонке `column`, находящемуся на смещении `offset` относительно текущей строки.
|
||||
Является частичной реализацией [оконных функций](https://en.wikipedia.org/wiki/SQL_window_function) LEAD() и LAG().
|
||||
|
||||
Результат функции зависит от затронутых блоков данных и порядка данных в блоке.
|
||||
Если сделать подзапрос с ORDER BY и вызывать функцию извне подзапроса, можно будет получить ожидаемый результат.
|
||||
|
||||
Если значение `offset` выходит за пределы блока данных, то берётся значение по-умолчанию для колонки `column`. Если передан параметр `default_value`, то значение берётся из него.
|
||||
Например, эта функция может использоваться чтобы оценить year-over-year значение показателя:
|
||||
|
||||
``` sql
|
||||
WITH toDate('2018-01-01') AS start_date
|
||||
SELECT
|
||||
toStartOfMonth(start_date + (number * 32)) AS month,
|
||||
toInt32(month) % 100 AS money,
|
||||
neighbour(money, -12) AS prev_year,
|
||||
round(prev_year / money, 2) AS year_over_year
|
||||
FROM numbers(16)
|
||||
```
|
||||
|
||||
```
|
||||
┌──────month─┬─money─┬─prev_year─┬─year_over_year─┐
|
||||
│ 2018-01-01 │ 32 │ 0 │ 0 │
|
||||
│ 2018-02-01 │ 63 │ 0 │ 0 │
|
||||
│ 2018-03-01 │ 91 │ 0 │ 0 │
|
||||
│ 2018-04-01 │ 22 │ 0 │ 0 │
|
||||
│ 2018-05-01 │ 52 │ 0 │ 0 │
|
||||
│ 2018-06-01 │ 83 │ 0 │ 0 │
|
||||
│ 2018-07-01 │ 13 │ 0 │ 0 │
|
||||
│ 2018-08-01 │ 44 │ 0 │ 0 │
|
||||
│ 2018-09-01 │ 75 │ 0 │ 0 │
|
||||
│ 2018-10-01 │ 5 │ 0 │ 0 │
|
||||
│ 2018-11-01 │ 36 │ 0 │ 0 │
|
||||
│ 2018-12-01 │ 66 │ 0 │ 0 │
|
||||
│ 2019-01-01 │ 97 │ 32 │ 0.33 │
|
||||
│ 2019-02-01 │ 28 │ 63 │ 2.25 │
|
||||
│ 2019-03-01 │ 56 │ 91 │ 1.62 │
|
||||
│ 2019-04-01 │ 87 │ 22 │ 0.25 │
|
||||
└────────────┴───────┴───────────┴────────────────┘
|
||||
```
|
||||
|
||||
## runningDifference(x)
|
||||
Считает разницу между последовательными значениями строк в блоке данных.
|
||||
Возвращает 0 для первой строки и разницу с предыдущей строкой для каждой последующей строки.
|
||||
|
Loading…
Reference in New Issue
Block a user