提供表格:
C1 C2 C3
----------------
1 'v1' 1.1
2 'v2' 2.2
3 'v3' 3.3
是否有任何“简便”的方式来以这种格式返回JSON:
{
"columns": [ "C1", "C2", "C3" ],
"rows": [
[ 1, "v1", 1.1 ],
[ 2, "v2", 2.2 ],
[ 3, "v3", 3.3 ]
]
}
要从表中生成具有单个值的数组,有一个巧妙的技巧,如下所示:
SELECT JSON_QUERY(REPLACE(REPLACE(
(
SELECT id
FROM table a
WHERE pk in (1,2)
FOR JSON PATH
), '{"id":',''),'}','')) 'ids'
哪个生成
"ids": [1,2]
但是要在替换之上构造嵌套数组确实很繁琐,有人知道实现此目的的好方法吗?
答案 0 :(得分:1)
好吧,您要求一种简便的方法,但以下操作并非易事:-)
棘手的部分是知道哪些值需要qout,哪些可以保持 naked 。
这需要通用的类型分析来查找哪些值是字符串。
我知道获取元数据的唯一方法(除了使用INFORMATIONSCHEMA.COLUMNS
之类的元视图来构建动态sql之外)是XML和AUTO模式。
此XML实际上非常接近您的需求。开头有一个列列表,然后是行列表。但这当然不是JSON ...
尝试一下:
-这是一个包含您提供的值的模型表。
DECLARE @mockup TABLE(C1 INT,C2 VARCHAR(100),C3 DECIMAL(4,2));
INSERT INTO @mockup VALUES
(1,'v1',1.1)
,(2,'v2',2.2)
,(3,'v3',3.3);
-现在我们以此为基础创建XML
DECLARE @xml XML =
(
SELECT *
FROM @mockup t
FOR XML RAW,XMLSCHEMA,TYPE
);
-使用SELECT @xml
检查XML的内容以查看其内部外观
-现在可以开始实际查询了:
SELECT '{"columns":[' +
STUFF(@xml.query('declare namespace xsd="http://www.w3.org/2001/XMLSchema";
for $col in /xsd:schema/xsd:element//xsd:attribute
return
<x>,{concat("""",xs:string($col/@name),"""")}</x>
').value('.','nvarchar(max)'),1,1,'') +
'],"rows":[' +
STUFF(
(
SELECT
',[' + STUFF(b.query(' declare namespace xsd="http://www.w3.org/2001/XMLSchema";
for $attr in ./@*
return
<x>,{if(/xsd:schema/xsd:element//xsd:attribute[@name=local-name($attr)]//xsd:restriction/@base="sqltypes:varchar") then
concat("""",$attr,"""")
else
xs:string($attr)
}
</x>
').value('.','nvarchar(max)'),1,1,'') + ']'
FROM @xml.nodes('/*:row') B(b)
FOR XML PATH(''),TYPE
).value('.','nvarchar(max)'),1,1,'') +
']}';
结果
{"columns":["C1","C2","C3"],"rows":[[3,"v3",3.30],[1,"v1",1.10],[2,"v2",2.20]]}
第一部分将使用XQuery
查找所有列(XML模式中的xsd:attribute
)并创建列名称数组。
第二部分将再次使用XQuery
,以便遍历所有行并将其列值写入串联的字符串中。每个值都可以引用其在模式中的类型。每当此类型为sqltypes:varchar
时,该值都会被加引号。所有其他值均保持不变。
这一般不会解决每种情况...
说实话,这更多是出于我自己的好奇心:-)想找出一种解决方法。
最好的答案可能是:使用其他工具。 SQL-Server不是这里的最佳选择;-)