第一行匹配条件,在第一行匹配其他条件之后
first row matching criteria, after first row matching other criteria
如何找到匹配条件的第一行并在第一行之后匹配其他条件?我可以很容易地通过连接来做到这一点,但希望避免连接(因此,大概使用 window 函数)。我正在使用 Snowflake(但如果您知道另一种方言的答案,我可以尝试翻译)。如果没有加入,我一直无法找到执行此操作的方法。
为清楚起见,假设我的数据是
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 行。
Snowflake 提供了非常强大的JavaScript user-defined table functions,可以在这里轻松使用。
这是代码...
让我们先创建数据
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);
然后我们引入一个 table 函数,它使用包含 col1
和 col2
的行,并且对于每一行 returns 一个 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 上过滤即可。
当然,您可以在这样的函数中表达任意复杂的逻辑。
如何找到匹配条件的第一行并在第一行之后匹配其他条件?我可以很容易地通过连接来做到这一点,但希望避免连接(因此,大概使用 window 函数)。我正在使用 Snowflake(但如果您知道另一种方言的答案,我可以尝试翻译)。如果没有加入,我一直无法找到执行此操作的方法。
为清楚起见,假设我的数据是
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 行。
Snowflake 提供了非常强大的JavaScript user-defined table functions,可以在这里轻松使用。
这是代码...
让我们先创建数据
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);
然后我们引入一个 table 函数,它使用包含 col1
和 col2
的行,并且对于每一行 returns 一个 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 上过滤即可。
当然,您可以在这样的函数中表达任意复杂的逻辑。