Hasura "Running Total" 计算列
Hasura "Running Total" Computed Column
我想在 Hasura 中创建一个计算列,其中 returns 一组另一个 table 并包括该集合的 运行 总列。例如:
table_a
id product_id
----------- ----------
1 "1"
2 "2"
2 "3"
table_b
id product_id qty created_at
----------- ---------- --- ----------
1 "1" 6 01/01/20
2 "2" 4 01/02/20
3 "3" 2 01/02/20
4 "3" 2 01/02/20
5 "1" 4 01/03/20
6 "2" 6 01/03/20
所需的 GQL 响应:
{
"data": {
"table_a": [
{
"id": 1,
"product_id": "1",
"computed_table_b_rows": [
{
id: 1,
product_id: "1",
qty: 6,
created_at: 01/01/20,
running_total: 6,
},
{
id: 5,
product_id: "1",
qty: 4,
created_at: 01/03/20,
running_total: 10,
},
]
}
]
}
}
这是我目前没有的方法:
CREATE FUNCTION filter_table_b(table_a_row table_a)
RETURNS SETOF table_b AS $$
SELECT *,
SUM (qty) OVER (PARTITION BY product_id ORDER BY created_at) as running_total
FROM table_b
WHERE product_id = table_a_row.product_id
$$ LANGUAGE sql STABLE;
似乎 SETOF 应该是 table 的子集,并且不能有新列。例如。我试过了:
CREATE FUNCTION getfoo(int) RETURNS SETOF table_a AS $$
SELECT *, 'asdf' as extra FROM table_a WHERE id = ;
$$ LANGUAGE SQL;
导致 Hasura 报告的错误:
SQL Execution Failed
postgres-error: return type mismatch in function declared to return table_a
{
"path": "$.args[0].args",
"error": "query execution failed",
"internal": {
"arguments": [],
"error": {
"status_code": "42P13",
"exec_status": "FatalError",
"message": "return type mismatch in function declared to return table_a",
"description": "Final statement returns too many columns.",
"hint": ""
},
"prepared": false,
"statement": "CREATE FUNCTION getfoo(int) RETURNS SETOF table_a AS $$\n SELECT *, 'asdf' as extra FROM table_a WHERE id = ;\n$$ LANGUAGE SQL;"
},
"code": "postgres-error"
}
但是还有其他一些选择:
- 将 "running total" 列添加到
table_b
本身(通过更改函数定义。详见下文。
- 如果这不够高效,另一种选择是使用总和和分区在 table_b 上创建一个包含 running_total 列的视图。然后创建从 table_a 到 table_b_view.
的关系
- 在 table_b 上创建一个触发器,当添加新行时它会计算 running_total 列并存储它,因为该数据似乎是静态的,因为它基于历史数据。
下面详细介绍了选项 1,因为它最接近原始实现(使用函数):
CREATE OR REPLACE FUNCTION public.table_b_running_total(table_b_row table_b)
RETURNS bigint
LANGUAGE sql
STABLE
AS $function$
SELECT SUM (qty)
FROM table_b
WHERE product_id = table_b_row.product_id
AND created_at <= table_b_row.created_at
LIMIT 1
$function$
有了这个,我能够得到想要的结果——虽然想要的 graphql 响应不完全匹配。
查询:
query MyQuery {
table_a(where:{ id: { _eq: 1 }}) {
id
product_id
table_bs {
id
product_id
qty
created_at
table_b_running_total
}
}
}
回复:
{
"data": {
"table_a": [
{
"id": 1,
"product_id": "1",
"table_bs": [
{
"id": 1,
"product_id": "1",
"qty": 6,
"created_at": "2020-01-01T00:00:00+00:00",
"table_b_running_total": 6
},
{
"id": 5,
"product_id": "1",
"qty": 4,
"created_at": "2020-01-03T00:00:00+00:00",
"table_b_running_total": 10
}
]
}
]
}
}
我想在 Hasura 中创建一个计算列,其中 returns 一组另一个 table 并包括该集合的 运行 总列。例如:
table_a
id product_id
----------- ----------
1 "1"
2 "2"
2 "3"
table_b
id product_id qty created_at
----------- ---------- --- ----------
1 "1" 6 01/01/20
2 "2" 4 01/02/20
3 "3" 2 01/02/20
4 "3" 2 01/02/20
5 "1" 4 01/03/20
6 "2" 6 01/03/20
所需的 GQL 响应:
{
"data": {
"table_a": [
{
"id": 1,
"product_id": "1",
"computed_table_b_rows": [
{
id: 1,
product_id: "1",
qty: 6,
created_at: 01/01/20,
running_total: 6,
},
{
id: 5,
product_id: "1",
qty: 4,
created_at: 01/03/20,
running_total: 10,
},
]
}
]
}
}
这是我目前没有的方法:
CREATE FUNCTION filter_table_b(table_a_row table_a)
RETURNS SETOF table_b AS $$
SELECT *,
SUM (qty) OVER (PARTITION BY product_id ORDER BY created_at) as running_total
FROM table_b
WHERE product_id = table_a_row.product_id
$$ LANGUAGE sql STABLE;
似乎 SETOF 应该是 table 的子集,并且不能有新列。例如。我试过了:
CREATE FUNCTION getfoo(int) RETURNS SETOF table_a AS $$
SELECT *, 'asdf' as extra FROM table_a WHERE id = ;
$$ LANGUAGE SQL;
导致 Hasura 报告的错误:
SQL Execution Failed
postgres-error: return type mismatch in function declared to return table_a
{
"path": "$.args[0].args",
"error": "query execution failed",
"internal": {
"arguments": [],
"error": {
"status_code": "42P13",
"exec_status": "FatalError",
"message": "return type mismatch in function declared to return table_a",
"description": "Final statement returns too many columns.",
"hint": ""
},
"prepared": false,
"statement": "CREATE FUNCTION getfoo(int) RETURNS SETOF table_a AS $$\n SELECT *, 'asdf' as extra FROM table_a WHERE id = ;\n$$ LANGUAGE SQL;"
},
"code": "postgres-error"
}
但是还有其他一些选择:
- 将 "running total" 列添加到
table_b
本身(通过更改函数定义。详见下文。 - 如果这不够高效,另一种选择是使用总和和分区在 table_b 上创建一个包含 running_total 列的视图。然后创建从 table_a 到 table_b_view. 的关系
- 在 table_b 上创建一个触发器,当添加新行时它会计算 running_total 列并存储它,因为该数据似乎是静态的,因为它基于历史数据。
下面详细介绍了选项 1,因为它最接近原始实现(使用函数):
CREATE OR REPLACE FUNCTION public.table_b_running_total(table_b_row table_b)
RETURNS bigint
LANGUAGE sql
STABLE
AS $function$
SELECT SUM (qty)
FROM table_b
WHERE product_id = table_b_row.product_id
AND created_at <= table_b_row.created_at
LIMIT 1
$function$
有了这个,我能够得到想要的结果——虽然想要的 graphql 响应不完全匹配。
查询:
query MyQuery {
table_a(where:{ id: { _eq: 1 }}) {
id
product_id
table_bs {
id
product_id
qty
created_at
table_b_running_total
}
}
}
回复:
{
"data": {
"table_a": [
{
"id": 1,
"product_id": "1",
"table_bs": [
{
"id": 1,
"product_id": "1",
"qty": 6,
"created_at": "2020-01-01T00:00:00+00:00",
"table_b_running_total": 6
},
{
"id": 5,
"product_id": "1",
"qty": 4,
"created_at": "2020-01-03T00:00:00+00:00",
"table_b_running_total": 10
}
]
}
]
}
}