使用 Snowflake SQL 如何找到两条记录,然后根据这些记录将另一条记录更改为使用局部变量的预定义记录?

Using Snowflake SQL how do you find two records and then change another one based on those records to a predefined record using a local variable?

使用 SQL 如何使用两条记录找到一个位置,保留该位置并使用该记录将 'Nonsense' 值替换为保留位置的值?我将展示到目前为止我能写的东西,然后写出我仍在努力弄清楚的东西:

SELECT * FROM "TABLES". "ACCTS_OF_SUPERHEROS".;

DECLARE @count_rows INT = 0;
DECLARE @row_total INT = 0;
DECLARE @refAcctNum INT = 0;
DECLARE @selectedPlaceName TINYTEXT;

SET @row_total = SELECT COUNT (*)

WHILE countRows < row_total
    for each acct_num store value in refAcctNum. 
    Using refAcctNum find place: "Gotham City", "Central City", "Metropolis", "Smallville", "Star City", "Fawcett City" store that in selectedPlaceName.
    If refAccountNumber has Nonsense then replace with selectedPlaceName record
    otherwise add + 1 to countRows and repeat. 
END

当前table数据; “ACCTS_OF_SUPERHEROS”table:

| row | acct_num | exact_address    | place
| --- | -------- |------------------|--------
| 1   | 049403   | 344 Clinton Str  | Metropolis 
| 2   | 049403   | 344 Clinton Str  | Nonsense
| 3   | 049206   | 1007 Mountain Dr | Gotham City
| 4   | 049206   | 1007 Mountain Dr | Gotham City
| 5   | 049206   | 1096 Show Dr.    | Fawcett City
| 6   | 049206   | 1096 Show Dr.    | Nonsense
| 7   | 049206   | NULL             | Nonsense
| 8   | 049291   | 1938 Sullivan Pl | Smallville
| 9   | 049293   | 700 Hamilton Str | Central City
| 10  | 049396   | 800 Nonsense Way | Nonsense
| 11  | 049396   | NULL             | Nonsense

期望输出:

| row | acct_num | exact_address    | place
| --- | -------- |------------------|--------
| 1   | 049403   | 344 Clinton Str  | Metropolis 
| 2   | 049403   | 344 Clinton Str  | Metropolis
| 3   | 049206   | 1007 Mountain Dr | Gotham City
| 4   | 049206   | 1007 Mountain Dr | Gotham City
| 5   | 049206   | 1096 Show Dr.    | Fawcett City
| 6   | 049206   | 1096 Show Dr.    | Fawcett City
| 7   | 049206   | NULL             | Fawcett City
| 8   | 049291   | 1938 Sullivan Pl | Smallville
| 9   | 049293   | 700 Hamilton Str | Central City
| 10  | 049396   | 800 Tidal Way    | Star City
| 11  | 049396   | NULL             | Star City

您可以使用 window 个函数:

select t.*,
       max(case when place <> 'Nonsense' then place end) over (partition by acct_num) as imputed_place
from t;

这 returns NULL 如果给定 acct_num 的所有行都是 'Nonsense'。您可以使用 COALESCE() 将值替换为其他值。

我正在阅读 Snowflake 中可用的 window 函数列表,认为您需要一个新的 window 函数。也许有人可以找到更内置的方法,但无论如何这里有一个用户定义的 table 函数 REPLACE_WITH_LKG 作为 window 函数实现,它将用最后一个已知的好值替换坏值。只要我打算写它,我认为它也可能是通用的,所以它使用正则表达式和 JavaScript RegExp 选项匹配“坏”值。

create or replace function REPLACE_WITH_LKG("VALUE" string, "REGEXP" string, "REGEXP_OPTIONS" string)
returns table(LKG_VALUE string)
language javascript
strict immutable
as
$$
{
    initialize: function (argumentInfo, context) {
        this.lkg = "";
    },
    processRow: function (row, rowWriter, context) {
        const rx = new RegExp(row.REGEXP, row.REGEXP_OPTIONS);
        if (!rx.test(row.VALUE)) {
            this.lkg = row.VALUE;
        }
        rowWriter.writeRow({LKG_VALUE: this.lkg});
    },
    finalize: function (rowWriter, context) {},
}
$$;

select S.*, LKG.LKG_VALUE as PLACE
from superhero S, table(REPLACE_WITH_LKG(PLACE, 'Nonsense', 'ig')
over(partition by null order by "ROW")) LKG;
;

性能说明;数据显示的方式是除了整个 table 之外没有任何分区。那是因为一个明显的分区,按帐户的地方,不会工作。如果使用帐户,第 10 行从不同的 window 中获取其值,因此示例数据的显示方式需要是跨越整个 table 的 window。这不会很好地并行化,对于非常大的 tables 应该避免。