Sql 大写:Google大查询中的RegExp替换捕获组

Sql 大写:Google大查询中的RegExp替换捕获组,sql,regex,google-bigquery,regexp-replace,Sql,Regex,Google Bigquery,Regexp Replace,我试图做一些非常简单的事情,在大查询中变得非常复杂。我想把人名之类的东西转换成适当的大小写(每个单词大写的第一个字母) 这是我目前正在处理的查询,它几乎可以正常工作 选择 REGEXP\u替换( 海螺( 上(左(‘测试’,1)), 下部(次级(“测试”,2)) ), “([a-z])”, 上('\\1') ); #输出:测试 #期望输出:测试 由于某些原因,上层无法处理捕获的组。 如果我将其他文本放入其中,则所有文本都将变为大写,但cap group变量将保持小写 非常感谢您在这方面的任何帮助

我试图做一些非常简单的事情,在大查询中变得非常复杂。我想把人名之类的东西转换成适当的大小写(每个单词大写的第一个字母)

这是我目前正在处理的查询,它几乎可以正常工作

选择
REGEXP\u替换(
海螺(
上(左(‘测试’,1)),
下部(次级(“测试”,2))
),
“([a-z])”,
上('\\1')
);
#输出:测试
#期望输出:测试
由于某些原因,上层无法处理捕获的组。 如果我将其他文本放入其中,则所有文本都将变为大写,但cap group变量将保持小写

非常感谢您在这方面的任何帮助。这似乎很奇怪,它并没有像预期的那样工作(可能是操作顺序的事情…)。无论如何,先谢谢你


Eric

我不是100%确定,但正则表达式似乎是在其中的字符串操作之后进行计算的

另一种方法是,尝试SPLIT():


另一种可能扩展得更好的方法—您能在1500万记录名数据集上测试它吗

SELECT capitalized_name, x, id FROM (
SELECT GROUP_CONCAT(capw, ' ')  OVER(PARTITION BY id ORDER BY pos) capitalized_name, x, id, ROW_NUMBER() OVER(PARTITION BY id ORDER BY pos DESC) rn
FROM (
  SELECT UPPER(LEFT(w, 1)) + LOWER(SUBSTR(w, 2)) capw, x, POSITION(w) pos, id
  FROM (
    SELECT SPLIT(rdf_schema_label, ' ') w, rdf_schema_label x, URI id
    FROM [dbpedia2014temp.Person]
  )
  ORDER BY pos
)
) WHERE rn=1

REGEX_REPLACE不是MySQL函数,必须实现它。 下面是一个名为ucwords的函数,它可以执行以下操作:

    DELIMITER ||

CREATE FUNCTION `ucwords`( str VARCHAR(128) ) RETURNS varchar(128) CHARSET latin1
BEGIN
DECLARE c CHAR(1);
DECLARE s VARCHAR(128);
DECLARE i INT DEFAULT 1;
DECLARE bool INT DEFAULT 1;
DECLARE punct CHAR(17) DEFAULT ' ()[]{},.-_!@;:?/';
SET s = LCASE( str );
WHILE i < LENGTH( str ) DO
BEGIN
SET c = SUBSTRING( s, i, 1 );
IF LOCATE( c, punct ) > 0 THEN
SET bool = 1;
ELSEIF bool=1 THEN
BEGIN
IF c >= 'a' AND c <= 'z' THEN
BEGIN
SET s = CONCAT(LEFT(s,i-1),UCASE(c),SUBSTRING(s,i+1));
SET bool = 0;
END;
ELSEIF c >= '0' AND c <= '9' THEN
SET bool = 0;
END IF;
END;
END IF;
SET i = i+1;
END;
END WHILE;
RETURN s;
END ||

DELIMITER ;
分隔符||
创建函数“ucwords”(str VARCHAR(128))返回VARCHAR(128)字符集1
开始
声明c字符(1);
声明s VARCHAR(128);
声明i INT默认值为1;
声明bool INT默认值为1;
声明点字符(17)默认'()[]{},.-!@;:?/';
设置s=LCASE(str);
而我<长度(str)做
开始
集合c=子串(s,i,1);
如果定位(c,点)>0,则
设置bool=1;
ELSEIF bool=1那么
开始

如果c>='a'和c='0'和c测试正在进行

,那么我首先尝试了一种费力但(我认为)简单的方法:

SELECT
CONCAT(
    UPPER(LEFT('tESt ing', 1)), 
    LOWER(REGEXP_EXTRACT(SUBSTR('tESt ing', 2), r'(\w* )')),
    UPPER(REGEXP_EXTRACT(SUBSTR('tESt ing', 2), r' (\w)')),
    LOWER(REGEXP_EXTRACT(SUBSTR('tESt ing', 2), r' \w(.*)'))
);
这似乎确实起作用,并根据需要返回
testing

然后我尝试了一些简化(我希望)来稍微减少工作量:

SELECT
CONCAT(
    UPPER(LEFT('tESt ing', 1)), 
    LOWER(REGEXP_EXTRACT('tESt ing', r'.(\w* )')),
    UPPER(REGEXP_EXTRACT('tESt ing', r' (\w)')),
    LOWER(REGEXP_EXTRACT('tESt ing', r' \w(.*)'))
);
这似乎也起作用(输出相同)。但是,它只删除
SUBSTR
调用,而不删除regexp操作,我担心这可能会更昂贵


尽管如此,我认为这可能值得分享。

这在现实世界的用例中似乎表现不好。我得到一个错误:在查询执行期间超出了资源。这是在一个大约有1500万行的表上测试的。有意义-我不知道如何为一个更大的表优化它。2种选择:将来,您可以在BigQuery SQL:中编写自己的JS函数。目前,您可以通过BigQuery将此过程外部化到Hadoop connector:。仍然获得超出的资源这是一个关于Google BigQuery的问题,而不是MySQL。当然资源效率更高,但这是因为它只适用于两个词。这并不能使它变得灵活和可用。例如,如果一个用户有一个中间名呢?另外,我想要一些可以在更长的字符串上使用的东西。
SELECT
CONCAT(
    UPPER(LEFT('tESt ing', 1)), 
    LOWER(REGEXP_EXTRACT('tESt ing', r'.(\w* )')),
    UPPER(REGEXP_EXTRACT('tESt ing', r' (\w)')),
    LOWER(REGEXP_EXTRACT('tESt ing', r' \w(.*)'))
);