简体   繁体   English

如何从存储为 json 数据的字符串中提取字符并将它们放在 SQL 服务器中的动态列数中

[英]How to extract characters from a string stored as json data and place them in dynamic number of columns in SQL Server

I have a column of string in SQL Server that stores JSON data with all the braces and colons included.我在SQL Server中有一列字符串,它存储JSON数据,其中包含所有大括号和冒号。

My problem is to extract all the key and value pairs and store them in separate columns with the key as the column header.我的问题是提取所有键和值对并将它们存储在单独的列中,键作为列 header。 What makes this challenging is that every record has different number of key/value pairs.使这个具有挑战性的是,每条记录都有不同数量的key/value对。

For example in the image below showing 3 records, the first record has 5 key/value pairs- EndUseCommunityMarket of 2 , EndUseProvincial Market of 0 , and so on.例如,在下图中显示 3 条记录,第一条记录有 5 个键/值对 - EndUseCommunityMarket of 2EndUseProvincial Market of 0 ,依此类推。 The second record has 1 key/value pair, and the third record has two key/value pairs.第二条记录有 1 个键/值对,第三条记录有两个键/值对。

在此处输入图像描述

If I have to show how I want this in excel it would be like:如果我必须在 excel 中展示我想要的效果,那就是:

在此处输入图像描述

I have seen some SQL code examples that does something similar but for a fixed number of columns, unlike this one it varies for every record.我见过一些 SQL 代码示例,它们执行类似的操作,但列数固定,与此不同,它对每条记录都不同。

Please I need a SQL statement that can achieve this as I am working on thousands of records.请我需要一个 SQL 语句来实现这一点,因为我正在处理数千条记录。

Below is this data copied from sql server :以下是从sql server复制的数据:

catch_ext
{"NfdsFadMonitoring":{"EndUseEaten":1}}
{"NfdsFadMonitoring":{"EndUseCommunityMarket":3}}
{"NfdsFadMonitoring":{"SpeciesComment":"","EndUseCommunityMarket":2}}
{"NfdsFadMonitoring":{"SpeciesComment":"mix reef fis","EndUseEaten":31}}
{"NfdsFadMonitoring":{"SpeciesComment":"10 fish with a total of 18kg","EndUseCommunityMarket":0,"EndUseProvincialMarket":0,"EndUseUrbanMarket":8,"EndUseEaten":1,"EndUseGivenAway":1}}
{"NfdsFadMonitoring":{"SpeciesComment":"mix reef fis","EndUseEaten":18}}

I expect you don't want to dynamically create a table, instead you probably want to create a property mapping table.我希望您不想动态创建表,而是您可能想创建一个属性映射表。 Here is a quick overview of the design.这是设计的快速概述。

Object table -- this stores the base information about your object
============
ID            -- unique id field for every object.
Name

Property types table -- this stores all the property types
====================
Property_Type_ID -- unique type id
Description      -- describes property

Object2Property -- stores the values for each property
===============
ObjectID -- the object
Property_Type_ID -- the property type
Value -- the value.

Using a model like this lets your properties be as dynamic as you wish but you don't have to create columns dynamically -- something that is hard and error prone.像这样使用 model 可以让您的属性像您希望的那样动态,但您不必动态创建列——这很难且容易出错。

using your specific example the tables would look like this使用您的具体示例,表格看起来像这样

OBJECT 
ID     NAME
1      WHAOO
2      RED SNAMPPER
3      KAWAKAWA

Property Types
ID     DESC
1      EndUseCommunityMarket
2      EndUseProvincialMarket 
3      EndUseUrbanMarket
4      EndUseEaten
5      EndUseGivenAway
6      Comment

Map
ObjID   TypeID   Value
1        1       2  
1        2       0
1        3       0
1        4       0
1        5       0
2        2       50
3        3       8
3        5       1

A. ROWS A. 行

Dynamic columns are a lot like rows.动态列很像行。

You could use OPENJSON (Transact-SQL)您可以使用OPENJSON (Transact-SQL)

DECLARE @json2 NVARCHAR(4000) = N'{"NfdsFadMonitoring":{"SpeciesComment":"10 fish with a total of 18kg","EndUseCommunityMarket":0,"EndUseProvincialMarket":0,"EndUseUrbanMarket":8,"EndUseEaten":1,"EndUseGivenAway":1}}';

SELECT [key], value
FROM OPENJSON(@json2,'lax $.NfdsFadMonitoring')

Output Output

key value
SpeciesComment  10 fish with a total of 18kg
EndUseCommunityMarket   0
EndUseProvincialMarket  0
EndUseUrbanMarket   8
EndUseEaten 1
EndUseGivenAway 1

Your inputs您的输入

CREATE TABLE ForEloga (Id int,Json nvarchar(max));

