【发布时间】:2019-05-31 13:40:16
【问题描述】:
我有一个查询(见下文),用于将输出创建为 XML。该查询处理具有多种列类型和数据的元数据 (EAV) 系统。
我需要这个查询的一个版本来生成 JSON 格式的输出
我已经尝试过了,但是遇到了问题。
1] 我需要将 nvarchar(max) 列数据转换为 nvarchar(4000) 这并不理想,这与我认为的串联有关。
2] XML 和 JSON 列数据未正确格式化为有效的 JSON。
我没有尝试过使用 OPENJSON 或 CTE,但愿意尝试一下。
我在 SQL Server 2017(见下文)中有一个用于创建 XMLdata 的查询,我需要更改它以将结果创建为 JSON。尝试了很多东西,但不太能得到它。感谢任何帮助。
已尝试查询 JSON 版本,但存在一些问题。 1] 我需要将 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
【问题讨论】:
-
如果您使用的是 SQL Server 2017,您可以访问
FOR JSON: Format Query Results as JSON with FOR JSON (SQL Server)。我建议从那里开始。请先尝试一下,如果遇到困难,请向我们展示您的尝试,解释为什么它们不起作用,并展示您追求的结果。 -
已经尝试使用 FOR JSON,但我无法让它工作。问题是数据是垂直存储的(因此是 CROSS APPLY)。有些列有多行数据,因此需要转换为 JSON 数组等。请查看我提供的查询,您应该能够明白我的意思。
-
我在您的帖子中看不到任何对
FOR JSON的引用来查看?也许您忘记粘贴该特定代码?请参阅我之前对我们需要什么的评论。 -
我曾尝试使用 FOR JSON,但我无法让它工作,我可以尝试找到我之前的尝试,但不确定它的用途,因为它不起作用。您不能只将 FOR XML 替换为 FOR JSON,因为存在差异,这意味着查询必须发生重大变化,这就是我坚持的重点。
-
请发布您的尝试,并向我们展示您所追求的预期结果。
标签: sql json sql-server xml