是否有一个函数可以让我输出 json 数组中元素的当前索引?
Is there a function that would allow me to output current index of an element in json array?
我有以下示例 Postgres SQL 查询。
SELECT name, json_array_elements(myjson)->>'id' id FROM
(SELECT 'Dingsda'::text AS name, json_build_array('{"id" : 100}'::json, '{"id" : 200}'::json) myjson
UNION ALL
SELECT 'Dingsbums'::text AS name, json_build_array('{"id" : 101}'::json, '{"id" : 201}'::json, '{"id" : 301}'::json) myjson
) t;
输出如下table.
+-----------+-----+
| name | id |
+-----------+-----+
| Dingsda | 100 |
| Dingsda | 200 |
| Dingsbums | 101 |
| Dingsbums | 201 |
+-----------+-----+
现在我想要实现的是在末尾放置第三列,其中包含 json 数组元素的索引,从 0 开始,依此类推。结果应如下所示。
+-----------+-----+-------+
| name | id | index |
+-----------+-----+-------+
| Dingsda | 100 | 0 |
| Dingsda | 200 | 1 |
| Dingsbums | 101 | 0 |
| Dingsbums | 201 | 1 |
| Dingsbums | 301 | 2 |
+-----------+-----+-------+
不幸的是,我还没有找到可以帮助我的功能。我尝试用 row_number() OVER
进行试验,但当涉及 json
类型的列时,它似乎 return 奇怪的结果。
是否有任何函数可以支持这个相当简单的要求?
编辑
Mureinik 的回答很有帮助,但我希望能够保留 json 中元素的原始序列。在这个例子中,序列丢失了。我认为这不是确定性的。
SELECT name, id, ROW_NUMBER() OVER (PARTITION BY name ORDER BY 1)
FROM (SELECT name, JSON_ARRAY_ELEMENTS(myjson)->>'id' id
FROM (SELECT 'Dingsda'::text AS name, JSON_BUILD_ARRAY('{"id" : 100}'::json, '{"id" : 200}'::json, '{"id" : 300}'::json, '{"id" : 400}'::json) myjson
UNION ALL
SELECT 'Dingsbums'::text AS name, JSON_BUILD_ARRAY('{"id" : 101}'::json, '{"id" : 201}'::json, '{"id" : 301}'::json) myjson
) t
) s;
+-----------+-----+-------+
| name | id | index |
+-----------+-----+-------+
| Dingsbums | 101 | 1 |
| Dingsbums | 201 | 2 |
| Dingsbums | 301 | 3 |
| Dingsda | 100 | 1 |
| Dingsda | 400 | 2 |
| Dingsda | 200 | 3 |
| Dingsda | 300 | 4 |
+-----------+-----+-------+
使用 row_number
似乎是正确的方法。您只需要用另一个查询包装此查询即可生成行号:
SELECT name, id, ROW_NUMBER() OVER (PARTITION BY name ORDER BY 1)
FROM (SELECT name, JSON_ARRAY_ELEMENTS(myjson)->>'id' id
FROM (SELECT 'Dingsda'::text AS name, JSON_BUILD_ARRAY('{"id" : 100}'::json, '{"id" : 200}'::json) myjson
UNION ALL
SELECT 'Dingsbums'::text AS name, JSON_BUILD_ARRAY('{"id" : 101}'::json, '{"id" : 201}'::json, '{"id" : 301}'::json) myjson
) t
) s;
永远不要在 SELECT
子句中使用集合返回函数(例如 json_array_elements()
),除非您确切地知道自己在做什么。这只会让你的事情变得更难。
您可以使用 table 函数 (9.4+) 的 WITH ORDINALITY
子句,这正是您的问题所在:
SELECT name, elem->>'id' id, "index"
FROM (SELECT 'Dingsda'::text AS name, json_build_array('{"id" : 100}'::json, '{"id" : 200}'::json) myjson
UNION ALL
SELECT 'Dingsbums'::text AS name, json_build_array('{"id" : 101}'::json, '{"id" : 201}'::json, '{"id" : 301}'::json) myjson) t,
json_array_elements(t.myjson) WITH ORDINALITY e(elem, "index");
您也可以将 generate_series()
与 json_array_length()
一起使用,但 WITH ORDINALITY
更简单。
您可以使用横向连接(无论如何推荐)和 with ordinality
SELECT name, x.element ->> 'id' as id, x.idx
FROM (
SELECT 'Dingsda'::text AS name, json_build_array('{"id" : 100}'::json, '{"id" : 200}'::json) myjson
UNION ALL
SELECT 'Dingsbums'::text AS name, json_build_array('{"id" : 101}'::json, '{"id" : 201}'::json, '{"id" : 301}'::json) myjson
) t
cross join lateral json_array_elements(myjson) with ordinality as x(element, idx)
我有以下示例 Postgres SQL 查询。
SELECT name, json_array_elements(myjson)->>'id' id FROM
(SELECT 'Dingsda'::text AS name, json_build_array('{"id" : 100}'::json, '{"id" : 200}'::json) myjson
UNION ALL
SELECT 'Dingsbums'::text AS name, json_build_array('{"id" : 101}'::json, '{"id" : 201}'::json, '{"id" : 301}'::json) myjson
) t;
输出如下table.
+-----------+-----+
| name | id |
+-----------+-----+
| Dingsda | 100 |
| Dingsda | 200 |
| Dingsbums | 101 |
| Dingsbums | 201 |
+-----------+-----+
现在我想要实现的是在末尾放置第三列,其中包含 json 数组元素的索引,从 0 开始,依此类推。结果应如下所示。
+-----------+-----+-------+
| name | id | index |
+-----------+-----+-------+
| Dingsda | 100 | 0 |
| Dingsda | 200 | 1 |
| Dingsbums | 101 | 0 |
| Dingsbums | 201 | 1 |
| Dingsbums | 301 | 2 |
+-----------+-----+-------+
不幸的是,我还没有找到可以帮助我的功能。我尝试用 row_number() OVER
进行试验,但当涉及 json
类型的列时,它似乎 return 奇怪的结果。
是否有任何函数可以支持这个相当简单的要求?
编辑
Mureinik 的回答很有帮助,但我希望能够保留 json 中元素的原始序列。在这个例子中,序列丢失了。我认为这不是确定性的。
SELECT name, id, ROW_NUMBER() OVER (PARTITION BY name ORDER BY 1)
FROM (SELECT name, JSON_ARRAY_ELEMENTS(myjson)->>'id' id
FROM (SELECT 'Dingsda'::text AS name, JSON_BUILD_ARRAY('{"id" : 100}'::json, '{"id" : 200}'::json, '{"id" : 300}'::json, '{"id" : 400}'::json) myjson
UNION ALL
SELECT 'Dingsbums'::text AS name, JSON_BUILD_ARRAY('{"id" : 101}'::json, '{"id" : 201}'::json, '{"id" : 301}'::json) myjson
) t
) s;
+-----------+-----+-------+
| name | id | index |
+-----------+-----+-------+
| Dingsbums | 101 | 1 |
| Dingsbums | 201 | 2 |
| Dingsbums | 301 | 3 |
| Dingsda | 100 | 1 |
| Dingsda | 400 | 2 |
| Dingsda | 200 | 3 |
| Dingsda | 300 | 4 |
+-----------+-----+-------+
使用 row_number
似乎是正确的方法。您只需要用另一个查询包装此查询即可生成行号:
SELECT name, id, ROW_NUMBER() OVER (PARTITION BY name ORDER BY 1)
FROM (SELECT name, JSON_ARRAY_ELEMENTS(myjson)->>'id' id
FROM (SELECT 'Dingsda'::text AS name, JSON_BUILD_ARRAY('{"id" : 100}'::json, '{"id" : 200}'::json) myjson
UNION ALL
SELECT 'Dingsbums'::text AS name, JSON_BUILD_ARRAY('{"id" : 101}'::json, '{"id" : 201}'::json, '{"id" : 301}'::json) myjson
) t
) s;
永远不要在 SELECT
子句中使用集合返回函数(例如 json_array_elements()
),除非您确切地知道自己在做什么。这只会让你的事情变得更难。
您可以使用 table 函数 (9.4+) 的 WITH ORDINALITY
子句,这正是您的问题所在:
SELECT name, elem->>'id' id, "index"
FROM (SELECT 'Dingsda'::text AS name, json_build_array('{"id" : 100}'::json, '{"id" : 200}'::json) myjson
UNION ALL
SELECT 'Dingsbums'::text AS name, json_build_array('{"id" : 101}'::json, '{"id" : 201}'::json, '{"id" : 301}'::json) myjson) t,
json_array_elements(t.myjson) WITH ORDINALITY e(elem, "index");
您也可以将 generate_series()
与 json_array_length()
一起使用,但 WITH ORDINALITY
更简单。
您可以使用横向连接(无论如何推荐)和 with ordinality
SELECT name, x.element ->> 'id' as id, x.idx
FROM (
SELECT 'Dingsda'::text AS name, json_build_array('{"id" : 100}'::json, '{"id" : 200}'::json) myjson
UNION ALL
SELECT 'Dingsbums'::text AS name, json_build_array('{"id" : 101}'::json, '{"id" : 201}'::json, '{"id" : 301}'::json) myjson
) t
cross join lateral json_array_elements(myjson) with ordinality as x(element, idx)