Customize JSON retrieved from mysql - mysql

Lets say this is my database table
id ProductID color size
1 abc red L
2 abc green M
3 abc yellow S
4 def purple L
5 def brown M
6 def pink S
Now I am fecthing data using my sql queires but in response i want my json in this structure
{
"status": true,
"message": "All Product Logs has been fetched Successfully",
"products": [
{
"id": "1",
"ProductID": "abc",
"colors": [
"red",
"green",
"yellow",
],
"sizes": [
"L",
"M",
"S",
]
},
{
"id": "2",
"ProductID": "def",
"colors": [
"purple",
"brown",
"pink",
],
"sizes": [
"L",
"M",
"S",
]
}
]
}
And this what i do but it doesn't makes sense
if ($response) {
$JSONDataArray=[];
$ColorDataArray=[];
$SizeDataArray=[];
while($row = mysqli_fetch_array($response)){
$ColorDataArray[]=array($row['color']);
$SizeDataArray[]=array($row['size']);
$JSONDataArray[]=array('productid' =>$row['productid'],'color' => $ColorDataArray,'sizes' => $SizeDataArray);
}
echo json_encode(['status'=>true,'message'=>'All Products has been fetched Successfully','products'=>$JSONDataArray]);
}
Anykind of help would be appreciated. What do u think should i change my database structure or should i change my query. I simply user Select * query without any where clause

One option is to use the JSON_ARRAYAGG function:
SELECT JSON_PRETTY(
CONCAT(
'{"status": true, ',
'"message": "All Product Logs has been fetched Successfully", ',
'"products": [',
(
SELECT
GROUP_CONCAT(`der`.`json`)
FROM (
SELECT
JSON_OBJECT(
'ProductID', `ProductID`,
'colors', JSON_ARRAYAGG(`color`),
'sizes', JSON_ARRAYAGG(`size`)
) `json`
FROM
`tbl`
GROUP BY
`ProductID`
) `der`
),
']}'
)
) `json_response`;
See dbfiddle.
Keep in mind: GROUP_CONCAT: The result is truncated to the maximum length that is given by the group_concat_max_len system variable.

Related

Use of Lateral Flatten for JSON in Snowflake

I have the following JSON as a variant field in snowflake. I get NULLS when querying the data as shown below - -
create or replace table car_sales
(
src variant
)
as
select parse_json(column1) as src
from values
('{
"MyData": {
"DataID": "16784",
"EmpFirstName": "Jenny",
"EmpLastName": "Test1",
"Description": "My Company Data",
"Assignment": [
{
"AssignentId": "1077",
"AssignentName": "Multi Location",
"AssignentDescription": "usa",
},
],
"salary": 21557
},
"Update": true
}') v;
When I query the data I get Nulls -
select value:AssignentId::string as "1ProductName"
from car_sales,
lateral flatten(input => src:Assignment);
Output is NULL
Can you help to troubleshoot why this is happening?
Try adding the MyData qualifier in the lateral flatten:
with car_sales(src) as (
select
parse_json(column1) as src
from
values
(
'{ "MyData": {
"DataID": "16784",
"EmpFirstName": "Jenny",
"EmpLastName": "Test1",
"Description": "My Company Data",
"Assignment": [
{
"AssignentId": "1077",
"AssignentName": "Multi Location",
"AssignentDescription": "usa",
},
],
"salary": 21557
}, "Update": true }'
)
)
select
value:AssignentId::string as "1ProductName"
from
car_sales,
lateral flatten(input => src:MyData:Assignment);
1ProductName
1077
You are trying to access the child node directly. Specify the parent node as well
select value:AssignentId::string as "1ProductName"
from car_sales,
lateral flatten(input => src:MyData:Assignment);
input => src:Assignment
should be
input => src:MyData:Assignment
Here is the query to read values for each key
select src:MyData.DataID::string as "DataID"
, src:MyData.EmpFirstName::string as "EmpFirstName"
, src:MyData.EmpLastName::string as "EmpLastName"
, src:MyData.Description::string as "Description"
, value:AssignentId::string as "AssignentId/1ProductName"
, value:AssignentName::string as "AssignentName"
, value:AssignentDescription::string as "AssignentDescription"
, src:MyData.salary::number as "salary"
, src:Update::boolean as "Update"
from car_sales,
lateral flatten(input => src:MyData:Assignment);

