雪花不支持的子查询类型无法在 UDF 标量中评估
Posted
技术标签:
【中文标题】雪花不支持的子查询类型无法在 UDF 标量中评估【英文标题】:Snowflake Unsupported subquery type cannot be evaluated in UDF scalar 【发布时间】:2021-04-20 14:34:46 【问题描述】:我正在尝试创建一个函数,它将一个电子邮件数组作为输入,并在电子邮件中返回一个散列用户名数组。 为此,我创建了这个 UDF:
CREATE OR REPLACE FUNCTION pseudonymize_email(email ARRAY) RETURNS ARRAY
LANGUAGE SQL STRICT IMMUTABLE
AS $$
SELECT array_agg(regexp_replace(value,'.+\@', concat(hash(value), '@'))) as email
FROM LATERAL flatten(input => email) as f
$$;
下面的例子可以正常工作
SELECT array_agg(regexp_replace(value,'.+\@', concat(hash(value), '@'))) as email
FROM LATERAL flatten(input => array_construct('toto@gmail.com', 'hello@yahoo.com')) as f
这将只返回一列和一个值。
但是,当在普通的选择语句中使用查询时,例如
WITH test_table(col1, col2) AS (
SELECT 1, array_construct('toto@gmail.com', 'hello@yahoo.com')
)
SELECT
col1,
col2,
pseudonymize_email(col2) as hashed_emails
FROM test_table
我确实收到以下错误:无法评估不支持的子查询类型
知道如何解决这个问题吗?
【问题讨论】:
【参考方案1】:使用 SQL UDF,有时 Snowflake 会尝试内联它们但没有成功。
另一种方法是编写 javascript UDF - 在这种情况下效果很好:
CREATE OR REPLACE FUNCTION pseudonymize_email_JS(email ARRAY) RETURNS ARRAY
LANGUAGE JAVASCRIPT STRICT IMMUTABLE
AS $$
// https://***.com/a/60467595/132438
// TODO: optimize by creating only once per VM
function md5(inputString)
var hc="0123456789abcdef";
function rh(n) var j,s="";for(j=0;j<=3;j++) s+=hc.charAt((n>>(j*8+4))&0x0F)+hc.charAt((n>>(j*8))&0x0F);return s;
function ad(x,y) var l=(x&0xFFFF)+(y&0xFFFF);var m=(x>>16)+(y>>16)+(l>>16);return (m<<16)|(l&0xFFFF);
function rl(n,c) return (n<<c)|(n>>>(32-c));
function cm(q,a,b,x,s,t) return ad(rl(ad(ad(a,q),ad(x,t)),s),b);
function ff(a,b,c,d,x,s,t) return cm((b&c)|((~b)&d),a,b,x,s,t);
function gg(a,b,c,d,x,s,t) return cm((b&d)|(c&(~d)),a,b,x,s,t);
function hh(a,b,c,d,x,s,t) return cm(b^c^d,a,b,x,s,t);
function ii(a,b,c,d,x,s,t) return cm(c^(b|(~d)),a,b,x,s,t);
function sb(x)
var i;var nblk=((x.length+8)>>6)+1;var blks=new Array(nblk*16);for(i=0;i<nblk*16;i++) blks[i]=0;
for(i=0;i<x.length;i++) blks[i>>2]|=x.charCodeAt(i)<<((i%4)*8);
blks[i>>2]|=0x80<<((i%4)*8);blks[nblk*16-2]=x.length*8;return blks;
var i,x=sb(inputString),a=1732584193,b=-271733879,c=-1732584194,d=271733878,olda,oldb,oldc,oldd;
for(i=0;i<x.length;i+=16) olda=a;oldb=b;oldc=c;oldd=d;
a=ff(a,b,c,d,x[i+ 0], 7, -680876936);d=ff(d,a,b,c,x[i+ 1],12, -389564586);c=ff(c,d,a,b,x[i+ 2],17, 606105819);
b=ff(b,c,d,a,x[i+ 3],22,-1044525330);a=ff(a,b,c,d,x[i+ 4], 7, -176418897);d=ff(d,a,b,c,x[i+ 5],12, 1200080426);
c=ff(c,d,a,b,x[i+ 6],17,-1473231341);b=ff(b,c,d,a,x[i+ 7],22, -45705983);a=ff(a,b,c,d,x[i+ 8], 7, 1770035416);
d=ff(d,a,b,c,x[i+ 9],12,-1958414417);c=ff(c,d,a,b,x[i+10],17, -42063);b=ff(b,c,d,a,x[i+11],22,-1990404162);
a=ff(a,b,c,d,x[i+12], 7, 1804603682);d=ff(d,a,b,c,x[i+13],12, -40341101);c=ff(c,d,a,b,x[i+14],17,-1502002290);
b=ff(b,c,d,a,x[i+15],22, 1236535329);a=gg(a,b,c,d,x[i+ 1], 5, -165796510);d=gg(d,a,b,c,x[i+ 6], 9,-1069501632);
c=gg(c,d,a,b,x[i+11],14, 643717713);b=gg(b,c,d,a,x[i+ 0],20, -373897302);a=gg(a,b,c,d,x[i+ 5], 5, -701558691);
d=gg(d,a,b,c,x[i+10], 9, 38016083);c=gg(c,d,a,b,x[i+15],14, -660478335);b=gg(b,c,d,a,x[i+ 4],20, -405537848);
a=gg(a,b,c,d,x[i+ 9], 5, 568446438);d=gg(d,a,b,c,x[i+14], 9,-1019803690);c=gg(c,d,a,b,x[i+ 3],14, -187363961);
b=gg(b,c,d,a,x[i+ 8],20, 1163531501);a=gg(a,b,c,d,x[i+13], 5,-1444681467);d=gg(d,a,b,c,x[i+ 2], 9, -51403784);
c=gg(c,d,a,b,x[i+ 7],14, 1735328473);b=gg(b,c,d,a,x[i+12],20,-1926607734);a=hh(a,b,c,d,x[i+ 5], 4, -378558);
d=hh(d,a,b,c,x[i+ 8],11,-2022574463);c=hh(c,d,a,b,x[i+11],16, 1839030562);b=hh(b,c,d,a,x[i+14],23, -35309556);
a=hh(a,b,c,d,x[i+ 1], 4,-1530992060);d=hh(d,a,b,c,x[i+ 4],11, 1272893353);c=hh(c,d,a,b,x[i+ 7],16, -155497632);
b=hh(b,c,d,a,x[i+10],23,-1094730640);a=hh(a,b,c,d,x[i+13], 4, 681279174);d=hh(d,a,b,c,x[i+ 0],11, -358537222);
c=hh(c,d,a,b,x[i+ 3],16, -722521979);b=hh(b,c,d,a,x[i+ 6],23, 76029189);a=hh(a,b,c,d,x[i+ 9], 4, -640364487);
d=hh(d,a,b,c,x[i+12],11, -421815835);c=hh(c,d,a,b,x[i+15],16, 530742520);b=hh(b,c,d,a,x[i+ 2],23, -995338651);
a=ii(a,b,c,d,x[i+ 0], 6, -198630844);d=ii(d,a,b,c,x[i+ 7],10, 1126891415);c=ii(c,d,a,b,x[i+14],15,-1416354905);
b=ii(b,c,d,a,x[i+ 5],21, -57434055);a=ii(a,b,c,d,x[i+12], 6, 1700485571);d=ii(d,a,b,c,x[i+ 3],10,-1894986606);
c=ii(c,d,a,b,x[i+10],15, -1051523);b=ii(b,c,d,a,x[i+ 1],21,-2054922799);a=ii(a,b,c,d,x[i+ 8], 6, 1873313359);
d=ii(d,a,b,c,x[i+15],10, -30611744);c=ii(c,d,a,b,x[i+ 6],15,-1560198380);b=ii(b,c,d,a,x[i+13],21, 1309151649);
a=ii(a,b,c,d,x[i+ 4], 6, -145523070);d=ii(d,a,b,c,x[i+11],10,-1120210379);c=ii(c,d,a,b,x[i+ 2],15, 718787259);
b=ii(b,c,d,a,x[i+ 9],21, -343485551);a=ad(a,olda);b=ad(b,oldb);c=ad(c,oldc);d=ad(d,oldd);
return rh(a)+rh(b)+rh(c)+rh(d);
return EMAIL.map(function(x)
var regex = /(.*)@/;
var base = regex.exec(x)[1];
return x.replace(regex, md5(base) + '@')
);
$$;
WITH test_table(col1, col2) AS (
SELECT 1, array_construct('toto@gmail.com', 'hello@yahoo.com')
)
SELECT
col1,
col2,
pseudonymize_email_js(col2) as hashed_emails
FROM test_table;
COL1 | COL2 | HASHED_EMAILS |
---|---|---|
1 | [ "toto@gmail.com", "hello@yahoo.com" ] | [ "f71dbe52628a3f83a77ab494817525c6@gmail.com", "5d41402abc4b2a76b9719d911017c592@yahoo.com" ] |
【讨论】:
谢谢,我不想那样做,但我认为这是目前唯一的解决方案!【参考方案2】:因此,鉴于您不能按您创建的性质对每行进行函数调用,一种选择是将其推送到 CTE 中,或者仅将 email_hash
的主体作为您的选择。但通常当人们试图这样做时,他们会试图隐藏复杂性或重用逻辑。
WITH test_table(col1, col2) AS (
SELECT 1, array_construct('toto@gmail.com', 'hello@yahoo.com')
), email_hash AS (
SELECT col1
,col2
,array_agg(regexp_replace(f.value,'.+\@', concat(hash(f.value), '@'))) as email
FROM test_table AS t,
TABLE(FLATTEN(input => t.col2)) f
GROUP BY 1,2
)
SELECT
col1,
col2,
email as hashed_emails
FROM email_hash
【讨论】:
感谢您的回答,但这并不令人满意,因为我想跨多个列和多个表使用此功能。使用 CTE 确实是一种解决方案,但它绝对不可扩展,并且不能真正用于以编程方式创建查询。 @ThomasMannschott Scalable 是一个有趣的词。因为您想做的事情虽然合乎逻辑,但实际上在性能级别上是不可扩展的。因此,您正在使用针对大规模操作优化的数据库,但您希望像在小型数据库中那样简单(也就是隐藏复杂性),但要将性能扩展到大规模水平。以上是关于雪花不支持的子查询类型无法在 UDF 标量中评估的主要内容,如果未能解决你的问题,请参考以下文章
SQL 编译错误:无法评估不受支持的子查询类型 - SELECT 子句中的函数调用