Google BigQuery替换字符串类型的函数

时间:2016-06-10 04:44:20

标签: string replace google-bigquery

我正在尝试替换数据中的某些客户名称。 我能够使用Google BigQuery语言通过一个特定字符串的替换函数将字符串的一部分转换为另一部分。

Replace(CustomerName, 'PLO', 'Rustic')
Replace(CustomerName, 'Kix', 'BowWow')

但是,我还有一些我需要使用替换功能

Replace(CustomerName, 'ABC', 'XYZ') OR Replace(CustomerName, 'PLO', 'Rustic') OR Replace(CustomerName, 'Kix', 'BowWow')

等等。

我已经尝试过了

Replace(CustomerName, 'ABC', 'XYZ') AND Replace(CustomerName, 'PLO', 'Rustic') AND Replace(CustomerName, 'Kix', 'BowWow')

但是这给我一个错误信息。

我也试过

{{1}}

但这也给我一个错误信息。

我能够使用" case语句"然后对每一个进行硬编码,但我想知道是否有更好/更快的方法来代替使用替换语句。

感谢您的帮助。

3 个答案:

答案 0 :(得分:0)

CASE WHEN选项非常合理。另一种选择是将它们链接在一起:

REPLACE(
  REPLACE(
    REPLACE(
      CustomerName,
      'ABC',
      'XYZ'),
    'PLO',
    'Rustic'),
  'Kix',
  'BowWow')

您选择哪一个确实取决于具体情况。链式REPLACE调用可能更快,但它们可能以奇怪的方式重叠(例如,如果输出到一个替换匹配后续输入的输入)。 CASE WHEN方法避免了这个问题,但它可能更昂贵,因为您需要执行一个操作来查找子字符串,而另一个操作来实际替换它。

请注意,当您使用ANDOR时,您尝试将REPLACE的字符串输出组合起来,就像它是布尔值一样,这就是它失败的原因。

答案 1 :(得分:0)

如果您有大量的更换件 - REPLACEs的链接可能变得不实用且烦人的手动工作。
下面解决了这个潜在的问题(假设您使用对来维护Lookup表:Word,Replacement)

SELECT CustomerName, fixedCustomerName FROM JS(
// input table
(
  SELECT
    CustomerName, Replacements
  FROM YourTable
  CROSS JOIN (
    SELECT 
      GROUP_CONCAT_UNQUOTED(CONCAT(Word, ',', Replacement), ';') AS Replacements
    FROM ReplacementLookup
) ,
// input columns
CustomerName, Replacements,
// output schema
"[
{name: 'CustomerName', type: 'string'},
{name: 'fixedCustomerName', type: 'string'}
]",
// function
"function(r, emit){
  var Replacements = r.Replacements.split(';');
  var fixedCustomerName = r.CustomerName;
  for (var i = 0; i < Replacements.length; i++) {
    var pat = new RegExp(Replacements[i].split(',')[0],'gi')
    fixedCustomerName = fixedCustomerName.replace(pat, Replacements[i].split(',')[1]);
  }
  emit({CustomerName: r.CustomerName,fixedCustomerName: fixedCustomerName});
 }"
)

您可以使用以下示例

进行测试
SELECT CustomerName, fixedCustomerName FROM JS(
// input table
(
  SELECT
    CustomerName, Replacements
  FROM (
    SELECT CustomerName FROM
      (SELECT '1234ABC567' AS CustomerName),
      (SELECT '12 34 PLO 56' AS CustomerName),
      (SELECT 'Kix' AS CustomerName),
      (SELECT '98 ABC PLO Kix ABC 76 XYZ 54' AS CustomerName),
      (SELECT 'ABCQweKIX' AS CustomerName)
  ) YourTable
  CROSS JOIN (
    SELECT 
      GROUP_CONCAT_UNQUOTED(CONCAT(Word, ',', Replacement), ';') AS Replacements
    FROM (
      SELECT Word, Replacement FROM
        (SELECT 'XYZ' AS Word, 'QWE' AS Replacement),
        (SELECT 'ABC' AS Word, 'XYZ' AS Replacement),
        (SELECT 'PLO' AS Word, 'Rustic' AS Replacement),
        (SELECT 'Kix' AS Word, 'BowWow' AS Replacement)
    )
  ) ReplacementLookup
) ,
// input columns
CustomerName, Replacements,
// output schema
"[
{name: 'CustomerName', type: 'string'},
{name: 'fixedCustomerName', type: 'string'}
]",
// function
"function(r, emit){
  var Replacements = r.Replacements.split(';');
  var fixedCustomerName = r.CustomerName;
  for (var i = 0; i < Replacements.length; i++) {
    var pat = new RegExp(Replacements[i].split(',')[0],'gi')
    fixedCustomerName = fixedCustomerName.replace(pat, Replacements[i].split(',')[1]);
  }
  emit({CustomerName: r.CustomerName,fixedCustomerName: fixedCustomerName});
 }"
)

请注意:如果一次替换的结果与后续替换

的输入匹配,则仍然存在问题

答案 2 :(得分:0)

我相信有多种方法可以解决此问题,这取决于数据集的大小,简单地手工制作一个指导表并将其上传到BigQuery的实用性以及您要替换的数据的粒度。

如果您的值非常精细,则可以在不同的列上创建一个具有“ from”和“ to”值的表,并将该表与主表连接起来,并非常干净地检索这些值。

# Replace the support_table table with your actual table
WITH support_table AS (
    SELECT "ABC" AS OldValue, "XYZ" AS NewValue
)
SELECT main_table.OldValue, support_table.NewValue FROM main_table
JOIN support_table ON main_table.old_value = support_table.old_value

现在,如果要用某项替换大的不同值列表,则可以对包含所有可能值的字符串使用 REGEXP_REPLACE

如果项目列表很大,则可以使用 STRING_AGG 包含要替换的所有值的表,或者跳过 STRING_AGG 步骤并手动创建所述字符串。 下面的两个代码片段均生成“ item1 | item2 | item3”。选择更快的速度。

# Replace the values_to_replace table with your actual table
WITH values_to_replace AS (
   SELECT "item1" AS ColumnWithItemsToReplace
   UNION ALL
   SELECT "item2"
   UNION ALL
   SELECT "item3"
)
SELECT STRING_AGG(ColumnsWithItemsToReplace,"|") FROM values_to_replace
SELECT r"item1|item2|item3"

STRING_AGG 将从表或查询中检索所有值,并使用选择的分隔符将它们连接起来。如果使用管道分隔符,则可以创建一个字符串,例如“ item1 | item2 | item3 | ...”

对于正则表达式,管道计数为“或”,这意味着正则表达式会将字符串解释为“ item1或item2或item3”。因此,如果将生成的字符串作为要替换的值传递给 REGEXP_REPLACE ,它将被视为有效。

下面的示例代码:

REGEXP_REPLACE(
 column_to_replace
,(SELECT STRING_AGG(ColumnWithItemsToReplace,"|") FROM `YourTable`)
,"Replacer"
)

希望有帮助。