How to join tables and get the json output using jooq

dslContext.select(
jsonObject(
key("id").value(CATEGORY.ID),
key("courses").value(
jsonArrayAgg(
jsonObject(
Arrays.stream(COURSE.fields())
.map(i -> key(CamelcaseConverter.snakeToCamel(i.getName())).value(
i))
.collect(
Collectors.toList())
)
)
)
)
).from(CATEGORY)
.leftJoin(COURSE_CATEGORY).on(CATEGORY.ID.eq(COURSE_CATEGORY.CATEGORY_ID))
.leftJoin(COURSE).on(COURSE.ID.eq(COURSE_CATEGORY.COURSE_ID)).fetchInto(JSONObject.class)
Output I got:
[
{
"courses": [
{
"id": 19
},
{
"id": null
}
],
"name": "Exam1",
"id": 1,
}
]
The required output is
[
{
"courses": [
{
"id": 19
}
],
"name": "Exam1",
"id": 1
},
{
"courses":[],
"name": "Exam2",
"id": 2
}
]
The query which need to be executed is
"select * from category left outer join course_category on category.id = course_category.category_id left outer join course on course_category.course_id = course.id"
how do I implement it?
You forgot to group by:
.groupBy(CATEGORY.ID, CATEGORY.NAME)
If you have a primary (or unique) key on CATEGORY.ID, then in MySQL, it will be sufficient to group by that
.groupBy(CATEGORY.ID)

Select Json formatted like a report to a table using T-SQL

