0

I have a JSON file that contains transactions, and each transaction contains multiple items. I need to flatten the data into SQL Server tables using T-SQL.

I have tried different options to flatten it, but it looks like I am missing something. Anyone who has worked on a similar structure have any ideas how this could be accomplished? 

DECLARE @json NVARCHAR(MAX);

SELECT @json = JsonPath
FROM [dbo].[stg_transactionsJson] b;

SELECT 
    CONVERT(NVARCHAR(50), JSON_VALUE(c.Value, '$.orderId')) AS orderId,
    CONVERT(DATETIME, JSON_VALUE(c.Value, '$.openTime')) AS openTime,
    CONVERT(DATETIME, JSON_VALUE(c.Value, '$.closeTime')) AS closeTime,
    CONVERT(NVARCHAR(50), JSON_VALUE(c.Value, '$.operatorId')) AS operatorId,
    CONVERT(NVARCHAR(50), JSON_VALUE(c.Value, '$.terminalId')) AS terminalId,
    CONVERT(NVARCHAR(50), JSON_VALUE(c.Value, '$.sessionId')) AS sessionId,
    CONVERT(NVARCHAR(50), JSON_VALUE(p.Value, '$.productGroupId')) AS productGroupId,
    CONVERT(NVARCHAR(150), JSON_VALUE(p.Value, '$.productId')) AS productId,
    CONVERT(NVARCHAR(50), JSON_VALUE(p.Value, '$.quantity')) AS quantity,
    CONVERT(NVARCHAR(150), JSON_VALUE(p.Value, '$.taxValue')) AS taxValue,
    CONVERT(NVARCHAR(50), JSON_VALUE(p.Value, '$.value')) AS ProductValue,
    CONVERT(NVARCHAR(150), JSON_VALUE(p.Value, '$.priceBandId')) AS priceBandId,
    GETDATE() AS DateUpdated
FROM
    OPENJSON(@json) AS c
OUTER APPLY 
    OPENJSON(c.Value, '$."products"') AS p;

And the sample JSON as follows

{
  "orderId": 431,
  "openTime": "2022-10-31T13:12:28",
  "closeTime": "2022-10-31T13:12:32",
  "operatorId": 7,
  "terminalId": 4,
  "sessionId": 1,
  "products": [
    {
      "productId": 2632,
      "productGroupId": 162,
      "quantity": 1,
      "taxValue": 0.58,
      "value": 3.5,
      "priceBandId": 2
    },
    {
      "productId": 3224,
      "productGroupId": 164,
      "quantity": 1,
      "taxValue": 0.08,
      "value": 0.5,
      "priceBandId": 2
    }
  ],
  "tenders": [
    {
      "tenderId": 2,
      "value": 4.0
    }
  ],
  "type": 1,
  "memberId": 1
}

2 Answers 2

2

You can Do it like this

First declare the values in an with clause and then cross apply the products

DECLARE @json NVARCHAR(MAX);
SET @json = '{
  "orderId": 431,
  "openTime": "2022-10-31T13:12:28",
  "closeTime": "2022-10-31T13:12:32",
  "operatorId": 7,
  "terminalId": 4,
  "sessionId": 1,
  "products": [
    {
      "productId": 2632,
      "productGroupId": 162,
      "quantity": 1,
      "taxValue": 0.58,
      "value": 3.5,
      "priceBandId": 2
    },
    {
      "productId": 3224,
      "productGroupId": 164,
      "quantity": 1,
      "taxValue": 0.08,
      "value": 0.5,
      "priceBandId": 2
    }
  ],
  "tenders": [
    {
      "tenderId": 2,
      "value": 4.0
    }
  ],
  "type": 1,
  "memberId": 1
}
';
SELECT c.orderId
  ,c.openTime
  ,c.closeTime
  ,c.operatorId
  ,c.terminalId
  ,c.sessionId
  , JSON_VALUE(p.Value, '$.productGroupId') productGroupId
  , JSON_VALUE(p.Value, '$.productId') productId
  , JSON_VALUE(p.Value, '$.quantity') quantity
  , JSON_VALUE(p.Value, '$.taxValue') taxValue
  , JSON_VALUE(p.Value, '$.value') value
  , JSON_VALUE(p.Value, '$.priceBandId') priceBandId
  ,GETDATE() AS DateUpdated
  FROM
  OPENJSON(@json)  WITH (
  orderId int '$.orderId',
  openTime date '$.openTime',
  closeTime date '$.closeTime',
  operatorId int '$.operatorId',
  terminalId int '$.terminalId',
  sessionId int '$.sessionId',
  [products] NVARCHAR(MAX) as JSON) c
CROSS APPLY OPENJSON(c.products) p
  
  
 
orderId openTime closeTime operatorId terminalId sessionId productGroupId productId quantity taxValue value priceBandId DateUpdated
431 2022-10-31 2022-10-31 7 4 1 162 2632 1 0.58 3.5 2 2023-01-11 13:57:47.607
431 2022-10-31 2022-10-31 7 4 1 164 3224 1 0.08 0.5 2 2023-01-11 13:57:47.607

fiddle

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for answering the question, How it could be if I have to use this in a table column ? It might take a lot of resource if I have to run it in a loop. Also how could I handle the tender block ?
you need to add another apply with tender , for the table you need another join before the open json
That is solved thanks, having problem only in applying the same into the table which has got the JSON column.
1

The expected output defines the exact statement, but if you need to parse nested JSON content you may try a combination of:

  • OPENJSON() with explicit schema and the AS JSON modifier for nested JSON
  • additional APPLY operators for each nested level.

T-SQL:

SELECT
   j1.orderId, j1.openTime, j1.closeTime, j1.operatorId, j1.terminalId, j1.sessionId, j1.type, j1.memberId,
   j2.productGroupId, j2.productId, j2.quantity, j2.taxValue, j2.productValue, j2.priceBandId,
   j3.tenderId, j3.tenderValue
FROM stg_transactionsJson s
OUTER APPLY OPENJSON(s.stg_transactionsJson) WITH (
   orderId NVARCHAR(50) '$.orderId',
   openTime DATETIME '$.openTime',
   closeTime DATETIME '$.closeTime',
   operatorId NVARCHAR(50) '$.operatorId',
   terminalId NVARCHAR(50) '$.terminalId',
   sessionId NVARCHAR(50) '$.sessionId',
   products NVARCHAR(MAX) '$.products' AS JSON,
   tenders NVARCHAR(MAX) '$.tenders' AS JSON,
   type int '$.type',
   memberId int '$.memberId'
) j1
OUTER APPLY OPENJSON(j1.products) WITH (
   productGroupId NVARCHAR(50) '$.productGroupId',
   productId NVARCHAR(150) '$.productId',
   quantity NVARCHAR(50) '$.quantity',
   taxValue NVARCHAR(150) '$.taxValue',
   productValue NVARCHAR(50) '$.value',
   priceBandId NVARCHAR(150)'$.priceBandId'
) j2
OUTER APPLY OPENJSON(j1.tenders) WITH (
   tenderId NVARCHAR(150) '$.tenderId',
   tenderValue NVARCHAR(50) '$.value'
) j3

2 Comments

Thank you so much. Creating another CTE with tenders solved the issue for tenders. How would it be possible to apply this at the table column level?
@Jobin, with an additional APPLY operator. The answer is updated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.