how to extract nested node values from JSON in ORACLE - sql

I am trying to extract nested nodes from below Json(Stored in column named DOC as CLOB format) but it is coming blank.
{
"id": "a3ac3bec-4c4e-42c8-a11c-068f3dfda201",
"createdDateTime": "2021-08-31T18:00:44Z",
"userDisplayName": "abc",
"userPrincipalName": "sad2547#gmail.com",
"userId": "36a3a1f2-6133-4a0b-a6c9-020693ebdbd3",
"appId": "1fa516bf-1332-4140-85c9-d844d4e69ca1",
"appDisplayName": "ProxyIdentityExperienceFramework",
"ipAddress": "999.99.0.999",
"clientAppUsed": "Mobile Apps and Desktop clients",
"correlationId": "c478bdd4-1541-4cd0-bf7e-bd0695325246",
"conditionalAccessStatus": "notApplied",
"isInteractive": true,
"riskDetail": "hidden",
"riskLevelAggregated": "hidden",
"riskLevelDuringSignIn": "hidden",
"riskState": "none",
"riskEventTypes": [],
"riskEventTypes_v2": [],
"resourceDisplayName": "IdentityExperienceFramework",
"resourceId": "a3c649c7-5daa-4c3f-a5a0-a3fd7281ee20",
"status": {
"errorCode": 0,
"failureReason": "Other.",
"additionalDetails": null
},
"deviceDetail": {
"deviceId": "",
"displayName": "",
"operatingSystem": "Windows 10",
"browser": "Chrome 92.0.4515",
"isCompliant": false,
"isManaged": false,
"trustType": ""
},
"location": {
"city": "xyz",
"state": "def",
"countryOrRegion": "US",
"geoCoordinates": {
"altitude": null,
"latitude": 12.65875,
"longitude": -74.65286
}
},
"appliedConditionalAccessPolicies": []
}
Below is my query:
SELECT x.*
FROM demo_json a,
JSON_TABLE(doc, '$'
COLUMNS (
ids VARCHAR2(100) PATH '$.id',
NESTED PATH '$.deviceDetail.*' COLUMNS
(
browser VARCHAR2(100) PATH '$.browser'
)
)
) x;
Any suggestions to retrive all nested nodes from json?
Thanks

Your JSON contains an error(missing double quotes) in userPrincipalName: "userPrincipalName": sad2547#gmail.com, it should be "userPrincipalName": "sad2547#gmail.com",
It works fine if you fix it:
https://dbfiddle.uk/?rdbms=oracle_18&fiddle=d340a38b993f78170e04750e2aa8013c
with DEMO_JSON (doc) as (
select q'[
{
"id": "a3ac3bec-4c4e-42c8-a11c-068f3dfda201",
"createdDateTime": "2021-08-31T18:00:44Z",
"userDisplayName": "abc",
"userPrincipalName": "sad2547#gmail.com",
"userId": "36a3a1f2-6133-4a0b-a6c9-020693ebdbd3",
"appId": "1fa516bf-1332-4140-85c9-d844d4e69ca1",
"appDisplayName": "ProxyIdentityExperienceFramework",
"ipAddress": "999.99.0.999",
"clientAppUsed": "Mobile Apps and Desktop clients",
"correlationId": "c478bdd4-1541-4cd0-bf7e-bd0695325246",
"conditionalAccessStatus": "notApplied",
"isInteractive": true,
"riskDetail": "hidden",
"riskLevelAggregated": "hidden",
"riskLevelDuringSignIn": "hidden",
"riskState": "none",
"riskEventTypes": [],
"riskEventTypes_v2": [],
"resourceDisplayName": "IdentityExperienceFramework",
"resourceId": "a3c649c7-5daa-4c3f-a5a0-a3fd7281ee20",
"status": {
"errorCode": 0,
"failureReason": "Other.",
"additionalDetails": null
},
"deviceDetail": {
"deviceId": "",
"displayName": "",
"operatingSystem": "Windows 10",
"browser": "Chrome 92.0.4515",
"isCompliant": false,
"isManaged": false,
"trustType": ""
},
"location": {
"city": "xyz",
"state": "def",
"countryOrRegion": "US",
"geoCoordinates": {
"altitude": null,
"latitude": 12.65875,
"longitude": -74.65286
}
},
"appliedConditionalAccessPolicies": []
}]' doc from dual
)
SELECT
x.*
FROM DEMO_JSON a,
JSON_TABLE(a.DOC, '$'
COLUMNS (
IDs VARCHAR2(100) PATH id,
nested path deviceDetail columns(
browser path browser
)
)
) X;