I have JSON stored in a SQL Server database table in the below format. I have been able to fudge a way to get the values I need but feel like there must be a better way to do it using T-SQL. The JSON is output from a report in the below format where the column names in "columns" correspond to the "rows"-"data" array values.
So column "Fiscal Month" corresponds to data value "11", "Fiscal Year" to "2019", etc.
{
"report": "Property ETL",
"id": 2648,
"columns": [
{
"name": "Fiscal Month",
"dataType": "int"
},
{
"name": "Fiscal Year",
"dataType": "int"
},
{
"name": "Portfolio",
"dataType": "varchar(50)"
},
{
"name": "Rent",
"dataType": "int"
}
],
"rows": [
{
"rowName": "1",
"type": "Detail",
"data": [
11,
2019,
"West Group",
10
]
},
{
"rowName": "2",
"type": "Detail",
"data": [
11,
2019,
"East Group",
10
]
},
{
"rowName": "3",
"type": "Detail",
"data": [
11,
2019,
"East Group",
10
]
},
{
"rowName": "Totals: ",
"type": "Total",
"data": [
null,
null,
null,
30
]
}
]
}
In order to get at the data in the 'data' array I currently have a 2 step process in T-SQL where I create a temp table, and insert the row key/values from '$.Rows' there. Then I can then select the individual columns for each row
CREATE TABLE #TempData
(
Id INT,
JsonData VARCHAR(MAX)
)
DECLARE #json VARCHAR(MAX);
DECLARE #LineageKey INT;
SET #json = (SELECT JsonString FROM Stage.Report);
SET #LineageKey = (SELECT LineageKey FROM Stage.Report);
INSERT INTO #TempData(Id, JsonData)
(SELECT [key], value FROM OPENJSON(#json, '$.rows'))
MERGE [dbo].[DestinationTable] TARGET
USING
(
SELECT
JSON_VALUE(JsonData, '$.data[0]') AS FiscalMonth,
JSON_VALUE(JsonData, '$.data[1]') AS FiscalYear,
JSON_VALUE(JsonData, '$.data[2]') AS Portfolio,
JSON_VALUE(JsonData, '$.data[3]') AS Rent
FROM #TempData
WHERE JSON_VALUE(JsonData, '$.data[0]') is not null
) AS SOURCE
...
etc., etc.
This works, but I want to know if there is a way to directly select the data values without the intermediate step of putting it into the temp table. The documentation and examples I've read seem to all require that the data have a name associated with it in order to access it. When I try and access the data directly at a position by index I just get Null.
I hope I understand your question correctly. If you know the columns names you need one OPENJSON() call with explicit schema, but if you want to read the JSON structure from $.columns, you need a dynamic statement.
JSON:
DECLARE #json nvarchar(max) = N'{
"report": "Property ETL",
"id": 2648,
"columns": [
{
"name": "Fiscal Month",
"dataType": "int"
},
{
"name": "Fiscal Year",
"dataType": "int"
},
{
"name": "Portfolio",
"dataType": "varchar(50)"
},
{
"name": "Rent",
"dataType": "int"
}
],
"rows": [
{
"rowName": "1",
"type": "Detail",
"data": [
11,
2019,
"West Group",
10
]
},
{
"rowName": "2",
"type": "Detail",
"data": [
11,
2019,
"East Group",
10
]
},
{
"rowName": "3",
"type": "Detail",
"data": [
11,
2019,
"East Group",
10
]
},
{
"rowName": "Totals: ",
"type": "Total",
"data": [
null,
null,
null,
30
]
}
]
}'
Statement for fixed structure:
SELECT *
FROM OPENJSON(#json, '$.rows') WITH (
[Fiscal Month] int '$.data[0]',
[Fiscal Year] int '$.data[1]',
[Portfolio] varchar(50) '$.data[2]',
[Rent] int '$.data[3]'
)
Dynamic statement:
DECLARE #stm nvarchar(max) = N''
SELECT #stm = CONCAT(
#stm,
N',',
QUOTENAME(j2.name),
N' ',
j2.dataType,
N' ''$.data[',
j1.[key],
N']'''
)
FROM OPENJSON(#json, '$.columns') j1
CROSS APPLY OPENJSON(j1.value) WITH (
name varchar(50) '$.name',
dataType varchar(50) '$.dataType'
) j2
SELECT #stm = CONCAT(
N'SELECT * FROM OPENJSON(#json, ''$.rows'') WITH (',
STUFF(#stm, 1, 1, N''),
N')'
)
PRINT #stm
EXEC sp_executesql #stm, N'#json nvarchar(max)', #json
Result:
--------------------------------------------
Fiscal Month Fiscal Year Portfolio Rent
--------------------------------------------
11 2019 West Group 10
11 2019 East Group 10
11 2019 East Group 10
30
Yes, it is possible without temporary table:
DECLARE #json NVARCHAR(MAX) =
N'
{
"report": "Property ETL",
"id": 2648,
"columns": [
{
"name": "Fiscal Month",
"dataType": "int"
},
{
"name": "Fiscal Year",
"dataType": "int"
},
{
"name": "Portfolio",
"dataType": "varchar(50)"
},
{
"name": "Rent",
"dataType": "int"
}
],
"rows": [
{
"rowName": "1",
"type": "Detail",
"data": [
11,
2019,
"West Group",
10
]
},
{
"rowName": "2",
"type": "Detail",
"data": [
11,
2019,
"East Group",
10
]
},
{
"rowName": "3",
"type": "Detail",
"data": [
11,
2019,
"East Group",
10
]
},
{
"rowName": "Totals: ",
"type": "Total",
"data": [
null,
null,
null,
30
]
}
]
}
}';
And query:
SELECT s.value,
rowName = JSON_VALUE(s.value, '$.rowName'),
[type] = JSON_VALUE(s.value, '$.type'),
s2.[key],
s2.value
FROM OPENJSON(JSON_QUERY(#json, '$.rows')) s
CROSS APPLY OPENJSON(JSON_QUERY(s.value, '$.data')) s2;
db<>fiddle demo
Or as a single row per detail:
SELECT s.value,
rowName = JSON_VALUE(s.value, '$.rowName'),
[type] = JSON_VALUE(s.value, '$.type'),
JSON_VALUE(s.value, '$.data[0]') AS FiscalMonth,
JSON_VALUE(s.value, '$.data[1]') AS FiscalYear,
JSON_VALUE(s.value, '$.data[2]') AS Portfolio,
JSON_VALUE(s.value, '$.data[3]') AS Rent
FROM OPENJSON(JSON_QUERY(#json, '$.rows')) s;
db<>fiddle demo 2

How to flatten json into table

I have just realised on my AWS Aurora postgres cluster having functions with temp_tables are not friendly with read replicas. I need to do a re-write (using CTEs) - anyway.... How do I take a json object with arrays nested and flatten them to a table like so:
{
"data": [
{
"groupName": "TeamA",
"groupCode": "12",
"subGroupCodes": [
"11"
]
},
{
"groupName": "TeamB",
"groupCode": "13",
"subGroupCodes": [
"15", "22"
]
}
]
}
I would like the output table to be:
groupName groupCode subGroupCodes
TeamA 12 11
TeamB 13 15
TeamB 13 22
I know I can get most of the way there with:
SELECT j."groupCode" as int, j."groupName" as pupilgroup_name
FROM json_to_recordset(p_in_filters->'data') j ("groupName" varchar(50), "groupCode" int)
But I just need to get the subGroupCodes as well but unpacking the array and joining to the correct parent groupCodes.
You need to first unnest the array, and then another unnest to get the subgroup codes:
with data (j) as (
values ('{
"data": [
{
"groupName": "TeamA",
"groupCode": "12",
"subGroupCodes": [
"11"
]
},
{
"groupName": "TeamB",
"groupCode": "13",
"subGroupCodes": [
"15", "22"
]
}
]
}'::jsonb)
)
select e ->> 'groupName' as group_name,
e ->> 'groupCode' as code,
sg.*
from data d
cross join lateral jsonb_array_elements(d.j -> 'data') as e(g)
cross join lateral jsonb_array_elements_text(g -> 'subGroupCodes') as sg(subgroup_code)

Return values from json data in SQL Server 2016

In SQL Server 2016, how do I return "PageSize", "Total", and "NumberOfPages" values with my sample code? I'm pulling column headings with no data.
I want to see:
SQL query output
Code:
DECLARE #jsonData NVARCHAR(MAX)
SET #jsonData = N'{
"PageSize": 500,
"PageNumber": 2,
"Total": 994,
"Items": [
{
"Id": 23004801096147,
"StatusName": "Open",
"CompanyName": "Microsoft",
"JobTitle": "Project Manager"
},
{
"Id": 23004801096147,
"StatusName": "Closed",
"CompanyName": "Salesforce",
"JobTitle": "Marketing Manager"
}
],
"NumberOfPages": 1024
}'
--Try 1
SELECT
JSON_VALUE(fh.value, '$.PageSize') AS [PageSize],
JSON_VALUE(fh.value, '$.Total') AS [Total],
JSON_VALUE(fh.value, '$.NumberOfPages') AS [NumberOfPages]
FROM OPENJSON(#jsonData, '$.FileHeader') as fh
--Try 2
SELECT 'PageSize' as 'PageSize', 'Total' as 'Total', 'NumberOfPages' as
'NumberOfPages'
FROM OPENJSON(#jsonData, '$.FileHeader') as fh
--Try 3
SELECT 'PageSize' as 'PageSize', 'Total' as 'Total', 'NumberOfPages' as
'NumberOfPages'
FROM OPENJSON(#jsonData) as fh
--Try 4
SELECT 'PageSize' as 'PageSize', 'Total' as 'Total', 'NumberOfPages' as
'NumberOfPages'
FROM OPENJSON(#jsonData)
SQL server 2016+ JSON:
https://learn.microsoft.com/en-us/sql/relational-databases/json/json-data-sql-server?view=sql-server-2017
Here's an example using your data:
DECLARE #jsonData NVARCHAR(MAX)
SET #jsonData = N'{
"PageSize": 500,
"PageNumber": 2,
"Total": 994,
"Items": [
{
"Id": 23004801096147,
"StatusName": "Open",
"CompanyName": "Microsoft",
"JobTitle": "Project Manager"
},
{
"Id": 23004801096147,
"StatusName": "Closed",
"CompanyName": "Salesforce",
"JobTitle": "Marketing Manager"
}
],
"NumberOfPages": 1024
}'
--Using OPENJSON and "WITH"
SELECT
[PageSize]
, [PageNumber]
, [Total]
, [NumberOfPages]
FROM OPENJSON(#jsonData)
WITH(
[PageSize] BIGINT '$.PageSize'
,[PageNumber] BIGINT '$.PageNumber'
,[Total] BIGINT '$.Total'
,[NumberOfPages] BIGINT '$.NumberOfPages'
)
--This is how you could accomplish the same with JSON_VALUE
SELECT
JSON_VALUE(#jsonData, '$.PageSize') AS [PageSize],
JSON_VALUE(#jsonData, '$.PageNumber') AS [PageNumber],
JSON_VALUE(#jsonData, '$.Total') AS [Total],
JSON_VALUE(#jsonData, '$.NumberOfPages') AS [NumberOfPages]