我有一个查询(见下文),用于创建XML输出。该查询处理的是matadata(EAV)系统,该系统具有多种列类型和数据。
我需要此查询的版本以将输出生成为JSON
我已经试过了,但是遇到了问题。
1]我需要将nvarchar(max)列数据转换为nvarchar(4000),这并不理想,这与我认为的串联有关。
2] XML和JSON列数据的格式没有正确设置为有效JSON。
我没有尝试使用OPENJSON或CTE,但愿意尝试任何事情。
我在SQL Server 2017中有一个查询(请参阅下文),该查询曾用于创建XMLdata,我需要更改它以将结果创建为JSON。尝试了很多东西,但还不能完全解决。感谢任何帮助。
已经尝试查询JSON版本,但是存在一些问题。 1]我需要CAST nvarchar为4000,否则它会截断数据(不理想)。 2]无法获取xml和json类型的列以产生正确的输出。
没有尝试使用OPENJSON或CTE,但可以接受想法。
-- structure
DECLARE @metaFields TABLE(
[metaFieldID] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[metasetID] [uniqueidentifier] NOT NULL,
[metaColumnID] [uniqueidentifier] NOT NULL,
[systemRef] [varchar](255) NOT NULL,
[displayType] [varchar](50) NOT NULL
)
DECLARE @metaColumns TABLE (
[metaColumnID] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[storageTable] [varchar](255) NOT NULL,
[storageColumn] [varchar](255) NOT NULL,
[storageType] [varchar](10) NOT NULL,
[storageSize] [smallint] NULL
)
DECLARE @metaDataObjectVersions TABLE (
[metaDataObjectVersionID] [int] NOT NULL,
[xmlVersionData] [xml] NULL
)
DECLARE @metaData TABLE (
[metaDataID] [int] NOT NULL,
[metaDataObjectVersionID] [int] NOT NULL,
[metaColumnID] [uniqueidentifier] NOT NULL,
[numericData] [real] NULL,
[dateData] [datetime] NULL,
[textData] [nvarchar](max) NULL,
[GUIDData] [uniqueidentifier] NULL,
[xmlData] [xml] NULL,
[jsonData] [nvarchar](max) NULL
)
-- data
INSERT INTO @metaFields
([metaFieldID],[metasetID],[metaColumnID],[systemRef],[displayType])
VALUES
('FFFFFFFF-0000-0000-0000-000000000001','AAAAAAAA-0000-0000-0000-000000000001','CCCCCCCC-0000-0000-0000-000000000001','ACTIVE','RADIOBUTTON'),
('FFFFFFFF-0000-0000-0000-000000000002','AAAAAAAA-0000-0000-0000-000000000001','CCCCCCCC-0000-0000-0000-000000000002','CREATED','TEXT'),
('FFFFFFFF-0000-0000-0000-000000000003','AAAAAAAA-0000-0000-0000-000000000001','CCCCCCCC-0000-0000-0000-000000000003','CONTENT','TEXTAREA'),
('FFFFFFFF-0000-0000-0000-000000000004','AAAAAAAA-0000-0000-0000-000000000001','CCCCCCCC-0000-0000-0000-000000000004','TAGS','TEXT'),
('FFFFFFFF-0000-0000-0000-000000000005','AAAAAAAA-0000-0000-0000-000000000001','CCCCCCCC-0000-0000-0000-000000000005','XOPTIONS','SELECTBOX'),
('FFFFFFFF-0000-0000-0000-000000000006','AAAAAAAA-0000-0000-0000-000000000001','CCCCCCCC-0000-0000-0000-000000000006','JOPTIONS','SELECTBOX')
INSERT INTO @metaColumns
([metaColumnID],[storageTable],[storageColumn],[storageType],[storageSize])
VALUES
('CCCCCCCC-0000-0000-0000-000000000001','METADATA','numericData','numeric',NULL),
('CCCCCCCC-0000-0000-0000-000000000002','METADATA','dateData','date',NULL),
('CCCCCCCC-0000-0000-0000-000000000003','METADATA','textData','text',NULL),
('CCCCCCCC-0000-0000-0000-000000000004','METADATA','GUIDData','guid',NULL),
('CCCCCCCC-0000-0000-0000-000000000005','METADATA','xmlData','text',NULL),
('CCCCCCCC-0000-0000-0000-000000000006','METADATA','jsonData','text',NULL)
INSERT INTO @metaDataObjectVersions
([metaDataObjectVersionID],[xmlVersionData])
VALUES
(1,'<data><active>1</active><created>2019-01-01</created><content><html><head><title> HTML Document</title></head><body><p>HTML document</p></body></html></content><tags>37C3879F-CF6E-4A5D-BD3C-FCEA1D9F2233,37C3879F-CF6E-4A5D-BD3C-FCEA1D9F2244</tags><xoptions><rows><row id="37c3879f-cf6e-4a5d-bd3c-fcea1d9f2233"><optionValue>Usage 1</optionValue><sorting>1</sorting><selected>1</selected></row></rows></xoptions><joptions>[{"id": 1,"value": "Option 1","selected": true},{"id": 1,"value": "Option 1","selected": false }]</joptions></data>'),
(2,'<data><active>0</active><content><html><head><title> HTML Document2</title></head><body><p>HTML document2</p></body></html></content><tags>37C3879F-CF6E-4A5D-BD3C-FCEA1D9F4433</tags><xoptions/><joptions>[{"id": 3,"value": "Option 3","selected": true}]</joptions></data>')
INSERT INTO @metaData
([metaDataID],[metaDataObjectVersionID],[metaColumnID],[numericData],[dateData],[textData],[GUIDData],[xmlData],[jsonData])
VALUES
(1,1,'CCCCCCCC-0000-0000-0000-000000000001',1,NULL,NULL,NULL,NULL,NULL),
(2,1,'CCCCCCCC-0000-0000-0000-000000000002',NULL,'2019-01-01',NULL,NULL,NULL,NULL),
(3,1,'CCCCCCCC-0000-0000-0000-000000000003',NULL,NULL,'<html><head><title> HTML Document</title></head><body><p>HTML document</p></body></html>',NULL,NULL,NULL),
(4,1,'CCCCCCCC-0000-0000-0000-000000000004',NULL,NULL,NULL,'37C3879F-CF6E-4A5D-BD3C-FCEA1D9F2233',NULL,NULL),
(5,1,'CCCCCCCC-0000-0000-0000-000000000004',NULL,NULL,NULL,'37C3879F-CF6E-4A5D-BD3C-FCEA1D9F2244',NULL,NULL),
(6,1,'CCCCCCCC-0000-0000-0000-000000000005',NULL,NULL,NULL,NULL,'<rows><row id="37c3879f-cf6e-4a5d-bd3c-fcea1d9f2233"><optionValue>Usage 1</optionValue><sorting>1</sorting><selected>1</selected></row></rows>',NULL),--<rows><row id="37c3879f-cf6e-4a5d-bd3c-fcea1d9f2233"><optionValue>Usage 1</optionValue><sorting>1</sorting><selected>1</selected></row></rows>
(7,1,'CCCCCCCC-0000-0000-0000-000000000006',NULL,NULL,NULL,NULL,NULL,'[{"id": 1,"value": "Option 1","selected": true},{"id": 1,"value": "Option 1","selected": false }]'),
(8,2,'CCCCCCCC-0000-0000-0000-000000000001',0,NULL,NULL,NULL,NULL,NULL),
(9,2,'CCCCCCCC-0000-0000-0000-000000000003',NULL,NULL,'<html><head><title> HTML Document2</title></head><body><p>HTML document2</p></body></html>',NULL,NULL,NULL),
(10,2,'CCCCCCCC-0000-0000-0000-000000000004',NULL,NULL,NULL,'37C3879F-CF6E-4A5D-BD3C-FCEA1D9F4433',NULL,NULL),
(11,2,'CCCCCCCC-0000-0000-0000-000000000005',NULL,NULL,NULL,NULL,NULL,NULL),
(12,2,'CCCCCCCC-0000-0000-0000-000000000006',NULL,NULL,NULL,NULL,NULL,'[{"id": 3,"value": "Option 3","selected": true}]')
-- EXISTING XML QUERY
SELECT metaDataObjectVersionID,
CAST(metaObjectVersionData AS XML) AS versionData
FROM (
SELECT MD.metaDataObjectVersionID,
(
SELECT CAST('<' + LOWER(MF.systemRef) + '>' + LEFT(DATA.col, LEN(DATA.col) - 1) + '</' + LOWER(MF.systemRef) + '>' AS XML)
FROM @metaData MD1
INNER JOIN @metaFields MF ON (MF.metaColumnID = MD1.metaColumnID)
CROSS APPLY (
SELECT CASE (SELECT MC.storageColumn FROM @metaColumns MC WHERE MC.metaColumnID = MD2.metaColumnID)
WHEN 'numericData' THEN ISNULL(CAST(numericData AS NVARCHAR(MAX)), '')
WHEN 'dateData' THEN ISNULL(CAST(dateData AS NVARCHAR(MAX)), '')
WHEN 'textData' THEN ISNULL(CAST(textData AS NVARCHAR(MAX)), '')
WHEN 'guidData' THEN ISNULL(CAST(guidData AS VARCHAR(36)), '')
WHEN 'xmlData' THEN ISNULL(CAST(xmlData AS NVARCHAR(MAX)), '')
WHEN 'jsonData' THEN ISNULL(CAST(jsonData AS NVARCHAR(MAX)), '')
ELSE CAST('' AS VARCHAR(36)) END + ','
FROM @metaData MD2
WHERE MD2.metaDataObjectVersionID = MD1.metaDataObjectVersionID AND MD2.metaColumnID = MD1.metaColumnID
FOR XML PATH('')
) AS DATA(col)
WHERE MD1.metaDataObjectVersionID = MD.metaDataObjectVersionID
GROUP BY MF.systemRef,
DATA.col
FOR XML PATH(''), ROOT('data')
) AS metaObjectVersionData
FROM @metaData MD
GROUP BY MD.metaDataObjectVersionID
) VW
-- JSON QUERY SO FAR
SELECT A.metaDataObjectVersionID, MDOV.xmlVersionData, N'{' + metaObjectVersionData + N'}' AS JSONVersionData
FROM (
SELECT MD.metaDataObjectVersionID,
(
SELECT QUOTENAME(LOWER(MF.systemRef),'"') + ':' + LEFT(DATA.col, LEN(DATA.col))
FROM @metaData MD1
INNER JOIN @metaFields MF ON (MF.metaColumnID = MD1.metaColumnID)
CROSS APPLY (
SELECT CASE (SELECT MC.storageColumn FROM @metaColumns MC WHERE MC.metaColumnID = MD2.metaColumnID)
WHEN 'numericData' THEN CAST(numericData AS NVARCHAR(MAX))
WHEN 'dateData' THEN QUOTENAME(CAST(dateData AS NVARCHAR(MAX)),'"')
WHEN 'textData' THEN QUOTENAME(CAST(textData AS NVARCHAR(4000)),'"')
WHEN 'guidData' THEN QUOTENAME(CAST(guidData AS VARCHAR(36)),'"')
WHEN 'xmlData' THEN QUOTENAME(STRING_ESCAPE(CAST(xmlData AS NVARCHAR(MAX)),'json'),'"')
WHEN 'jsonData' THEN jsonData
ELSE CAST('' AS VARCHAR(36))
END + ','
FROM @metaData MD2
WHERE MD2.metaDataObjectVersionID = MD1.metaDataObjectVersionID AND MD2.metaColumnID = MD1.metaColumnID
FOR XML PATH('')
) AS DATA(col)
WHERE MD1.metaDataObjectVersionID = MD.metaDataObjectVersionID
GROUP BY MF.systemRef,
DATA.col
FOR XML PATH('')
) AS metaObjectVersionData
FROM @metaData MD
GROUP BY MD.metaDataObjectVersionID
) A
JOIN @metaDataObjectVersions MDOV ON A.metaDataObjectVersionID = MDOV.metaDataObjectVersionID
我希望输出格式正确且JSON有效。正确的预期格式如下:
{
"active": 1,
"content": "<html><head ><title> HTML Document</title></head><body><p>HTML document</p><a href=\"https://www.w3schools.com\">This is a link</a></body></html>",
"created": "Jan 1 2019 12:00AM",
"joptions": [
{
"id": 1,
"value": "Option 1",
"selected": true
},
{
"id": 1,
"value": "Option 1",
"selected": false
}
],
"tags": [
"37C3879F-CF6E-4A5D-BD3C-FCEA1D9F2233",
"37C3879F-CF6E-4A5D-BD3C-FCEA1D9F2244"
],
"xoptions": "<rows><row id=\"37c3879f-cf6e-4a5d-bd3c-fcea1d9f2233\"><optionValue>Usage 1</optionValue> <sorting>1</sorting><selected>1</selected></row></rows>"
}
我现在有一个有效的查询,但看起来有点混乱。如果有人可以提出改进建议,请发表评论。
--THIS IS THE QUERY WHICH SEEMS TO WORK!!!
SELECT MDOV.metaDataObjectVersionID,
'{' + STRING_AGG(QUOTENAME(LOWER(MD1.systemRef),'"') + ' : ' +
CASE
WHEN MD1.storageColumn = 'numericData' THEN CASE WHEN CNT > 1 THEN '[' + MD1.numericData + ']' ELSE MD1.numericData END
WHEN MD1.storageColumn = 'dateData' THEN CASE WHEN CNT > 1 THEN '[' + MD1.dateData + ']' ELSE MD1.dateData END
WHEN MD1.storageColumn = 'textData' THEN CASE WHEN CNT > 1 THEN '[' + MD1.textData + ']' ELSE MD1.textData END
WHEN MD1.storageColumn = 'guidData' THEN CASE WHEN CNT > 1 THEN '[' + MD1.guidData + ']' ELSE MD1.guidData END
WHEN MD1.storageColumn = 'xmlData' THEN CASE WHEN CNT > 1 THEN '[' + MD1.xmlData + ']' ELSE MD1.xmlData END
WHEN MD1.storageColumn = 'jsonData' THEN CASE WHEN CNT > 1 THEN '[' + MD1.jsonData + ']' ELSE MD1.jsonData END
END ,',') + '}'
FROM @metaDataObjectVersions MDOV
CROSS APPLY (
SELECT MD2.metaDataObjectVersionID,MF.systemRef,MD2.metaColumnID,MC.storageColumn,
COUNT(*) AS CNT,
STRING_AGG(CONVERT(VARCHAR,numericData), ',') AS numericData,
STRING_AGG('"' + CONVERT(VARCHAR, dateData,121) + '"', ',') AS dateData,
STRING_AGG('"' + CONVERT(CHAR(36),guidData) + '"', ',') AS guidData,
STRING_AGG('"' + STRING_ESCAPE(textData, 'json') + '"', ',') AS textData,
STRING_AGG('"' + STRING_ESCAPE(CONVERT(NVARCHAR(MAX),xmlData), 'json') + '"', ',') AS xmlData,
STRING_AGG('"' + STRING_ESCAPE(jsonData, 'json') + '"', ',') AS jsonData
FROM @metaData MD2
JOIN @metaFields MF ON MD2.metaColumnID = MF.metaColumnID
JOIN @metaColumns MC ON MD2.metaColumnID = MC.metaColumnID
WHERE MD2.metaDataObjectVersionID = MDOV.metaDataObjectVersionID
GROUP BY MD2.metaDataObjectVersionID,MF.systemRef,MD2.metaColumnID,MC.storageColumn
) MD1
GROUP BY MDOV.metaDataObjectVersionID
ORDER BY MDOV.metaDataObjectVersionID
答案 0 :(得分:0)
我花了一些时间,但是有很多问题。请在您的问题中添加一些详细信息:
XML的转义真的很奇怪,XML类型的列是带转义序列的字符串还是真实的XML?最困难的部分是列命名。 XML和JSON需要事先知道这些名称。您可以通过CAST('<' + SomeName + '>' AS XML)
使用技巧,这可以解决,但您可以通过以下方式打开通往地狱的门...
您自己的查询在这里引入了一个巨大的问题。您得到类似
<content>&lt;html&gt;&lt;head&...
您真的要在XML中存储字符串XML 吗?
另一个问题,当您尝试在XML,字符串和JSON之间使用强制转换时,引号的类型是。双引号不能直接在JSON中使用(需要转义),但是XML也可以很好地使用单引号...这将需要大量的IF/CASE
...
有些标签具有多个数组值(例如"tags":[Val1,Val2]
),FOR JSON
不支持。
至少,我敢肯定,您的查询可以简化。试试这个:
SELECT ov.metaDataObjectVersionID
,(
SELECT CAST(
CONCAT('<'
,LOWER(MF.systemRef)
,'>'
,(SELECT
CONCAT(numericData
,dateData
,CAST(textData AS XML).value('.','nvarchar(max)')
,GUIDData
,xmlData.value('.','nvarchar(max)')
,jsonData
,'') FOR XML PATH(''))
,'</'
,LOWER(MF.systemRef)
,'>') AS XML)
FROM @metaData MD1
INNER JOIN @metaFields MF ON (MF.metaColumnID = MD1.metaColumnID)
WHERE MD1.metaDataObjectVersionID = ov.metaDataObjectVersionID
FOR XML PATH(''), ROOT('data'),TYPE
) AS metaObjectVersionDataXML
FROM @metaDataObjectVersions ov;
metaDataObjectVersionID=1
<data>
<active>1</active>
<created>Jan 1 2019 12:00AM</created>
<content><html><head><title> HTML Document</title></head><body><p>HTML document</p></body></html></content>
<tags>37C3879F-CF6E-4A5D-BD3C-FCEA1D9F2233</tags>
<tags>37C3879F-CF6E-4A5D-BD3C-FCEA1D9F2244</tags>
<xoptions><rows><row id="37c3879f-cf6e-4a5d-bd3c-fcea1d9f2233"><optionValue>Usage 1</optionValue><sorting>1</sorting><selected>1</selected></row></rows></xoptions>
<joptions>[{"id": 1,"value": "Option 1","selected": true},{"id": 1,"value": "Option 1","selected": false }]</joptions>
</data>
嗯,tags
看起来并不像您所需要的,但这可以解决...
我会尝试使用XQuery / FLWOR语句从本机XML中创建JSON,但是在尝试做更多事情之前,请您回答我的问题。
答案 1 :(得分:0)
对不起,但这不是我在问题中要的。您产生的xml实际上是无效的。我已经在Jason中找到了很好的解决方案。无论如何,谢谢,我现在将关闭它。