Insert into ForEloga Values 
(1,'{"NfdsFadMonitoring":{"EndUseEaten":1}}'),
(2,'{"NfdsFadMonitoring":{"EndUseCommunityMarket":3}}'),
(3,'{"NfdsFadMonitoring":{"SpeciesComment":"","EndUseCommunityMarket":2}}'),
(4,'{"NfdsFadMonitoring":{"SpeciesComment":"mix reef fis","EndUseEaten":31}}'),
(5,'{"NfdsFadMonitoring":{"SpeciesComment":"10 fish with a total of 18kg","EndUseCommunityMarket":0,"EndUseProvincialMarket":0,"EndUseUrbanMarket":8,"EndUseEaten":1,"EndUseGivenAway":1}}'),
(6,'{"NfdsFadMonitoring":{"SpeciesComment":"mix reef fis","EndUseEaten":18}}');

SELECT Id, [key], value
FROM ForEloga CROSS APPLY OPENJSON(Json,'lax $.NfdsFadMonitoring')

Output Output

Id  key value
1   EndUseEaten 1
2   EndUseCommunityMarket   3
3   SpeciesComment  
3   EndUseCommunityMarket   2
4   SpeciesComment  mix reef fis
4   EndUseEaten 31
5   SpeciesComment  10 fish with a total of 18kg
5   EndUseCommunityMarket   0
5   EndUseProvincialMarket  0
5   EndUseUrbanMarket   8
5   EndUseEaten 1
5   EndUseGivenAway 1
6   SpeciesComment  mix reef fis
6   EndUseEaten 18

B. COLUMNS: CROSS APPLY WITH WITH B. 列:与WITH交叉应用

If you know all possible properties then I recommend CROSS APPLY with WITH as shown in Example 3 - Join rows with JSON data stored in table cells using CROSS APPLY in OPENJSON (Transact-SQL) .如果您知道所有可能的属性,那么我建议使用WITH进行CROSS APPLY ,如示例 3 所示 - 使用OPENJSON (Transact-SQL)中的CROSS APPLY 将存储在表格单元格中的 JSON 数据加入行

 SELECT store.title, location.street, location.lat, location.long FROM store CROSS APPLY OPENJSON(store.jsonCol, 'lax $.location') WITH ( street varchar(500), postcode varchar(500) '$.postcode', lon int '$.geo.longitude', lat int '$.geo.latitude' ) AS location

Try this:尝试这个:

Table Schema:表架构:

CREATE TABLE #JsonValue(sp_name VARCHAR(100),catch_ext VARCHAR(1000))

INSERT INTO #JsonValue VALUES ('WAHOO','{"NfdsFadMonitoring":{"EndUseEaten":1}}')
INSERT INTO #JsonValue VALUES ('RUBY SNAPPER','{"NfdsFadMonitoring":{"EndUseCommunityMarket":3}}')
INSERT INTO #JsonValue VALUES ('KAWAKAWA','{"NfdsFadMonitoring":{"SpeciesComment":"","EndUseCommunityMarket":2}}')
INSERT INTO #JsonValue VALUES ('XXXXXXXX','{"NfdsFadMonitoring":{"SpeciesComment":"mix reef fis","EndUseEaten":31}}')
INSERT INTO #JsonValue VALUES ('YYYYYYYY','{"NfdsFadMonitoring":{"SpeciesComment":"10 fish with a total of 18kg","EndUseCommunityMarket":0,"EndUseProvincialMarket":0,"EndUseUrbanMarket":8,"EndUseEaten":1,"EndUseGivenAway":1}}')
INSERT INTO #JsonValue VALUES ('ZZZZZZZZZZ','{"NfdsFadMonitoring":{"SpeciesComment":"mix reef fis","EndUseEaten":18}}')

Query:询问:

SELECT sp_name
    ,ISNULL(MAX(CASE WHEN [Key]='EndUseCommunityMarket' THEN Value END),'')EndUseCommunityMarket
    ,ISNULL(MAX(CASE WHEN [Key]='EndUseProvincialMarket' THEN Value END),'')EndUseProvincialMarket
    ,ISNULL(MAX(CASE WHEN [Key]='EndUseUrbanMarket' THEN Value END),'')EndUseUrbanMarket
    ,ISNULL(MAX(CASE WHEN [Key]='EndUseEaten' THEN Value END),'')EndUseEaten
    ,ISNULL(MAX(CASE WHEN [Key]='EndUseGivenAway' THEN Value END),'')EndUseGivenAway
FROM(
    SELECT sp_name, [key], value
    FROM #JsonValue CROSS APPLY OPENJSON(catch_ext,'$.NfdsFadMonitoring')
    )D
GROUP BY sp_name

Output: Output:

sp_name       EndUseCommunityMarket EndUseProvincialMarket EndUseUrbanMarket EndUseEaten EndUseGivenAway
------------- --------------------- ---------------------- ----------------- ----------- ---------------
KAWAKAWA      2                                                                          
RUBY SNAPPER  3                                                                          
WAHOO                                                                        1           
XXXXXXXX                                                                     31          
YYYYYYYY      0                     0                      8                 1           1
ZZZZZZZZZZ                                                                   18  

Hope this will help you.希望这会帮助你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM