如何在 Google Bigquery 中将字符串转换为列名?
How to convert strings into column names in Google Bigquery?
我在 Google BigQuery 中有一个大型数据集,其中包含数百万行我正在尝试清理的脏数据(应用程序跟踪)。我的问题之一是,对于应用程序中触发的不同事件,相同的数据被发送到不同的列。我的意思是,也许该国家/地区对于某些事件被发送到自定义维度 1,但对于其他事件则发送到自定义维度 147。我不能 post 实际数据,但是 SELECT * FROM table_with_dirty_data
会产生这样的结果:
date | session | eventAction | cd001 | cd002 | cd004 | cd005
-----|---------|-------------|-------|----------|----------|-------
1 | 1 | 'event_1' | '1' | 'Pizza' | null | '21'
1 | 1 | 'event_2' | '10' | '25' | 'Pizza' | '14.56'
1 | 1 | 'event_3' | '3.1' | null | '15' | 'France'
1 | 2 | 'event_1' | '6' | 'Burger' | null | '21'
1 | 2 | 'event_2' | '21' | '25' | 'Burger' | '12.6'
这里的最终目标是得到一个可以分析的干净 table。像这样:
date | session | eventAction | country | vendor | product | price
-----|---------|-------------|----------|----------|----------|-------
1 | 1 | 'event_1' | 'France' | '1' | 'Pizza' | '14.56'
1 | 1 | 'event_2' | 'France' | '1' | 'Pizza' | '14.56'
1 | 1 | 'event_3' | 'France' | '1' | 'Pizza' | '14.56'
1 | 2 | 'event_1' | 'Spain' | '25' | 'Burger' | '12.6'
1 | 2 | 'event_2' | 'Spain' | '25' | 'Burger' | '12.6'
我知道有些事件需要一定程度的统计插补和数据类型转换,但现在我只关心将每个变量放入其自己的列中。所以我创建了一个辅助 table(我们称它为 matrix
),如下所示:
event_name | variable_1 | variable_2 | variable_3
-----------|------------|------------|----------
'event_1' | 'cd020' | 'cd035' | 'cd120'
'event_2' | 'cd020' | 'cd146' | 'cd056'
'event_3' | 'cd001' | 'cd020' | 'cd035'
依此类推,其中 variable_#
列每个单元格中的值是可以找到信息的 table_with_dirty_data
中的列名称。也就是说,对于具有 event_name
'event_1' 和 'even_2' 的事件,可以在名为 cd020
的列中找到 variable_1
,但在名为 cd001
的列中对于 event_name
'event_3' 的事件。所以基本上 matrix
所做的是将每个变量为每个事件发送到哪个自定义维度。
我在 table_with_dirty_data
中有数百个不同的事件,并且 matrix
包含所有 200 个 GA 自定义维度,所以做一些像
SELECT
CASE
WHEN event_name = 'event_1' THEN cd020
WHEN event_name = 'event_2' THEN cd020
WHEN event_name = 'event_3' THEN cd001
END AS variable_1
, CASE
WHEN event_name = 'event_1' THEN cd035
WHEN event_name = 'event_2' THEN cd146
WHEN event_name = 'event_3' THEN cd020
END AS variable_2
, CASE
WHEN event_name = 'event_1' THEN cd120
WHEN event_name = 'event_2' THEN cd056
WHEN event_name = 'event_3' THEN cd035
END AS variable_3
FROM table_with_dirty_data
会占用我很长的时间,而且很容易出错。我想做的是使用 SELECT
语句 return 存储信息的 table_with_dirty_data
中的列名 (cd###
) 并使用 WHILE
遍历所有不同的事件。因此,例如,使用 event_name = 'event_1'
它将是这样的:
SELECT
CASE
WHEN event_name = 'event_1'
THEN (SELECT variable_1 FROM matrix WHERE event_name = 'event_1')
END AS variable_1
, CASE
WHEN event_name = 'event_1'
THEN (SELECT variable_2 FROM matrix WHERE event_name = 'event_1')
END AS variable_2
, CASE
WHEN event_name = 'event_1'
THEN (SELECT variable_3 FROM matrix WHERE event_name = 'event_1')
END AS variable_3
FROM table_with_dirty_data
WHERE event_name = 'event_1'
这里的目标是我可以循环遍历包含所有 event_name
的数组(这很容易实现)。最终我需要一个 table 中的所有事件,但我可以接受 table 来策划每个事件,只要它可以以编程方式完成(我个人不知道它是否均匀在 GBQ 中可能...必须检查一下)。
问题是我正在使用的 SELECT
语句被评估为一个字符串,因此 CASE
子句中的查询结果是字符串文字。例如,如果我为 event = 'event_1',
运行
SELECT variable_1 FROM matrix WHERE event_name = 'event_1'
评估为
'cd020'
然后导致外部查询变为
SELECT
CASE
WHEN event_name = 'event_1' THEN 'cd020'
END AS variable_1
, CASE
WHEN event_name = 'event_1' THEN 'cd035'
END AS variable_2
, CASE
WHEN event_name = 'event_1' THEN 'cd120'
END AS variable_3
FROM table_with_dirty_data
WHERE event_name = 'event_1'
这会产生这样的 table
event_name | variable_1 | variable_2 | variable_3
-----------|------------|------------|----------
'event_1' | 'cd020' | 'cd035' | 'cd120'
'event_1' | 'cd020' | 'cd035' | 'cd120'
'event_1' | 'cd020' | 'cd035' | 'cd120'
每次找到事件 'event_1' 时, 而不是 return 存储在 cd020
、cd035
或 cd120
列中的值。
有谁知道取消引用那些内部查询结果的方法,以便在执行外部查询时将它们转换为列名(因此 'cd020' 变为 cd020
)??
PS:如果有人知道的话,我也愿意接受完全不同的策略。
听起来 EXECUTE IMMEDIATE 可能 会有所帮助。我不确定我是否完全理解映射,但它应该允许您根据 matrix
table.
编写动态语句
但是,根据描述尚不清楚生成的查询可能有多笨重,因为您提到有数百种此类事件并且您可能会 运行 进入其他问题,例如查询复杂性或长度限制。
我按照@shollyman 的建议使用 EXECUTE IMMEDIATE
子句解决了这个问题。我只是为其中一个事件做了这件事,但我相信这回答了最初的问题(将它扩展到其他事件只是写一个 WHILE
循环的问题)。我会一步一步来,因为我没有使用实际的 repex。
第一步我用查询需要查找的事件的名称声明了一个名为 event
的变量。
DECLARE event STRING DEFAULT 'event_1';
然后我声明了一个变量,其中包含查询需要查找变量的列名。
DECLARE variable_name STRING DEFAULT (SELECT variable_1 FROM matrix WHERE event_name = event);
然后我像往常一样编写查询,但使用 EXECUTE IMMEDIATE
子句。我使用了三重双引号,以便可以将其分成多行以提高可读性)。
EXECUTE IMMEDIATE CONCAT("""
SELECT
CASE WHEN event_name = '""", event, "' THEN ", variable_name, """ END AS variable_1
FROM table_with_dirty_data
WHERE event_name = '""", event, """'
""");
如果其他人要使用它,请注意我在一些三重双引号之前或之后使用的单独的单引号。我这样做是因为,例如,声明的变量 event
,即使它是一个字符串,似乎也被连接为 event
(周围没有单引号),这会中断查询执行。
我在 Google BigQuery 中有一个大型数据集,其中包含数百万行我正在尝试清理的脏数据(应用程序跟踪)。我的问题之一是,对于应用程序中触发的不同事件,相同的数据被发送到不同的列。我的意思是,也许该国家/地区对于某些事件被发送到自定义维度 1,但对于其他事件则发送到自定义维度 147。我不能 post 实际数据,但是 SELECT * FROM table_with_dirty_data
会产生这样的结果:
date | session | eventAction | cd001 | cd002 | cd004 | cd005
-----|---------|-------------|-------|----------|----------|-------
1 | 1 | 'event_1' | '1' | 'Pizza' | null | '21'
1 | 1 | 'event_2' | '10' | '25' | 'Pizza' | '14.56'
1 | 1 | 'event_3' | '3.1' | null | '15' | 'France'
1 | 2 | 'event_1' | '6' | 'Burger' | null | '21'
1 | 2 | 'event_2' | '21' | '25' | 'Burger' | '12.6'
这里的最终目标是得到一个可以分析的干净 table。像这样:
date | session | eventAction | country | vendor | product | price
-----|---------|-------------|----------|----------|----------|-------
1 | 1 | 'event_1' | 'France' | '1' | 'Pizza' | '14.56'
1 | 1 | 'event_2' | 'France' | '1' | 'Pizza' | '14.56'
1 | 1 | 'event_3' | 'France' | '1' | 'Pizza' | '14.56'
1 | 2 | 'event_1' | 'Spain' | '25' | 'Burger' | '12.6'
1 | 2 | 'event_2' | 'Spain' | '25' | 'Burger' | '12.6'
我知道有些事件需要一定程度的统计插补和数据类型转换,但现在我只关心将每个变量放入其自己的列中。所以我创建了一个辅助 table(我们称它为 matrix
),如下所示:
event_name | variable_1 | variable_2 | variable_3
-----------|------------|------------|----------
'event_1' | 'cd020' | 'cd035' | 'cd120'
'event_2' | 'cd020' | 'cd146' | 'cd056'
'event_3' | 'cd001' | 'cd020' | 'cd035'
依此类推,其中 variable_#
列每个单元格中的值是可以找到信息的 table_with_dirty_data
中的列名称。也就是说,对于具有 event_name
'event_1' 和 'even_2' 的事件,可以在名为 cd020
的列中找到 variable_1
,但在名为 cd001
的列中对于 event_name
'event_3' 的事件。所以基本上 matrix
所做的是将每个变量为每个事件发送到哪个自定义维度。
我在 table_with_dirty_data
中有数百个不同的事件,并且 matrix
包含所有 200 个 GA 自定义维度,所以做一些像
SELECT
CASE
WHEN event_name = 'event_1' THEN cd020
WHEN event_name = 'event_2' THEN cd020
WHEN event_name = 'event_3' THEN cd001
END AS variable_1
, CASE
WHEN event_name = 'event_1' THEN cd035
WHEN event_name = 'event_2' THEN cd146
WHEN event_name = 'event_3' THEN cd020
END AS variable_2
, CASE
WHEN event_name = 'event_1' THEN cd120
WHEN event_name = 'event_2' THEN cd056
WHEN event_name = 'event_3' THEN cd035
END AS variable_3
FROM table_with_dirty_data
会占用我很长的时间,而且很容易出错。我想做的是使用 SELECT
语句 return 存储信息的 table_with_dirty_data
中的列名 (cd###
) 并使用 WHILE
遍历所有不同的事件。因此,例如,使用 event_name = 'event_1'
它将是这样的:
SELECT
CASE
WHEN event_name = 'event_1'
THEN (SELECT variable_1 FROM matrix WHERE event_name = 'event_1')
END AS variable_1
, CASE
WHEN event_name = 'event_1'
THEN (SELECT variable_2 FROM matrix WHERE event_name = 'event_1')
END AS variable_2
, CASE
WHEN event_name = 'event_1'
THEN (SELECT variable_3 FROM matrix WHERE event_name = 'event_1')
END AS variable_3
FROM table_with_dirty_data
WHERE event_name = 'event_1'
这里的目标是我可以循环遍历包含所有 event_name
的数组(这很容易实现)。最终我需要一个 table 中的所有事件,但我可以接受 table 来策划每个事件,只要它可以以编程方式完成(我个人不知道它是否均匀在 GBQ 中可能...必须检查一下)。
问题是我正在使用的 SELECT
语句被评估为一个字符串,因此 CASE
子句中的查询结果是字符串文字。例如,如果我为 event = 'event_1',
SELECT variable_1 FROM matrix WHERE event_name = 'event_1'
评估为
'cd020'
然后导致外部查询变为
SELECT
CASE
WHEN event_name = 'event_1' THEN 'cd020'
END AS variable_1
, CASE
WHEN event_name = 'event_1' THEN 'cd035'
END AS variable_2
, CASE
WHEN event_name = 'event_1' THEN 'cd120'
END AS variable_3
FROM table_with_dirty_data
WHERE event_name = 'event_1'
这会产生这样的 table
event_name | variable_1 | variable_2 | variable_3
-----------|------------|------------|----------
'event_1' | 'cd020' | 'cd035' | 'cd120'
'event_1' | 'cd020' | 'cd035' | 'cd120'
'event_1' | 'cd020' | 'cd035' | 'cd120'
每次找到事件 'event_1' 时, 而不是 return 存储在 cd020
、cd035
或 cd120
列中的值。
有谁知道取消引用那些内部查询结果的方法,以便在执行外部查询时将它们转换为列名(因此 'cd020' 变为 cd020
)??
PS:如果有人知道的话,我也愿意接受完全不同的策略。
听起来 EXECUTE IMMEDIATE 可能 会有所帮助。我不确定我是否完全理解映射,但它应该允许您根据 matrix
table.
但是,根据描述尚不清楚生成的查询可能有多笨重,因为您提到有数百种此类事件并且您可能会 运行 进入其他问题,例如查询复杂性或长度限制。
我按照@shollyman 的建议使用 EXECUTE IMMEDIATE
子句解决了这个问题。我只是为其中一个事件做了这件事,但我相信这回答了最初的问题(将它扩展到其他事件只是写一个 WHILE
循环的问题)。我会一步一步来,因为我没有使用实际的 repex。
第一步我用查询需要查找的事件的名称声明了一个名为 event
的变量。
DECLARE event STRING DEFAULT 'event_1';
然后我声明了一个变量,其中包含查询需要查找变量的列名。
DECLARE variable_name STRING DEFAULT (SELECT variable_1 FROM matrix WHERE event_name = event);
然后我像往常一样编写查询,但使用 EXECUTE IMMEDIATE
子句。我使用了三重双引号,以便可以将其分成多行以提高可读性)。
EXECUTE IMMEDIATE CONCAT("""
SELECT
CASE WHEN event_name = '""", event, "' THEN ", variable_name, """ END AS variable_1
FROM table_with_dirty_data
WHERE event_name = '""", event, """'
""");
如果其他人要使用它,请注意我在一些三重双引号之前或之后使用的单独的单引号。我这样做是因为,例如,声明的变量 event
,即使它是一个字符串,似乎也被连接为 event
(周围没有单引号),这会中断查询执行。