我想要一个解决方案,将 C# SQL Server DataTable 发送到 Google BigQuery 过程,以将其与另一个表连接并进行更新。
我没有发现任何与 SQL Server 过程类似的情况
CREATE PROCEDURE MyProcedure
@MyTable MyTableType READONLY
但读到我可以将 JSON 数据发送到 GBQ,然后我想也许我可以使用
IReader
创建此 JSON 结构并将其发送到 GBQ。
然后我可以使用此 JSON 数据,使用类似于此处描述的语法进行连接。
有没有更简单的方法来实现这样的目标?那么不需要创建 GBQ 临时表来加入它吗?编辑:
解决方案
我们最终选择了永久表GBQ端来发送数据,然后使用以下更新语句进行更新:
UPDATE MyTable MyTableAlias
SET MyTableAlias.Field1 = BrandNewTableAlias.Field1
FROM BrandNewTable BrandNewTableAlias
WHERE
MyTableAlias.Field1 = BrandNewTableAlias.Field1;
GBQ 不允许在像 SQL Server 这样的 UPDATE
操作上使用
JOIN
语句,因此我们必须使用上面的语法,如 StackOverflow 上的here 和 Google 文档上的 here 所解释。
序列化DataTable解决了问题
JsonConvert.SerializeObject(Chunk, Formatting.None)
并使用此代码调用 GBQ 过程:
public static void BQExecuteProcedure(BigQueryClient Client, BigQueryRoutine Routine, BigQueryParameter[] Parameters)
{
StringBuilder ProcedureName = new StringBuilder();
ProcedureName.AppendJoin('.', new string[] { Routine.Reference.DatasetId, Routine.Reference.RoutineId });
ProcedureName.Append("(");
if (Parameters != null)
{
ProcedureName.AppendJoin(", ", Parameters.Select(p => "@" + p.Name));
}
ProcedureName.Append(")");
string s = ProcedureName.ToString();
string p = null;
Client.CreateQueryJob(sql: $"CALL {ProcedureName}", parameters: Parameters).PollUntilCompleted();
if (!(QueryJob.Status.State.ToUpper().Equals("DONE")))
{
throw new Exception(QueryJob.Status.ErrorResult.ToString());
}
}
GBQ 过程如下所示
CREATE OR REPLACE PROCEDURE MyDataset.PROCEDURE_NAME(JsonSerializedRecords STRING)
BEGIN
UPDATE MyDataset.MY_TABLE MY_TABLE_ALIAS
SET
MY_TABLE_ALIAS.EXAMPLE_FIELD = INPUT_TABLE_ALIAS.UPDATE_FIELD
FROM
(
SELECT
JSON_EXTRACT_SCALAR(json_string, "$.UPDATEFIELD") AS UPDATE_FIELD
FROM UNNEST(JSON_EXTRACT_ARRAY(JsonSerializedRecords)) AS json_string
) INPUT_TABLE_ALIAS
WHERE
MY_TABLE_ALIAS.FIELD_1 = INPUT_TABLE_ALIAS.FIELD_1 AND
MY_TABLE_ALIAS.FIELD_2 = INPUT_TABLE_ALIAS.FIELD_2;
END
我们还必须分解输入数据表,因为 GBQ 脚本的输入参数不能大于 1MB。