This commit is contained in:
Alexandr Krasheninnikov 2019-08-13 16:11:24 +03:00
parent 9fa0b867f1
commit ea9cf3a62f
7 changed files with 209 additions and 83 deletions

View File

@ -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,14 +137,17 @@ 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);
}
if (isColumnConst(*source_column)) {
auto column = result_type->createColumnConst(input_rows_count, (*source_column)[0]);
block.getByPosition(result).column = std::move(column);
} else {
auto column = result_type->createColumn();
column->reserve(input_rows_count);
// with constant offset - insertRangeFrom
if (is_constant_offset)
{
@ -156,16 +156,16 @@ public:
if (offset_value > 0)
{
// insert shifted value
if ((size_t)std::abs(offset_value) <= input_rows_count) {
if ((size_t)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);
}
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, 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));
insertDefaults(column, row_count, default_values_column, 0);
column->insertRangeFrom(*source_column, 0, input_rows_count - row_count);
} else {
// populate column with source values
column->insertRangeFrom(*source_column, 0, input_rows_count);
@ -203,10 +203,9 @@ public:
}
}
}
block.getByPosition(result).column = std::move(column);
}
}
private:
const Context & context;
};

View 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

View 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);

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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 для первой строки и разницу с предыдущей строкой для каждой последующей строки.