Related

Select data from Json array MS SQL Server

I have to select data from Json like this:
[
{
"id": 10100,
"externalId": "100000035",
"name": "Test1",
"companyId": 10099,
"phone": "0738003811",
"email": "test#Test.com",
"mainAddress": {
"county": "UK",
"province": "test",
"zipCode": "01234",
"city": "test",
"street": "test",
"gln": "44,37489331;26,21941193",
"country": {
"iso2": "UK",
"iso3": "UK"
}
},
"active": false,
"main": true,
"stores": [
"Test"
],
"attributes": [
{
"attributeId": 1059,
"attributeName": "CH6 name",
"attributeExternalId": null,
"attributeValueId": 74292,
"attributeValueType": "MONO_LINGUAL",
"attributeValueEid": null,
"attributePlainValue": "Unknown"
},
{
"attributeId": 1061,
"attributeName": "BD",
"attributeExternalId": null,
"attributeValueId": 81720,
"attributeValueType": "MONO_LINGUAL",
"attributeValueEid": null,
"attributePlainValue": "Not assigned"
}
],
"daysSinceLastOrder": null
},
{
"id": 62606,
"externalId": "VL_LC_000190",
"name": "Test",
"companyId": 17793,
"phone": "44333424",
"email": "test#email.com",
"mainAddress": {
"firmName": "test",
"county": "test",
"province": "test",
"zipCode": "247555",
"city": "test",
"street": "test",
"gln": "44.8773851;23.9223518",
"country": {
"iso2": "RO",
"iso3": "ROU"
},
"phone": "07547063789"
},
"active": true,
"main": false,
"stores": [
"Valcea"
],
"attributes": [
{
"attributeId": 1042,
"attributeName": "Type of location",
"attributeExternalId": "TYPE_OF_DIVISION",
"attributeValueId": 34506,
"attributeValueType": "MONO_LINGUAL",
"attributeValueEid": "Small OTC (<40mp)",
"attributePlainValue": "Small OTC (<40mp)"
},
{
"attributeId": 17,
"attributeName": "Limit for payment",
"attributeExternalId": "LIMIT_FOR_PAYMENT_IN_DAYS",
"attributeValueId": 59120,
"attributeValueType": "NUMBER",
"attributeValueEid": null,
"attributePlainValue": "28"
}
],
"daysSinceLastOrder": 147
}
]
I know how to select data from simple json object using "FROM OPENJSON",
but now I have to select a
AttributeValueId, AttributeId and AttributeName, attributePlainValue and CompanyId for each Attribute. So I dont know how to select data from attributes array and then how to join to this CompanyId which is one level up.
Maybe someone knows how write this query.
As mentioned by #lptr in the comments:
You need to pass the result of one OPENJSON to another, using CROSS APPLY. You can select a whole JSON object or array as a property, by using the syntax AS JSON
select
t1.companyid,
t2.*
from openjson(#j)
with (
companyId int,
attributes nvarchar(max) as json
) as t1
cross apply openjson(t1.attributes)
with
(
attributeId int,
attributeName nvarchar(100),
attributeValueId nvarchar(100),
attributePlainValue nvarchar(100)
) as t2;
db<>fiddle
For example, you can use code like this.
f1.metaData->"$.identity.customerID" = '.$customerID.'

How to parse Json array and nested values?

I am trying to parse all arrays and nested value in given Json but for nested blocks, it creates 3 distinct recs instead one. Is there a way to display only one rec instead 3 without doing union or group by?
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#auditLogs/signIns",
"value": [
{
"id": "a3ac3bec-4c4e-42c8-a11c-068f3dfda201",
"createdDateTime": "2021-08-31T18:00:44Z",
"userDisplayName": "abc",
"userPrincipalName": "sad2547#gmail.com",
"userId": "36a3a1f2-6133-4a0b-a6c9-020693ebdbd3",
"appId": "1fa516bf-1332-4140-85c9-d844d4e69ca1",
"appDisplayName": "ProxyIdentityExperienceFramework",
"ipAddress": "999.99.0.999",
"clientAppUsed": "Mobile Apps and Desktop clients",
"correlationId": "c478bdd4-1541-4cd0-bf7e-bd0695325246",
"conditionalAccessStatus": "notApplied",
"isInteractive": true,
"riskDetail": "hidden",
"riskLevelAggregated": "hidden",
"riskLevelDuringSignIn": "hidden",
"riskState": "none",
"riskEventTypes": [],
"riskEventTypes_v2": [],
"resourceDisplayName": "IdentityExperienceFramework",
"resourceId": "a3c649c7-5daa-4c3f-a5a0-a3fd7281ee20",
"status": {
"errorCode": 0,
"failureReason": "Other.",
"additionalDetails": null
},
"deviceDetail": {
"deviceId": "",
"displayName": "",
"operatingSystem": "Windows 10",
"browser": "Chrome 92.0.4515",
"isCompliant": false,
"isManaged": false,
"trustType": ""
},
"location": {
"city": "xyz",
"state": "def",
"countryOrRegion": "US",
"geoCoordinates": {
"altitude": null,
"latitude": 12.65875,
"longitude": -74.65286
}
},
"appliedConditionalAccessPolicies": []
},
{
"id": "a3ac3bec-4c4e-42c8-a11c-068f3dfda201",
"createdDateTime": "2021-08-31T18:00:44Z",
"userDisplayName": "abc",
"userPrincipalName": "sad2547#gmail.com",
"userId": "36a3a1f2-6133-4a0b-a6c9-020693ebdbd3",
"appId": "1fa516bf-1332-4140-85c9-d844d4e69ca1",
"appDisplayName": "ProxyIdentityExperienceFramework",
"ipAddress": "999.99.0.999",
"clientAppUsed": "Mobile Apps and Desktop clients",
"correlationId": "c478bdd4-1541-4cd0-bf7e-bd0695325246",
"conditionalAccessStatus": "notApplied",
"isInteractive": true,
"riskDetail": "hidden",
"riskLevelAggregated": "hidden",
"riskLevelDuringSignIn": "hidden",
"riskState": "none",
"riskEventTypes": [],
"riskEventTypes_v2": [],
"resourceDisplayName": "IdentityExperienceFramework",
"resourceId": "a3c649c7-5daa-4c3f-a5a0-a3fd7281ee20",
"status": {
"errorCode": 1,
"failureReason": "Other.",
"additionalDetails": null
},
"deviceDetail": {
"deviceId": "",
"displayName": "",
"operatingSystem": "Windows 10",
"browser": "Chrome 92.0.4505",
"isCompliant": false,
"isManaged": false,
"trustType": ""
},
"location": {
"city": "abc",
"state": "def",
"countryOrRegion": "US",
"geoCoordinates": {
"altitude": null,
"latitude": 12.65875,
"longitude": -74.65286
}
},
"appliedConditionalAccessPolicies": []
]
}
SQL:
SELECT x.*
FROM DEMO_JSON a,
JSON_TABLE(a.DOC, '$.value[*]'
COLUMNS (
IDs VARCHAR2(100) PATH id,
nested path status columns(
code path errorCode),
nested path deviceDetail columns(
browser path browser
),
nested path location columns(
city path city)
)
) X;
Output:
IDS CODE BROWSER CITY
a3ac3bec-4c4e-42c8-a11c-068f3dfda201 0
a3ac3bec-4c4e-42c8-a11c-068f3dfda201 Chrome 92.0.4515
a3ac3bec-4c4e-42c8-a11c-068f3dfda201 xyz
a3ac3bec-4c4e-42c8-a11c-068f3dfda201 1
a3ac3bec-4c4e-42c8-a11c-068f3dfda201 Chrome 92.0.4505
a3ac3bec-4c4e-42c8-a11c-068f3dfda201 abc```

Get nested data c.<type>.<type> in SQL Query?

I've been searching everywhere for this seemingly simple action: I'd like to select only a certain few data type from a nested source.
The closest that I can get to the solution is this:
SELECT c.receipt_number, c.millitime, c.email, c.phone, c.shipping, c.shipping_note, c.amount_paid, i.description, i.quantity
FROM c
JOIN i IN c.line_items
WHERE c.millitime > 1627813253000
But this will create lots of duplicated data, like the receipt_number, email, etc in the example:
[
{
"receipt_number": null,
"millitime": 1627813377000,
"email": "test#gmail.com",
"phone": "000000000",
"shipping": {
"address": {
"city": "Sydney",
"country": "AU",
"line1": "Test Street",
"line2": null,
"postal_code": "3000",
"state": "VIC"
},
"name": "New Cust"
},
"shipping_note": "Please knock on door.",
"amount_paid": 104,
"description": "Curry Chicken",
"quantity": 1
},
{
"receipt_number": null,
"millitime": 1627813377000,
"email": "test#gmail.com",
"phone": "000000000",
"shipping": {
"address": {
"city": "Sydney",
"country": "AU",
"line1": "Test Street",
"line2": null,
"postal_code": "3000",
"state": "VIC"
},
"name": "New Cust"
},
"shipping_note": "Please knock on door.",
"amount_paid": 104,
"description": "Chicken Noodle",
"quantity": 8
}
]
Is there a way to create a nested result of c.line_items with just the desired data description and quantity? The final result should be similar to:
[
{
"receipt_number": null,
"millitime": 1627813377000,
"email": "test#gmail.com",
"phone": "000000000",
"shipping": {
"address": {
"city": "Sydney",
"country": "AU",
"line1": "Test Street",
"line2": null,
"postal_code": "3000",
"state": "VIC"
},
"name": "New Cust"
},
"shipping_note": "Please knock on door.",
"amount_paid": 104,
"line_items": [
{
"description": "Chicken Noodle",
"quantity": 8
},
{
"description": "Curry Chicken",
"quantity": 1
}
]
}
]
I have created the same in
You can use distinct keyword to remove duplicates from the results.
Add c.line_items to your select list and change i.description, i.quantity to c.description, c.quantity to add view under line_items.
Query:
SELECT distinct c.receipt_number, c.millitime, c.email, c.phone, c.shipping, c.shipping_note, c.amount_paid, c.line_items
FROM c
JOIN i IN c.line_items
WHERE c.millitime > 1627813253000
Result:
Reference: Azure Cosmos DB SQL query - JSON items

Deduplicate table SQL with nested rows (type STRUCT)

I have a SQL table (in BigQuery) with possible duplicated rows. The table has over 20 columns, some of them are nested (data type "STRUCT)". I want to deduplicate the table.
I can't simply query SELECT DISTINCT * because I get an error
Query error: Column options of type STRUCT cannot be used in SELECT DISTINCT
So far, I tried to create a unique ID based on a hash of certain columns.
I have now this unique ID (called sha256), but I can't figure out a way of selecting only rows with unique hash.
I tried to GROUP BY, but it doesn't work with STRUCT type, and I tried also to INNER JOIN with a table containing only unique hashed, but I get duplicates also.
For reference, here are 2 example rows of the dataset:
{
"sha256": "un2k3TUtzwzmQMvxfrjztsh/A/GW3WWzV4U4CezqceA=",
"has_phone": true,
"options": {
"sub_toplist": true,
"gallery": false,
"urgent": false,
"has_option": true,
"photosup": true,
"booster": false
},
"calendar": {
"dates": null
},
"owner": {
"siren": null,
"pro_rates_link": null,
"user_id": "f0d94687-1a24-4ed4-8adb-7faded053ca8",
"type": "private",
"no_salesmen": true,
"name": "marius",
"store_id": "5022456"
},
"location": {
"feature": {
"properties": null,
"geometry": {
"coordinates": [
"9.41733",
"42.54701"
],
"type": "Point"
},
"type": "Feature"
},
"is_shape": true,
"provider": "here",
"lng": "9.41733",
"lat": "42.54701",
"zipcode": "20290",
"city_label": "Lucciana 20290",
"city": "Lucciana",
"region_name": "Corse",
"department_name": null,
"source": "city",
"department_id": "0",
"region_id": "9"
},
"attributes": {
"pro_rates_link": null,
"immo_sell_type": "old",
"ges": "a",
"square": "92",
"rooms": "4",
"energy_rate": "b",
"is_import": false,
"custom_ref": null,
"lease_type": "sell",
"real_estate_type": "1",
"fai_included": null,
"type_real_estate_sale": null
},
"price_calendar": null,
"price": [
"270000"
],
"body": "text",
"url": "https://www.example.fr/ventes_immobilieres/1729537955.htm",
"category_name": "Ventes immobilières",
"category_id": "9",
"images": {
"urls_thumb": [
"https://img3.example.fr/ad-thumb/d63e236ce3546906b3ce661640a7cf858d0a0593.jpg"
],
"urls": [
"https://img3.example.fr/ad-image/ac6bd9ce0cc3aa507727ddece51f437d77ae4cfa.jpg",
],
"nb_images": "7",
"small_url": "https://img3.example.fr/ad-small/ac6bd9ce0cc3aa507727ddece51f437d77ae4cfa.jpg",
"thumb_url": "https://img3.example.fr/ad-thumb/ac6bd9ce0cc3aa507727ddece51f437d77ae4cfa.jpg"
},
"ad_type": "offer",
"first_publication_date": "2020-01-02 15:00:46 UTC",
"status": "active",
"subject": "Villa à Lucciana",
"index_date": "2020-01-16 15:00:45 UTC",
"expiration_date": "2020-03-02 15:00:46 UTC",
"list_id": "1729537955"
},
{
"sha256": "wCMrggkqSJ3PgbkuWAgBpCMtFfkJDRlz6TOeO5Nngsg=",
"has_phone": true,
"options": {
"sub_toplist": false,
"gallery": false,
"urgent": false,
"has_option": false,
"photosup": false,
"booster": false
},
"calendar": {
"dates": null
},
"owner": {
"siren": null,
"pro_rates_link": null,
"user_id": "ae0f432d-0aa2-4828-a20b-3472255588b4",
"type": "private",
"no_salesmen": true,
"name": "M.Milleliri",
"store_id": "12132533"
},
"location": {
"feature": {
"properties": null,
"geometry": {
"coordinates": [
"9.1917",
"41.54506"
],
"type": "Point"
},
"type": "Feature"
},
"is_shape": true,
"provider": "here",
"lng": "9.1917",
"lat": "41.54506",
"zipcode": "20146",
"city_label": "Sotta 20146",
"city": "Sotta",
"region_name": "Corse",
"department_name": null,
"source": "city",
"department_id": "0",
"region_id": "9"
},
"attributes": {
"pro_rates_link": null,
"immo_sell_type": "old",
"ges": "Non renseigné",
"square": null,
"rooms": null,
"energy_rate": "Non renseigné",
"is_import": false,
"custom_ref": null,
"lease_type": "sell",
"real_estate_type": "3",
"fai_included": null,
"type_real_estate_sale": null
},
"price_calendar": null,
"price": [
"100000"
],
"body": "text",
"url": "https://www.example.fr/ventes_immobilieres/1736199673.htm",
"category_name": "Ventes immobilières",
"category_id": "9",
"images": {
"urls_thumb": [
"https://img3.example.fr/ad-thumb/4f3632dc8e5c50075aa6c6e4b559e2042546f009.jpg"
],
"urls": [
"https://img3.example.fr/ad-image/4f3632dc8e5c50075aa6c6e4b559e2042546f009.jpg"
],
"urls_large": [
"https://img3.example.fr/ad-large/4f3632dc8e5c50075aa6c6e4b559e2042546f009.jpg"
],
"nb_images": "1",
"small_url": "https://img3.example.fr/ad-small/4f3632dc8e5c50075aa6c6e4b559e2042546f009.jpg",
"thumb_url": "https://img3.example.fr/ad-thumb/4f3632dc8e5c50075aa6c6e4b559e2042546f009.jpg"
},
"ad_type": "offer",
"first_publication_date": "2020-01-16 14:21:05 UTC",
"status": "active",
"subject": "Terrain 1250 m2 Sotta",
"index_date": "2020-01-16 14:21:05 UTC",
"expiration_date": "2020-03-16 14:21:05 UTC",
"list_id": "1736199673"
}
and the query I'm working on so far:
WITH
table_unique_hash AS (
SELECT
DISTINCT(SHA256(CONCAT(FORMAT_TIMESTAMP('%Y/%m/%d_%H:%M:%S_', index_date), CAST(list_id AS STRING)))) AS sha256
FROM
`test_bucket_data.daily_table`),
table_hashed AS (
SELECT
SHA256(CONCAT(FORMAT_TIMESTAMP('%Y/%m/%d_%H:%M:%S_', index_date), CAST(list_id AS STRING))) AS sha256, *
FROM
`test_bucket_data.daily_table`)
SElECT * FROM table_hashed
limit 10;
A solution would be to find a way of inner join the table_hashed and the table_unique_hash on the sha256 column...
Thanks for your help!
I found a workaround based on this topic. The combination of GROUP BY and ANY function for all the STRUCT columns made it work!
SELECT
has_phone,
ANY_VALUE(options) as options,
ANY_VALUE(calendar) as calendar,
ANY_VALUE(owner) as owner,
ANY_VALUE(location) as location,
ANY_VALUE(attributes) as attributes,
price_calendar,
price,
body,
url,
category_name,
category_id,
ANY_VALUE(images) as images,
ad_type,
first_publication_date,
status,
subject,
index_date,
expiration_date,
list_id,
FROM
`{table_name}`
Group by
has_phone,
price_calendar,
price,
body,
url,
category_name,
category_id,
ad_type,
first_publication_date,
status,
subject,
index_date,
expiration_date,
list_id
Note: my "price" field was previously an array; I transformed it in my source json to an int

How to get list of Users under a certain Manager/Approver in Coupa API?

I'm lost and I'm hoping that someone may have worked on this before.
So Coupa has its API:
https://coupadocs.atlassian.net/wiki/display/integrate/Users+API
I was able to retrieve user information together with the corresponding manager. Sample response:
https://unknownserver-test.coupahost.com/api/users?employee-number=10003323
[
{
"id": 2756,
"created-at": "2017-03-30T09:29:19-05:00",
"updated-at": "2017-03-31T04:30:53-05:00",
"login": "user1.user1",
"email": "staging23#coupa.com",
"purchasing-user": false,
"expense-user": false,
"sourcing-user": false,
"inventory-user": false,
"employee-number": "10003323",
"phone-work": null,
"phone-mobile": null,
"firstname": "user1",
"lastname": "user1",
"fullname": "user1 user1",
"api-user": false,
"active": false,
"salesforce-id": null,
"account-security-type": 0,
"authentication-method": "coupa_credentials",
"sso-identifier": null,
"default-locale": null,
"default-account": null,
"business-group-security-type": null,
"edit-invoice-on-quick-entry": false,
"avatar-thumb-url": null,
"mention-name": "user1user1",
"company-employee-id": "10003323",
"netsuite-employee-id": "10003323",
"subsidiary": {
"id": 1592,
"external-ref-num": null,
"external-ref-code": "company North America:1"
},
"job-title": {
"id": 2591,
"external-ref-num": null,
"external-ref-code": "VP, Sales"
},
"employee-type": "",
"default-expense-region": "",
"default-geo-spend": "",
"notes": "",
"exclude-from-autosarf": "",
"roles": [
{
"id": 10,
"name": "Expense User"
}
],
"manager": {
"id": 838,
"login": "john.doe",
"email": "staging#coupa.com"
},
"default-currency": {
"id": 1,
"code": "USD"
},
"department": {
"id": 342,
"name": "Sales - Exec:176"
},
"expenses-delegated-to": [],
"can-expense-for": [],
"content-groups": [],
"account-groups": [],
"approval-groups": [],
"working-warehouses": [],
"inventory-organizations": [],
"created-by": {
"id": 2748,
"login": "user1 creator",
"email": "user1.creator#company.com"
},
"updated-by": {
"id": 2748,
"login": "user1 creator",
"email": "user1.creator#company.com"
}
}
]
What I've tried are these:
https://unknownserver-test.coupahost.com/api/users?user[manager][id]=838&return_object=shallow
https://unknownserver-test.coupahost.com/api/users?manager[id]=838&return_object=shallow
https://unknownserver-test.coupahost.com/api/users?users[user][manager][id]=838&return_object=shallow
https://{{URL PREFIX}}.{{HOST}}.com/api/users?manager_id=838&return_object=shallow
If you only need the IDs of the users, you'd get better performance with return_object=limited
If there are more than 50 users returned, you'll have to paginate with the offset query param.