编辑输出(根据检索到的数量和分号设置括号)
Posted
技术标签:
【中文标题】编辑输出(根据检索到的数量和分号设置括号)【英文标题】:Editing the output (set brackets depending on the quantity retrieved and the semicolon) 【发布时间】:2020-04-15 03:39:28 【问题描述】:每次我运行我的代码时,我都会以 JSON 格式获得一、两或多行。我正在使用 Oracle 11g。
这是我在 SQL Fiddle 上的CODE,您将在那里找到所有数据。
例如,在这种情况下,我得到了这样的东西:
"sku":"99342435","PRICE":"9999",PRICES_FOR_CLIENTS:["group":"A","PRICE":"29223","group":"B", "PRICE":"33223","group":"SUPERMARKET","PRICE":"48343","group":"WALMART","PRICE":"40340"];
但我可以根据表中存储的数据获得此输出:
"sku":"99342435","PRICE":"9999",PRICES_FOR_CLIENTS:["group":"A","PRICE":"29223","group":"B", "PRICE":"33223","group":"SUPERMARKET","PRICE":"48343","group":"WALMART","PRICE":"40340"];
"sku":"95453343","PRICE":"8778",PRICES_FOR_CLIENTS:["group":"A","PRICE":"29223","group":"B", "PRICE":"33223","group":"SUPERMARKET","PRICE":"48343","group":"WALMART","PRICE":"40340"];
我想让我的查询能够在第一行中放置一个“左括号”,检查是否存在其他行,如果没有显示新行,则插入一个 close最后是括号和一个分号;像这样:
["sku":"99342435","PRICE":"9999",PRICES_FOR_CLIENTS:["group":"A","PRICE":"29223", "group":"B","PRICE":"33223","group":"SUPERMARKET","PRICE":"48343","group":"WALMART","PRICE":"40340 "]];
但另一种情况可能是存在 多于 1 行;在这种情况下,我想在第一行放一个 左括号,而不是右括号。我只想在第一行打开括号并在最后一行和分号内关闭它。不同的行必须用逗号分隔。请遵循以下示例:
["sku":"99342435","PRICE":"9999",PRICES_FOR_CLIENTS:["group":"A","PRICE":"29223", "group":"B","PRICE":"33223","group":"SUPERMARKET","PRICE":"48343","group":"WALMART","PRICE":"40340 "],
"sku":"95453343","PRICE":"8778",PRICES_FOR_CLIENTS:["group":"A","PRICE":"29223","group":"B", "PRICE":"33223","group":"SUPERMARKET","PRICE":"48343","group":"WALMART","PRICE":"40340"]] ;
我尝试了很多次,但我无法做到。
你能帮帮我吗?
【问题讨论】:
嘿伙计,你好吗?我已经更新了我的问题;是的,这有点棘手:/ 感谢包含 DBMS — 我还注意到代码在 SQL Fiddle 上,但我认为它应该在问题中(SELECT 语句应该是;支持数据在 SQL 上很好小提琴——说它在那里)。 准备好了,谢谢你的提示:)。我认为最好的办法是将所有内容都放在 SQL FIDDLE 中。 据我了解,当只有一行要输出(包含在
中)时,您正在寻求创建一个 JSON“对象”,当还有更多时,您正在寻求创建一个 JSON 对象“数组”多于一行输出。我建议总是生成一个数组会更好——它可以处理零行或多行,每一行都是一个对象。我不清楚为什么分号是个好主意——这意味着它不再是纯 JSON。我不知道 Oracle 为从多行输出生成 JSON 提供了哪些工具;你可以像我一样抨击手册。
是的,我知道;我试图做一些疯狂的事情,但 Oracle 和 JSON 根本不是好朋友;无论如何,谢谢你的提示。
【参考方案1】:
这开始落入仅仅因为你可以让它工作的领域,并不意味着你应该这样做。但要回答您的问题,请查看以下代码:
SELECT CASE WHEN sub2.TOTAL_ROW > 1 AND sub2.this_row = 1 THEN '[' ELSE NULL END||
sub2.json||
CASE WHEN sub2.total_row > 1 AND sub2.this_row = sub2.total_row THEN ']' ELSE NULL END AS JSON
FROM (SELECT '"sku":"'||sub.item_code||'","PRICE":"'||sub.item_price||'",PRICES_FOR_CLIENTS:['||listagg('"group":"'||sub.identifier||'","PRICE":"'||sub.price||'"',',') WITHIN GROUP (ORDER BY sub.identifier)||'];' AS JSON,
COUNT(*) OVER () AS TOTAL_ROW,
ROW_NUMBER() OVER (ORDER BY sub.item_code, sub.item_price) AS THIS_ROW
FROM (SELECT DECODE(ppc.customer_class_code, 'E', c.description, ppc.customer_class_code) AS IDENTIFIER, tpp.item_code, replace(tpp.price, ',', '.') AS ITEM_PRICE, REPLACE(avg(ppc.price), ',', '.') AS PRICE,
tpl.request_id, max(tpl.request_id) over (partition by tpp.item_code) as max_request
FROM table_price_list tpl
INNER JOIN table_price_product tpp ON tpp.list_header_id = tpl.list_header_id AND tpp.request_id = tpl.request_id
INNER JOIN prices_per_client ppc ON tpp.item_code = ppc.item_code
LEFT JOIN clients c ON ppc.customer_number = c.account_number
WHERE SYSDATE BETWEEN NVL(tpp.start_date_active, SYSDATE) AND NVL(tpp.end_date_active, SYSDATE+1)
GROUP BY DECODE(ppc.customer_class_code, 'E', c.description, ppc.customer_class_code), tpp.item_code, tpp.price, tpl.request_id) sub
WHERE sub.identifier IS NOT NULL
and sub.request_id = sub.max_request
GROUP BY sub.item_code, sub.item_price) sub2
ORDER BY sub2.this_row;
我更新了你的SQLFiddle
这个查询所做的是扩展前一个查询。它使用分析函数COUNT
和ROW_NUMBER
计算总行数和该行数。我根本没有对它们进行分区,因为我们希望它们考虑所有返回的行。如果 Total Rows > 1 并且这是第一行,则以 '[' 开头。在中间附加 JSON。如果这是最后一行(Total > 1 和 ROW_NUMBER
= COUNT
),则将 ']' 附加到末尾。
编辑 1:更改为始终有括号
SELECT DECODE(sub2.this_row, 1, '[', NULL)||
sub2.json||
DECODE(sub2.this_row, sub2.total_row, ']', NULL) AS JSON
FROM (SELECT '"sku":"'||sub.item_code||'","PRICE":"'||sub.item_price||'",PRICES_FOR_CLIENTS:['||listagg('"group":"'||sub.identifier||'","PRICE":"'||sub.price||'"',',') WITHIN GROUP (ORDER BY sub.identifier)||'];' AS JSON,
COUNT(*) OVER () AS TOTAL_ROW,
ROW_NUMBER() OVER (ORDER BY sub.item_code, sub.item_price) AS THIS_ROW
FROM (SELECT DECODE(ppc.customer_class_code, 'E', c.description, ppc.customer_class_code) AS IDENTIFIER, tpp.item_code, replace(tpp.price, ',', '.') AS ITEM_PRICE, REPLACE(avg(ppc.price), ',', '.') AS PRICE,
tpl.request_id, max(tpl.request_id) over (partition by tpp.item_code) as max_request
FROM table_price_list tpl
INNER JOIN table_price_product tpp ON tpp.list_header_id = tpl.list_header_id AND tpp.request_id = tpl.request_id
INNER JOIN prices_per_client ppc ON tpp.item_code = ppc.item_code
LEFT JOIN clients c ON ppc.customer_number = c.account_number
WHERE SYSDATE BETWEEN NVL(tpp.start_date_active, SYSDATE) AND NVL(tpp.end_date_active, SYSDATE+1)
GROUP BY DECODE(ppc.customer_class_code, 'E', c.description, ppc.customer_class_code), tpp.item_code, tpp.price, tpl.request_id) sub
WHERE sub.identifier IS NOT NULL
and sub.request_id = sub.max_request
GROUP BY sub.item_code, sub.item_price) sub2
ORDER BY sub2.this_row;
这是更新后的 SQLFiddle (Link)。
考虑到更简单的逻辑,我将CASE
换成了DECODE
。如果该行是第一行,它将获得左括号。如果它是最后一行,它将获得右括号。如果两者兼有,则两者兼而有之。
【讨论】:
嘿德尔,你好吗?感谢回复。我不知道为什么,但我发现 Oracle 有点棘手; JSON 和与之相关的一切都很奇怪,我很容易感到困惑。他们说:“来吧,没那么难”,我就是不知道。 PS:你解释的很好 只是一个注释:它应该始终显示左括号'['和右括号']',行数无关紧要。 @Student_new 我添加了一个编辑来修复逻辑。看看吧。【参考方案2】:处理此问题的最简单方法是对现有查询的结果再执行一次LISTAGG
,并将其包含在[
和]
中:
SELECT '[' || LISTAGG(JSON, ',') WITHIN GROUP(ORDER BY NULL) || ']' AS JSON
FROM (
SELECT '"sku":"'||sub.item_code||'","PRICE":"'||sub.item_price||'","PRICES_FOR_CLIENTS":['||listagg('"group":"'||sub.identifier||'","PRICE":"'||sub.price||'"',',') WITHIN GROUP (ORDER BY sub.identifier)||']' AS JSON
FROM (SELECT DECODE(ppc.customer_class_code, 'E', c.description, ppc.customer_class_code) AS IDENTIFIER, tpp.item_code, replace(tpp.price, ',', '.') AS ITEM_PRICE, REPLACE(avg(ppc.price), ',', '.') AS PRICE,
tpl.request_id, max(tpl.request_id) over (partition by tpp.item_code) as max_request
FROM table_price_list tpl
INNER JOIN table_price_product tpp ON tpp.list_header_id = tpl.list_header_id AND tpp.request_id = tpl.request_id
INNER JOIN prices_per_client ppc ON tpp.item_code = ppc.item_code
LEFT JOIN clients c ON ppc.customer_number = c.account_number
WHERE SYSDATE BETWEEN NVL(tpp.start_date_active, SYSDATE) AND NVL(tpp.end_date_active, SYSDATE+1)
GROUP BY DECODE(ppc.customer_class_code, 'E', c.description, ppc.customer_class_code), tpp.item_code, tpp.price, tpl.request_id) sub
WHERE sub.identifier IS NOT NULL
and sub.request_id = sub.max_request
GROUP BY sub.item_code, sub.item_price
) j
Demo on SQLFiddle
注意,PRICES_FOR_CLIENTS
需要用双引号括起来,否则查询的输出不是有效的JSON。您还需要从原始查询输出的字符串末尾删除;
。
【讨论】:
谢谢你的回复,尼克。我正在检查这个! @Student_new 您使用的是哪个版本的 Oracle? 实际上我使用的是 11g,但他们正在改变一切,12c 即将推出 如果您使用的是 11g,您需要这样做。升级到 12c 后,您将可以访问 JSON 生成函数(JSON_OBJECT、JSON_ARRAY)及其聚合版本,这将更容易。 我是 Oracle 数据库的新手;有些事情对我来说只是“奇怪”:/以上是关于编辑输出(根据检索到的数量和分号设置括号)的主要内容,如果未能解决你的问题,请参考以下文章
如何设置webstorm以自动将分号添加到javascript函数,方法等