编辑输出(根据检索到的数量和分号设置括号)

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

这个查询所做的是扩展前一个查询。它使用分析函数COUNTROW_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函数,方法等

在 MS Access 中以分号分隔的列表检索电子邮件地址的子查询

无需括号与分号的XSS

我看到花括号、括号和分号彼此相邻,为啥?

html中的大括号和百分号是啥意思?

类声明大括号后的分号