критерии соответствия первой строки, после соответствия первой строки другим критериям - PullRequest
0 голосов
/ 05 ноября 2018

Как мне найти первую строку, которая соответствует критериям и следует за первой строкой, чтобы соответствовать другим критериям? Я могу сделать это с помощью соединения достаточно легко, но хочу избежать объединения (и, таким образом, предположительно, использовать оконные функции). Я использую Снежинку (но если вы знаете ответ на другом диалекте, я могу попытаться перевести его). Я не смог найти способ сделать это без объединения.

Для ясности предположим, что мои данные

create table t (col1 varchar, col2 varchar, col3 varchar, row_number int) as
      select 'a', 'd' ,'r', 1
union select 'a', 'c', 'r', 2
union select 'b', 'd', 'r', 3
union select 'b', 'c', 's', 4
union select 'a', 'd', 's', 5
union select 'a', 'd', 'r', 6

Среди строк с col3='r' первая с col2='c' равна 2, а первая после этого с col1='a' равна 6. Я хочу выделить строку 6 на основе этих критериев.

1 Ответ

0 голосов
/ 06 ноября 2018

Snowflake предлагает очень мощные пользовательские табличные функции JavaScript , которые можно легко использовать здесь.

Вот код ...

Давайте сначала создадим данные

create or replace table t (col1 varchar, col2 varchar, col3 varchar, row_number int)
as select * from values
        ('a', 'd' ,'r', 1),
        ('a', 'c', 'r', 2),
        ('b', 'd', 'r', 3),
        ('b', 'c', 's', 4),
        ('a', 'd', 's', 5),
        ('a', 'd', 'r', 6);

Затем мы вводим табличную функцию, которая использует строки, содержащие col1 и col2, и для каждой строки возвращает столбец MATCH, содержащий true/false в зависимости от того, соответствует ли он вашему предикату

CREATE OR REPLACE FUNCTION myfunc (
        col1 varchar,
        col2 varchar)
RETURNS TABLE (MATCH boolean)
LANGUAGE JAVASCRIPT
AS $$
{
  seen: false,
  produced: false,
  processRow: function (row, rowWriter, context) {
        let match = false;
        if (!this.seen && row.COL2 == "c") {       
          this.seen = true;       
        } else if (this.seen && !this.produced && row.COL1 == "a") {          
          this.produced = true;   
          match = true;
        }
        rowWriter.writeRow({MATCH: match});
   },
   initialize: function (argumentInfo, context) {
     this.seen = this.produced = false;
   }
}   
$$;

И затем мы используем его, разбивая данные на col3 и проверяя, чтобы строки использовались вдоль row_number:

select * from t,
        table(myfunc(col1, col2) over (partition by col3 order by row_number));

------+------+------+------------+-------+
 COL1 | COL2 | COL3 | ROW_NUMBER | MATCH |
------+------+------+------------+-------+
 b    | c    | s    | 4          | FALSE |
 a    | d    | s    | 5          | TRUE  |
 a    | d    | r    | 1          | FALSE |
 a    | c    | r    | 2          | FALSE |
 b    | d    | r    | 3          | FALSE |
 a    | d    | r    | 6          | TRUE  |
------+------+------+------------+-------+

Если вам нужно, теперь вы можете просто отфильтровать по MATCH, и все готово.

Естественно, вы можете выражать произвольно сложную логику в такой функции, как эта.

...