【问题标题】:How do I replace only part of string after specific string keeping part of string to replace in SQL?在特定字符串保留部分字符串以在 SQL 中替换后,如何仅替换部分字符串?
【发布时间】:2020-03-04 20:43:11
【问题描述】:

我有一个名为 user 的表,其中包含列数据。数据包含很长的字符串(它是一个嵌套在数据列中的 JSON 作为字符串)。在 fontSize 值是字符串的所有情况下,我想将 fontSize 键的所有值更改为 int,但必须保留 int 值。 所以基本上这就是我想做的:

{
  "id": 1,
  "name": "New Window",
  "resources": {
    "widgets": [
      {
        "id": 1,
        "color": "#ffffff",
        "fontSize": "5",
        "width": 150
      },
      {
        "id": 2,
        "color": "#aaaaaa",
        "fontSize": "10",
        "width": 200
      }
    ]
  }
}

改为:

{
  "id": 1,
  "name": "New Window",
  "resources": {
    "widgets": [
      {
        "id": 1,
        "color": "#ffffff",
        "fontSize": 5,
        "width": 150
      },
      {
        "id": 2,
        "color": "#aaaaaa",
        "fontSize": 10,
        "width": 200
      }
    ]
  }
}

在 fontSize 值是字符串的所有情况下(在某些情况下它已经是整数)。 fontsize的值不同,必须保留。

我知道逻辑。我必须在表用户中找到所有情况,其中数据列如'%“fontSize”:“%',然后在“fontSize”之后删除第一个“:模式和第一个”在数字之后。我该怎么做?在SQL中是否可能? 感谢您的帮助!

【问题讨论】:

  • 您使用的是哪个 dbms?
  • 我正在使用 PostgreSQL
  • @a_horse_with_no_name 好吧,我知道。问题是 Safari 浏览器将输入的值转换为字符串。我已经修好了,但我的模型还是坏了

标签: sql json regex postgresql replace


【解决方案1】:

这非常难看,并显示了一个用例,其中使用 JSON 对模型进行非规范化是一个不好的选择(如果这是一个正确的一对多关系,那么列 font_size 将被定义为一个整数,并且你一开始不会有这个问题)。


我唯一能想到的就是取消嵌套所有数组元素,将值更改为整数,将“小部件”聚合回数组并使用它来更新表。

以下代码假定您的表中有一个名为 id 的主键列。

第一步是将 fontSize 值替换为适当的整数。

select t.id, jsonb_set(w.jw, '{fontSize}', to_jsonb((w.jw ->> 'fontSize')::int))
from the_table t
  cross join jsonb_array_elements(t.the_value -> 'resources' -> 'widgets') as w(jw)

jsonb_array_elements() 将每个小部件作为单个 JSONB 值返回(在单独的行中)。 to_jsonb((w.jw ->> 'fontSize')::int 将键 fontSize 的当前值转换为整数,jsonb_set() 将其放回 JSON 值中。

给定您返回的示例数据(包括假定的主键列)

id | jsonb_set                                                  
---+------------------------------------------------------------
42 | {"id": 1, "color": "#ffffff", "width": 150, "fontSize": 5} 
42 | {"id": 2, "color": "#aaaaaa", "width": 200, "fontSize": 10}

现在可以将其聚合回一个数组:

select t.id, jsonb_agg(jsonb_set(w.jw, '{fontSize}', to_jsonb((w.jw ->> 'fontSize')::int))) as new_widgets
from the_table t
  cross join jsonb_array_elements(t.the_value -> 'resources' -> 'widgets') as w(jw)
group by id

鉴于上面的示例日期,现在返回:

id | new_widgets                                                                                                               
---+---------------------------------------------------------------------------------------------------------------------------
42 | [{"id": 1, "color": "#ffffff", "width": 150, "fontSize": 5}, {"id": 2, "color": "#aaaaaa", "width": 200, "fontSize": 10}] 

此查询现在可以用作 UPDATE 语句的来源,该语句再次使用 jsonb_set() 更改表中的值。

update the_table
  set the_value = jsonb_set(the_value, '{resources, widgets}', x.new_widgets)
from (  
  select t.id, jsonb_agg(jsonb_set(w.jw, '{fontSize}', to_jsonb((w.jw ->> 'fontSize')::int))) as new_widgets
  from the_table t
    cross join jsonb_array_elements(t.the_value -> 'resources' -> 'widgets') as w(jw)
  group by id
) as x
where x.id = the_table.id;

完整的在线示例:https://rextester.com/OIFOBX92774


如果您的列未定义为jsonb(应该是),则需要在上述查询中将其转换为the_column::jsonb

【讨论】:

    猜你喜欢
    • 2016-07-07
    • 2019-10-20
    • 1970-01-01
    • 2012-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多