我需要将JSON数据保存到Oracle数据库。 JSON看起来像这样(见下文)。但它不会保持相同的格式。我可能会添加一些额外的节点或修改现有的节点。那么是否可以动态创建或修改oracle表以添加更多列?我打算用Java做到这一点。我将创建一个与JSON匹配的Java类,将JSON转换为Java对象并将其持久保存到表中。但是如何动态修改Java类呢?或者用PL / SQL做到这一点会更好吗? JSON来自移动设备到REST Web服务。
{"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}}
答案 0 :(得分:1)
我建议您避免创建新列,而是创建一个新表,其中包含每个新列的一个条目。我在这里假设新列将是菜单项。因此,您将拥有一个包含以下列的“菜单”表:
id file
你会有一个“menuitem”表,其中包含每个菜单项的一个条目:
id value onclick
因此,不是动态添加列,而是添加记录。
答案 1 :(得分:0)
我在评论中建议将您的方法更改为No MongoDB等NoSQL数据库。但是,如果您仍然觉得需要使用关系数据库,那么EAV model可能会指向正确的方向。
总而言之,您将拥有一个“帮助程序”表,用于存储实体所具有的列及其类型。
您不能修改Java类,但可以像Map一样定义类,并实现逻辑以添加所需的列。
PHP产品Magento在其数据库中使用EAV。
答案 2 :(得分:0)
Mongodb可能是您的最佳选择,或者您可以拥有一个大的TEXT字段,并且只提取您可能搜索的列。
但是,您可以为其他规范化数据创建表,并使用ALTER TABLE添加列。后者可能特别昂贵。
答案 3 :(得分:0)
使用https://github.com/zolekode/json-to-tables/。
您在这里:
import json
from core.extent_table import ExtentTable
from core.table_maker import TableMaker
menu = {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}
menu = json.dumps(menu)
menu = json.loads(menu)
extent_table = ExtentTable()
table_maker = TableMaker(extent_table)
table_maker.convert_json_object_to_table(menu, "menu")
table_maker.show_tables(8)
table_maker.save_tables("menu", export_as="sql", sql_connection="your_connection")
输出:
SHOWING TABLES :D
menu
ID id value popup
0 0 file File 0
1 1 None None None
____________________________________________________
popup
ID
0 0
1 1
____________________________________________________
popup_?_menuitem
ID PARENT_ID is_scalar scalar
0 0 0 False None
1 1 0 False None
2 2 0 False None
____________________________________________________
popup_?_menuitem_$_onclick
ID value onclick PARENT_ID
0 0 New CreateNewDoc() 0
1 1 Open OpenDoc() 1
2 2 Close CloseDoc() 2
3 3 None None None
____________________________________________________
答案 4 :(得分:0)
这可以在MYSQL数据库中完成:
此代码采用 JSON 输入字符串并自动生成 SQL Server CREATE TABLE 语句使其更容易 将序列化数据转换为数据库模式。
它并不完美,但应该在开始时提供一个不错的起点 处理新的 JSON 文件。
SET NOCOUNT ON;
DECLARE
@JsonData nvarchar(max) = '
{
"Id" : 1,
"IsActive":true,
"Ratio": 1.25,
"ActivityArray":[true,false,true],
"People" : ["Jim","Joan","John","Jeff"],
"Places" : [{"State":"Connecticut", "Capitol":"Hartford", "IsExpensive":true},{"State":"Ohio","Capitol":"Columbus","MajorCities":["Cleveland","Cincinnati"]}],
"Thing" : { "Type":"Foo", "Value" : "Bar" },
"Created_At":"2018-04-18T21:25:48Z"
}',
@RootTableName nvarchar(4000) = N'AppInstance',
@Schema nvarchar(128) = N'dbo',
@DefaultStringPadding smallint = 20;
DROP TABLE IF EXISTS ##parsedJson;
WITH jsonRoot AS (
SELECT
0 as parentLevel,
CONVERT(nvarchar(4000),NULL) COLLATE Latin1_General_BIN2 as parentTableName,
0 AS [level],
[type] ,
@RootTableName COLLATE Latin1_General_BIN2 AS TableName,
[key] COLLATE Latin1_General_BIN2 as ColumnName,
[value],
ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS ColumnSequence
FROM
OPENJSON(@JsonData, '$')
UNION ALL
SELECT
jsonRoot.[level] as parentLevel,
CONVERT(nvarchar(4000),jsonRoot.TableName) COLLATE Latin1_General_BIN2,
jsonRoot.[level]+1,
d.[type],
CASE WHEN jsonRoot.[type] IN (4,5) THEN CONVERT(nvarchar(4000),jsonRoot.ColumnName) ELSE jsonRoot.TableName END COLLATE Latin1_General_BIN2,
CASE WHEN jsonRoot.[type] IN (4) THEN jsonRoot.ColumnName ELSE d.[key] END,
d.[value],
ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS ColumnSequence
FROM
jsonRoot
CROSS APPLY OPENJSON(jsonRoot.[value], '$') d
WHERE
jsonRoot.[type] IN (4,5)
), IdRows AS (
SELECT
-2 as parentLevel,
null as parentTableName,
-1 as [level],
null as [type],
TableName as Tablename,
TableName+'Id' as columnName,
null as [value],
0 as columnsequence
FROM
(SELECT DISTINCT tablename FROM jsonRoot) j
), FKRows AS (
SELECT
DISTINCT -1 as parentLevel,
null as parentTableName,
-1 as [level],
null as [type],
TableName as Tablename,
parentTableName+'Id' as columnName,
null as [value],
0 as columnsequence
FROM
(SELECT DISTINCT tableName,parentTableName FROM jsonRoot) j
WHERE
parentTableName is not null
)
SELECT
*,
CASE [type]
WHEN 1 THEN
CASE WHEN TRY_CONVERT(datetime2, [value], 127) IS NULL THEN 'nvarchar' ELSE 'datetime2' END
WHEN 2 THEN
CASE WHEN TRY_CONVERT(int, [value]) IS NULL THEN 'float' ELSE 'int' END
WHEN 3 THEN
'bit'
END COLLATE Latin1_General_BIN2 AS DataType,
CASE [type]
WHEN 1 THEN
CASE WHEN TRY_CONVERT(datetime2, [value], 127) IS NULL THEN MAX(LEN([value])) OVER (PARTITION BY TableName, ColumnName) + @DefaultStringPadding ELSE NULL END
WHEN 2 THEN
NULL
WHEN 3 THEN
NULL
END AS DataTypePrecision
INTO ##parsedJson
FROM jsonRoot
WHERE
[type] in (1,2,3)
UNION ALL SELECT IdRows.parentLevel, IdRows.parentTableName, IdRows.[level], IdRows.[type], IdRows.TableName, IdRows.ColumnName, IdRows.[value], -10 AS ColumnSequence, 'int IDENTITY(1,1) PRIMARY KEY' as datatype, null as datatypeprecision FROM IdRows
UNION ALL SELECT FKRows.parentLevel, FKRows.parentTableName, FKRows.[level], FKRows.[type], FKRows.TableName, FKRows.ColumnName, FKRows.[value], -9 AS ColumnSequence, 'int' as datatype, null as datatypeprecision FROM FKRows
-- For debugging:
-- SELECT * FROM ##parsedJson ORDER BY ParentLevel, level, tablename, columnsequence
DECLARE @CreateStatements nvarchar(max);
SELECT
@CreateStatements = COALESCE(@CreateStatements + CHAR(13) + CHAR(13), '') +
'CREATE TABLE ' + @Schema + '.' + TableName + CHAR(13) + '(' + CHAR(13) +
STRING_AGG( ColumnName + ' ' + DataType + ISNULL('('+CAST(DataTypePrecision AS nvarchar(20))+')','') + CASE WHEN DataType like '%PRIMARY KEY%' THEN '' ELSE ' NULL' END, ','+CHAR(13)) WITHIN GROUP (ORDER BY ColumnSequence)
+ CHAR(13)+')'
FROM
(SELECT DISTINCT
j.TableName,
j.ColumnName,
MAX(j.ColumnSequence) AS ColumnSequence,
j.DataType,
j.DataTypePrecision,
j.[level]
FROM
##parsedJson j
CROSS APPLY (SELECT TOP 1 ParentTableName + 'Id' AS ColumnName FROM ##parsedJson p WHERE j.TableName = p.TableName ) p
GROUP BY
j.TableName, j.ColumnName,p.ColumnName, j.DataType, j.DataTypePrecision, j.[level]
) j
GROUP BY
TableName
PRINT @CreateStatements;
您可以在 https://bertwagner.com/posts/converting-json-to-sql-server-create-table-statements/
上找到解决方案在 JAVA 中也可以将 JSON 转换为 POJO 类:
包com.cooltrickshome;
2
导入 java.io.File;
3
导入 java.io.IOException;
4
导入 java.net.MalformedURLException;
5
导入 java.net.URL;
6
导入 org.jsonschema2pojo.DefaultGenerationConfig;
7
导入 org.jsonschema2pojo.GenerationConfig;
8
导入 org.jsonschema2pojo.Jackson2Annotator;
9
导入 org.jsonschema2pojo.SchemaGenerator;
10
导入 org.jsonschema2pojo.SchemaMapper;
11
导入 org.jsonschema2pojo.SchemaStore;
12
导入 org.jsonschema2pojo.SourceType;
13
导入 org.jsonschema2pojo.rules.RuleFactory;
14
导入 com.sun.codemodel.JCodeModel;
15
公共类 JsonToPojo {
16
/**
17
* @param 参数
18
*/
19
public static void main(String[] args) {
20
String packageName="com.cooltrickshome";
21
File inputJson= new File("."+File.separator+"input.json");
22
文件 outputPojoDirectory=new File("."+File.separator+"convertedPojo");
23
outputPojoDirectory.mkdirs();
24
试试{
25
new JsonToPojo().convert2JSON(inputJson.toURI().toURL(), outputPojoDirectory, packageName, inputJson.getName().replace(".json", ""));
26
} catch (IOException e) {
27
// TODO 自动生成的catch块
28
System.out.println("转pojo时遇到问题:"+e.getMessage());
29
e.printStackTrace();
30
}
31
}
32
public void convert2JSON(URL inputJson, File outputPojoDirectory, String packageName, String className) 抛出 IOException{
33
JCodeModel codeModel = new JCodeModel();
34
URL 源 = inputJson;
35
GenerationConfig config = new DefaultGenerationConfig() {
36
@覆盖
37
public boolean isGenerateBuilders() { // 通过覆盖方法设置配置选项
38
返回真;
39
}
40
public SourceType getSourceType(){
41
返回 SourceType.JSON;
42
}
43
};
44
SchemaMapper mapper = new SchemaMapper(new RuleFactory(config, new Jackson2Annotator(config), new SchemaStore()), new SchemaGenerator());
45
mapper.generate(codeModel, className, packageName, source);
46
codeModel.build(outputPojoDirectory);
47
}
48
}