質問:MS SQL 2014でSQLクエリからJSONを生成する最適なソリューションは何ですか?プロシージャを作成しましたが、非常に時間がかかります。
私の例:
DECLARE @customers xml;
DECLARE @json NVARCHAR(max);
SET @customers = (SELECT * FROM dbo.Customers FOR XML path, root)
EXEC [dbo].[HTTP_JSON] @customers, @json
EXEC [dbo].[HTTP_JSON](@Shopping)
Create PROCEDURE [dbo].[HTTP_JSON]
@parameters xml, @response NVARCHAR(max) OUTPUT
WITH EXEC AS CALLER
AS
set @response = (SELECT Stuff(
(SELECT * from
(SELECT ',
{'+
Stuff((SELECT ',"'+coalesce(b.c.value('local-name(.)', 'NVARCHAR(MAX)'),'')+'":"'+
b.c.value('text()[1]','NVARCHAR(MAX)') +'"'
from x.a.nodes('*') b(c)
for xml path(''),TYPE).value('(./text())[1]','NVARCHAR(MAX)')
,1,1,'')+'}'
from @parameters.nodes('/root/*') x(a)
) JSON(theLine)
for xml path(''),TYPE).value('.','NVARCHAR(MAX)' )
,1,1,''))
GO
楽しみのために、以前の答えに基づいてスカラー関数を作成しました。
明らかなXMLパラメーターとは別に、2つの追加を追加しました:1)ヘッダーを含める(以下に示す)、2)ToLowerケース(クラスにリンクする小文字のJSONフィールド名を好む)。
クエリが複数のレコードである場合、フォーマットされた配列が返されます。
Declare @Table table (ID int,Active bit,First_Name varchar(50),Last_Name varchar(50),EMail varchar(50))
Insert into @Table values
(1,1,'John','Smith','[email protected]'),
(2,0,'Jane','Doe' ,'[email protected]')
Select A.ID
,A.Last_Name
,A.First_Name
,B.JSON
From @Table A
Cross Apply (Select JSON=[dbo].[udf-Str-JSON](0,1,(Select A.* For XML Raw)) ) B
返品
ID Last_Name First_Name JSON
1 Smith John {"id":"1","active":"1","first_name":"John","last_name":"Smith","email":"[email protected]"}
2 Doe Jane {"id":"2","active":"0","first_name":"Jane","last_name":"Doe","email":"[email protected]"}
またはさらに簡単に
Select JSON=[dbo].[udf-Str-JSON](0,1,(Select * From @Table for XML RAW))
ヘッダーがオンの状態で戻る
{
"status": {
"successful": "true",
"timestamp": "2016-10-09 06:08:16 GMT",
"rows": "2"
},
"results": [{
"id": "1",
"active": "1",
"first_name": "John",
"last_name": "Smith",
"email": "[email protected]"
}, {
"id": "2",
"active": "0",
"first_name": "Jane",
"last_name": "Doe",
"email": "[email protected]"
}]
}
ヘッダーがオフの状態で戻る
[{
"id": "1",
"active": "1",
"first_name": "John",
"last_name": "Smith",
"email": "[email protected]"
}, {
"id": "2",
"active": "0",
"first_name": "Jane",
"last_name": "Doe",
"email": "[email protected]"
}]
DF
ALTER FUNCTION [dbo].[udf-Str-JSON] (@IncludeHead int,@ToLowerCase int,@XML xml)
Returns varchar(max)
AS
Begin
Declare @Head varchar(max) = '',@JSON varchar(max) = ''
; with cteEAV as (Select RowNr=Row_Number() over (Order By (Select NULL))
,Entity = xRow.value('@*[1]','varchar(100)')
,Attribute = xAtt.value('local-name(.)','varchar(100)')
,Value = xAtt.value('.','varchar(max)')
From @XML.nodes('/row') As R(xRow)
Cross Apply R.xRow.nodes('./@*') As A(xAtt) )
,cteSum as (Select Records=count(Distinct Entity)
,Head = IIF(@IncludeHead=0,IIF(count(Distinct Entity)<=1,'[getResults]','[[getResults]]'),Concat('{"status":{"successful":"true","timestamp":"',Format(GetUTCDate(),'yyyy-MM-dd hh:mm:ss '),'GMT','","rows":"',count(Distinct Entity),'"},"results":[[getResults]]}') )
From cteEAV)
,cteBld as (Select *
,NewRow=IIF(Lag(Entity,1) over (Partition By Entity Order By (Select NULL))=Entity,'',',{')
,EndRow=IIF(Lead(Entity,1) over (Partition By Entity Order By (Select NULL))=Entity,',','}')
,JSON=Concat('"',IIF(@ToLowerCase=1,Lower(Attribute),Attribute),'":','"',Value,'"')
From cteEAV )
Select @JSON = @JSON+NewRow+JSON+EndRow,@Head = Head From cteBld, cteSum
Return Replace(@Head,'[getResults]',Stuff(@JSON,1,1,''))
End
-- Parameter 1: @IncludeHead 1/0
-- Parameter 2: @ToLowerCase 1/0 (converts field name to lowercase
-- Parameter 3: (Select * From ... for XML RAW)
**編集-タイプミスを修正
以下は、ほぼすべてのデータセットのJSON配列を作成する必要があります。ただし、ビットをtrue/falseに変換する方法はまだ作成していません。
考慮すべき点が1つあります。最初のSELECTの最初の列は、ENTITYフィールドに相当する主キーである必要があります。この場合、 Select * from @User for XML RAW
... IDはエンティティであり、まさにテーブルの最初のフィールドです
パフォーマンスに関しては、19個のフィールドを持つ500件のレコードが0.694秒でJSON文字列191,987バイトを作成します(0.098秒で50件のレコード)
以下を考慮してください。
Declare @User table (ID int,Active bit,First_Name varchar(50),Last_Name varchar(50),EMail varchar(50),LastOn DateTime)
Insert into @User values
(1,1,'John','Smith','[email protected]','2016-10-05 17:32:41.903'),
(2,0,'Jane','Doe' ,'[email protected]','2016-10-05 08:25:18.203')
Declare @XML xml = (Select * From @User for XML RAW)
Declare @JSON varchar(max) = ''
;with cteEAV as (
Select RowNr = Row_Number() over (Order By (Select NULL))
,Entity = xRow.value('@*[1]','varchar(100)')
,Attribute = xAtt.value('local-name(.)','varchar(100)')
,Value = xAtt.value('.','varchar(max)')
From @XML.nodes('/row') As A(xRow)
Cross Apply A.xRow.nodes('./@*') As B(xAtt) )
,cteBld as (
Select *
,NewRow = IIF(Lag(Entity,1) over (Partition By Entity Order By (Select NULL))=Entity,'',',{')
,EndRow = IIF(Lead(Entity,1) over (Partition By Entity Order By (Select NULL))=Entity,',','}')
,JSON = Concat('"',Attribute,'":','"',Value,'"')
From cteEAV )
Select @JSON = @JSON+NewRow+JSON+EndRow
From cteBld
Select '['+Stuff(@JSON,1,1,'')+']'
戻り値
[{"ID":1, "Active":1, "First_Name":"John", "Last_Name":"Smith", "EMail":"[email protected]", "LastOn":"2016-10-05T17:32:41.903", "TotalSales":25569.0000} ,{"ID":2, "Active":0, "First_Name":"Jane", "Last_Name":"Doe", "EMail":"[email protected]", "LastOn":"2016-10-05T08:25:18.203", "TotalSales":22888.0000}]
より読みやすいバージョン
cteEAVは動的にデータのピボットを解除し、以下を生成します:
cteBLDはフラグを拡張および追加しますNew/End Row
最終選択
これにより、すべてがまとめられ、必要に応じてラップまたはネストできる1つの最終文字列が生成されます。