t-sql openjson更新数组

时间:2017-11-11 23:10:16

标签: json sql-server tsql

我尝试使用open json插入订单信息和订单行。

这是json的例子。

declare @json nvarchar(max) = '
{"OrderID":0,
"CustomerID":2250,
"SupplierID":1,
"CuratorID":988,
"FirmID":null,
"OrderStateID":2,
"DeliveryTypeID":1,
"Code1C":"",
"CreationDate":"2017-11-12T01:05:14.3233187+03:00",
"ReservationDate":"2017-11-15T01:05:16.1306759+03:00",
"AssemblyDate":null,
"DeliveryDate":"2017-11-12T01:05:15.1748244+03:00",
"TransportAddress":"",
"TransportName":"","TransportPhone":"","RecieverAddress":"","RecieverName":"",
"RecieverPhone":"","Comment":"","LoaderID":null,"DriverID":null,
"CanDelete":true,"LoadingDate":null,"RealizeNum":"","IsDocumentsCreate":false,"DeliveryType":null,"Firm":null,
"OrderLines":[
    {"OrderLineID":0,"OrderID":0,"ProductID":1,"ProductCount":100,"ChangeCount":0,"Price":363.0,"Product":null,"Order":null},
    {"OrderLineID":0,"OrderID":0,"ProductID":3,"ProductCount":100,"ChangeCount":0,"Price":860.0,"Product":null,"Order":null}
]}'

现在我在Orders表中插入主要信息。

insert into Sales.Orders (CustomerID
                        ,SupplierID
                        ,CuratorID
                        ,OrderStateID
                        ,FirmID
                        ,DeliveryTypeID
                        ,Code1C
                        ,CreationDate
                        ,ReservationDate
                        ,DeliveryDate) select * from openjson(@s) with 
    (CustomerID int, SupplierID int, 
    CuratorID int, OrderStateID int, FirmID int, DeliveryTypeID int, Code1C nvarchar(10), 
    CreationDate datetime2, ReservationDate datetime2, DeliveryDate datetime2);
select * from openjson(@s);

工作正常。下一步我需要插入订单行数组。但在插入之前,我需要将OrderID设置为每个订单行。

这里我选择最后插入的订单标识。

declare @ident int;
select @ident = SCOPE_IDENTITY();

但我不明白,如何将此值设置为每个订单行。 下一个代码不起作用

set @json = JSON_MODIFY(@s, '$.OrderLines.OrderID', @ident);

感谢您的任何建议

3 个答案:

答案 0 :(得分:0)

由于OrderLines是一个数组,您需要分别引用每一行。

在这种情况下,您需要为数组中的每个对象分别使用两个语句:

set @json = JSON_MODIFY(@json, '$.OrderLines[0].OrderID', @ident);
set @json = JSON_MODIFY(@json, '$.OrderLines[1].OrderID', @ident);

关于如何使用t-SQL引用JSON中的各种元素的好读物是https://www.codeproject.com/Articles/1125457/Native-JSON-Support-in-SQL-Server

要找出可以使用的行数:

SELECT count(*)
FROM OPENJSON(@json, '$.OrderLines') 

然后您可以使用光标循环浏览项目。

例如:

declare @count      int;
declare @index      int = 0;
declare @sql        nvarchar(1000);
declare @parmasDef  nvarchar(1000);

select @count = count(*)
from OPENJSON(@json, '$.OrderLines');

set @parmasDef = N'@json nvarchar(max) output,@ident int'

while @index < @count
begin
    set @sql = N'set @json = JSON_MODIFY(@json, ''$.OrderLines[' + cast(@index as nvarchar(10)) + '].OrderID'', @ident);'
    exec sp_executesql @sql, @parmasDef, @json = @json output, @ident=@ident
    set @index += 1;
end 

print @json

答案 1 :(得分:0)

您也可以使用基于集合的逻辑来执行此操作,而不是在SQL中进行while循环。您需要使用STRING_AGG而不是FOR JSON PATH/AUTO,因为将对象重新组合在一起时,它们没有根。

DECLARE
    @json nvarchar(max) = N'{
"SomeOtherJson": "bleh",
"OrderLines":[
    {"OrderLineID":0,"OrderID":0,"ProductID":1,"ProductCount":100,"ChangeCount":0,"Price":363.0,"Product":null,"Order":null},
    {"OrderLineID":0,"OrderID":0,"ProductID":3,"ProductCount":100,"ChangeCount":0,"Price":860.0,"Product":null,"Order":null}
]}',
    @Id INT = 1;

WITH OrderLines AS (
    SELECT JSON_MODIFY(t.[value], '$.OrderID', @Id) OrderLine, @Id Id
    FROM OPENJSON((SELECT JSON_QUERY(@json, 'lax $.OrderLines'))) t
), OrderLineList AS (
    SELECT CONCAT('[',STRING_AGG(t.OrderLine, ','),']') OrderLines
    FROM OrderLines t
    GROUP BY t.Id
)
SELECT JSON_MODIFY(@json, '$.OrderLines', JSON_QUERY(t.OrderLines))
FROM OrderLineList t

导致(美化)的结果:

{
    "SomeOtherJson": "bleh",
    "OrderLines": [
        {
            "OrderLineID": 0,
            "OrderID": 1,
            "ProductID": 1,
            "ProductCount": 100,
            "ChangeCount": 0,
            "Price": 363,
            "Product": null,
            "Order": null
        },
        {
            "OrderLineID": 0,
            "OrderID": 1,
            "ProductID": 3,
            "ProductCount": 100,
            "ChangeCount": 0,
            "Price": 860,
            "Product": null,
            "Order": null
        }
    ]
}

答案 2 :(得分:0)

不是真正的答案,但为了扩展@ Jon49的答案,基于集的操作也可以使用VARCHAR(MAX)应用于具有CROSS APPLY列作为JSON的表。例如:

DECLARE @orders TABLE(Id int, ORDERLINES NVARCHAR(MAX));
INSERT INTO @orders (Id, ORDERLINES) VALUES (1, N'{
"OrderLines":[
    {"OrderLineID":1,"OrderID":0,"ProductID":1,"ProductCount":100,"ChangeCount":0,"Price":363.0,"Product":null,"Order":null},
    {"OrderLineID":2,"OrderID":0,"ProductID":3,"ProductCount":100,"ChangeCount":0,"Price":860.0,"Product":null,"Order":null}
]}')

INSERT INTO @orders (Id, ORDERLINES) VALUES (2, N'{
"OrderLines":[
    {"OrderLineID":3,"OrderID":0,"ProductID":1,"ProductCount":22,"ChangeCount":0,"Price":363.0,"Product":null,"Order":null},
    {"OrderLineID":4,"OrderID":0,"ProductID":3,"ProductCount":33,"ChangeCount":0,"Price":860.0,"Product":null,"Order":null}
]}');

WITH OrderLines AS (
    SELECT JSON_MODIFY(t.[value], '$.OrderID', o.Id) OrderLine, o.Id
    FROM @orders o
    CROSS APPLY OPENJSON((SELECT JSON_QUERY(o.ORDERLINES, 'lax $.OrderLines'))) t
), OrderLineList AS (
    SELECT CONCAT('[',STRING_AGG(t.OrderLine, ','),']') OrderLines, t.Id
    FROM OrderLines t
    GROUP BY t.Id
)

SELECT JSON_MODIFY(o.ORDERLINES, '$.OrderLines', JSON_QUERY(t.OrderLines))
FROM OrderLineList t
INNER JOIN @orders o ON (o.Id=t.Id);