I'm trying to extract a JSON from a table, my code is something like this:
SELECT
JSON_ARRAY(
JSON_OBJECT(
'id', studant.id,
'student', student.name,
'best_grades',
JSON_ARRAYAGG(
CASE
WHEN class.test_grade = A
THEN
JSON_OBJECT(
'id', class.id,
'class', class.name,
'test_grade', class.test_grade
)
END
)))
It works pretty well, it adds a new object every time the condition is true, but the problem is, when test_grade is different than A it still adding an object, but with null as value, it gets like this:
[{
"id": 1,
"student": "Adam",
"best_grades": [
{
"id": 1,
"class": "Math",
"test_grade": "A"
},
{
"id": 2,
"class": "Biology",
"test_grade": "A"
},
null,
null
]
},
{
"id": 2,
"student": "Susy",
"best_grades": [
{
"id": 1,
"class": "Math",
"test_grade": "A"
},
null,
{
"id": 3,
"class": "History",
"test_grade": "A"
},
null
]
},
{
"id": 3,
"student": "Max",
"best_grades": [
null,
{
"id": 2,
"class": "Biology",
"test_grade": "A"
},
{
"id": 3,
"class": "History",
"test_grade": "A"
},
null
]
}
]
What I need is, in case the condition is not true the program just skip to the next object instead of returning null and creating a new object like that.
Basically I want it to IGNORE, SKIP, PASS or DO NOTHING when the grade is different than A, someone told me to do something like
CASE
WHEN class.test_grade = A
THEN
JSON_OBJECT(
'id', class.id,
'class', class.name,
'test_grade', class.test_grade
)
ELSE
BEGIN
END
END CASE
But it doesn't work and says that "'END' is not valid in this position";
Is there a way to make MYSQL ignore the command if the condition is false?
Related
[
{
"permissions": [
{
"name": "CREATE",
"id": 1
},
{
"name": "DELETE",
"id": 4
}
],
"roles": [
{
"name": "ADMIN",
"permission": [
{
"name": "CREATE",
"id": 1
},
{
"name": "UPDATE",
"id": 2
},
{
"name": "GET",
"id": 3
},
{
"name": "DELETE",
"id": 4
}
],
"id": 1
},
{
"name": "ADMIN",
"permission": [
{
"name": "CREATE",
"id": 1
},
{
"name": "UPDATE",
"id": 2
},
{
"name": "GET",
"id": 3
},
{
"name": "DELETE",
"id": 4
}
],
"id": 1
}
],
"id": 1,
"username": "raj#100"
},
{
"permissions": [
{
"name": null,
"id": null
}
],
"roles": [
{
"name": "USER",
"permission": [
{
"name": "GET",
"id": 3
}
],
"id": 3
}
],
"id": 2,
"username": "ram145"
}
]
As you can see from the above output the in roles the ADMIN is repeated twice and in the second users has no permissions so he should have an empty array but the output is with the permission object with all its values empty
This is the jooq statement which is executed :
public Object findAllUsers(String role, String permission) {
SelectOnConditionStep<Record1<JSON>> query = dslContext.select(
jsonObject(
key("id").value(USER.ID),
key("fullName").value(USER.FULL_NAME),
key("username").value(USER.USERNAME),
key("email").value(USER.EMAIL),
key("mobile").value(USER.MOBILE),
key("isActive").value(USER.IS_ACTIVE),
key("lastLoggedIn").value(USER.LAST_LOGGED_IN),
key("profileImage").value(USER.PROFILE_IMAGE),
key("roles").value(
coalesce(
jsonArrayAgg(
jsonObject(
key("id").value(ROLE.ID),
key("name").value(ROLE.NAME),
key("permission").value(
coalesce(
select(
jsonArrayAgg(
jsonObject(
key("id").value(PERMISSION.ID),
key("name").value(PERMISSION.NAME)
)
)
).from(ROLE_PERMISSION)
.leftJoin(PERMISSION)
.on(PERMISSION.ID.eq(ROLE_PERMISSION.PERMISSION_ID))
.where(ROLE_PERMISSION.ROLE_ID.eq(ROLE.ID))
.orderBy(PERMISSION.NAME.asc()),
jsonArray()
)
)
)
),
jsonArray()
)
),
key("permissions").value(
coalesce(
jsonArrayAgg(
jsonObject(
key("id").value(PERMISSION.ID),
key("name").value(PERMISSION.NAME)
)
),
jsonArray()
)
)
)
).from(USER)
.leftJoin(USER_ROLE).on(USER.ID.eq(USER_ROLE.USER_ID))
.leftJoin(ROLE).on(USER_ROLE.ROLE_ID.eq(ROLE.ID))
.leftJoin(USER_PERMISSION).on(USER.ID.eq(USER_PERMISSION.USER_ID))
.leftJoin(PERMISSION).on(USER_PERMISSION.PERMISSION_ID.eq(PERMISSION.ID));
if (role != null) {
query.where(ROLE.NAME.eq(role));
}
if (permission != null) {
query.where(PERMISSION.NAME.eq(role));
}
return query.groupBy(USER.ID)
.orderBy(USER.ID.asc())
.fetch().into(JSONObject.class);
}
Is there any way to fix this problem?
Why the duplicates?
Your join graph creates a cartesian product between the two "nested collections" ROLE and PERMISSION. You can't remove that cartesian product with GROUP BY alone, that works only if you join a single to-many relationship.
Instead, you can write subqueries like this (you already did this correctly for the ROLE_PERMISSION relationship):
dslContext.select(jsonObject(
key("id").value(USER.ID),
key("username").value(USER.USERNAME),
key("roles").value(coalesce(field(
select(jsonArrayAgg(jsonObject(
key("id").value(ROLE.ID),
key("name").value(ROLE.NAME),
key("permission").value(coalesce(field(
select(coalesce(jsonArrayAgg(jsonObject(
key("id").value(PERMISSION.ID),
key("name").value(PERMISSION.NAME)
)), jsonArray()))
.from(ROLE_PERMISSION)
.join(PERMISSION)
.on(PERMISSION.ID.eq(ROLE_PERMISSION.PERMISSION_ID))
.where(ROLE_PERMISSION.ROLE_ID.eq(ROLE.ID))
.orderBy(PERMISSION.NAME.asc())
), jsonArray()))
)))
.from(USER_ROLE)
.join(ROLE)
.on(USER_ROLE.ROLE_ID.eq(ROLE.ID))
.where(USER_ROLE.USER_ID.eq(USER.ID))
), jsonArray())),
key("permissions").value(coalesce(field(
select(coalesce(jsonArrayAgg(jsonObject(
key("id").value(PERMISSION.ID),
key("name").value(PERMISSION.NAME)
)))
.from(USER_PERMISSION)
.join(PERMISSION)
.on(USER_PERMISSION.PERMISSION_ID.eq(PERMISSION.ID))
.where(USER_PERMISSION.USER_ID.eq(USER.ID))
), jsonArray()))
))
.from(USER)
.orderBy(USER.ID.asc())
.fetch().into(JSONObject.class);
Join vs semi join
After you edited your question to become a slightly different question, the point you were trying to make is that you want to filter the USER table by some ROLE or PERMISSION that they must have. You can't achieve this with JOIN alone (unless you're happy with the duplicates). The answer I gave doesn't change. If you're joining multiple to-many relationships, you'll get cartesian products.
So, instead, why not semi join them? Either with jOOQ's synthetic SEMI JOIN syntax, or manually using EXISTS or IN, e.g.
.where(role != null
? exists(selectOne()
.from(USER_ROLE)
.where(USER_ROLE.role().NAME.eq(role))
)
: noCondition()
)
.and(permission != null
? exists(selectOne()
.from(USER_PERMISSION)
.where(USER_PERMISSION.permission().NAME.eq(permission))
)
: noCondition()
)
This is using the implicit join syntax, which is optional, but I think it does simplify your query.
I retrieved JSON from an API (part of json file was showed at the bottom). I was hoping to parse the json and store in SQL table. With the following SQL query, there was only 1 row returned. How can I return all rows with table headers NAME JobNum Water Sewer ? I tried while loop using variable to replace [0] after $.items, but seemed not to work. I wasn't sure if the structure of json file works for cross apply.
DECLARE #MondayComApi VARCHAR(MAX)
SELECT #MondayComApi = BULKCOLUMN
FROM OPENROWSET(BULK'D:/temp/a.json', SINGLE_BLOB) JSON
IF (ISJSON(#MondayComApi) = 1)
BEGIN
PRINT 'JSON File is valid';
SELECT NAME, JobNum, Water, Sewer
FROM OPENJSON(#MondayComApi, '$.data.boards')
WITH (
NAME VARCHAR(100) '$.items[0].name',
JobNum VARCHAR(100) '$.items[0].column_values[0].text',
Water VARCHAR(100) '$.items[0].column_values[1].text',
Sewer VARCHAR(100) '$.items[0].column_values[2].text'
)
END
ELSE
BEGIN
PRINT 'JSON File is invalid';
END
The following was part of the JSON - I reduced content of "items" to shorten length:
{
"data": {
"boards": [
{
"items": [
{
"name": "Holmes Project",
"column_values": [
{
"title": "Job",
"text": "D1210"
},
{
"title": "Water",
"text": "YES"
},
{
"title": "Sewer",
"text": "YES"
}
]
},
{
"name": "Lake Short Project)",
"column_values": [
{
"title": "Job",
"text": "D1014"
},
{
"title": "Water",
"text": "YES"
},
{
"title": "Sewer",
"text": "YES"
}
]
},
{
"name": "Chase Project",
"column_values": [
{
"title": "Job",
"text": "D2101"
},
{
"title": "Water",
"text": "NO"
},
{
"title": "Sewer",
"text": "YES"
}
]
},
{
"name": "Juanita Project",
"column_values": [
{
"title": "Job",
"text": "D1102"
},
{
"title": "Water",
"text": "YES"
},
{
"title": "Sewer",
"text": "YES"
}
]
},
{
"name": "Lowry Project",
"column_values": [
{
"title": "Job",
"text": "D1014"
},
{
"title": "Water",
"text": "YES"
},
{
"title": "Sewer",
"text": "YES"
}
]
}
]
}
]
},
"account_id": 5687438790
}
I moved more of the JSON path out of WITH and into OPENJSON:
SELECT NAME, JobNum, Water, Sewer
FROM
OPENJSON(#MondayComApi, '$.data.boards[0].items')
WITH (
NAME VARCHAR(100) '$.name',
JobNum VARCHAR(100) '$.column_values[0].text',
Water VARCHAR(100) '$.column_values[1].text',
Sewer VARCHAR(100) '$.column_values[2].text'
)
Firstly, SINGLE_BLOB should be SINGLE_CLOB if it is ANSI or UTF-8 data.
Next, to break out a JSON array into separate rows, you need OPENJSON without a schema, then you use OPENJSON again on each row, where key column contains the index, and value contains the object.
If boards always contains only one object in its array, you can remove the second OPENJSON and change the path of the first to $.data.boards[0].items
Then we can break out the column_values and pivot them back up into a single row.
SELECT
NAME = JSON_VALUE(item.value, '$.name'),
cv.JobNum,
cv.Water,
cv.Sewer
FROM OPENJSON(#j, '$.data.boards') boards
CROSS APPLY OPENJSON(boards.value, '$.items') item
CROSS APPLY (
SELECT
MIN(CASE WHEN title = 'Job' THEN [text] END) JobNum,
MIN(CASE WHEN title = 'Water' THEN [text] END) Water,
MIN(CASE WHEN title = 'Sewer' THEN [text] END) Sewer
FROM OPENJSON(item.value, '$.column_values')
WITH (
title varchar(100),
[text] varchar(100)
) column_values
) cv
any one can help me how to get the sub document List with pagination
i just give a sample example :
{
"accessories": [`
{
"data": {
"name": "TEST",
"updated_at": "2020-03-27T16:16:20.818Z"
},
"id": "56e83ea1-042e-47e0-85f8-186189c37426"
}
],
"calibration_reports": [`
{
"data": {
"deleted_at": "",
"frm27_equipment": [
"test_cat1"
],
"frm27_link": [
"yes"
],
"frm27_submit": null,
"updated_at": "2020-03-30T10:24:52.703Z"
},
"id": "e4c8b1b4-7f37-46db-a49d-bca74482b968"
},
{
"data": {
"deleted_at": "",
"frm27_equipment": [
"test_cat1"
],
"frm27_link": [
"no"
],
"frm27_submit": null,
"updated_at": "2020-03-30T10:34:37.615Z"
},
"id": "445854d6-66bf-4e33-b620-05a5053119a8"
}
],
}
]
}
Here i want to get a calibration_reports list with pagination is it possible ? using couchbase (N1ql Query)
please if any one know, what is the process how to get the list of result with pagination using couchbase(N1QL) query. please help me.
One possible way to go about this is to use UNNEST.
For instance:
SELECT calreports.id
FROM utpal u
UNNEST u.calibration_reports calreports
This would return something like:
[
{ "id": "aaa" },
{ "id": "bbb" },
{ "id": "ccc" },
... etc ...
]
And then you can use normal LIMIT/OFFSET for pagination, like so:
SELECT calreports.id
FROM utpal u
UNNEST u.calibration_reports calreports
LIMIT 50
OFFSET 150;
I have MarkLogic 9 on my database.
I have created the following documents in my database:
test1.json
{
"users": [
{
"userId": "A",
"value": 0
}
]
}
test2.json
{
"users": [
{
"userId": "A",
"value": "0"
}
]
}
test3.json
{
"users": [
{
"value": 0,
"userId": "A"
}
]
}
test4.json
{
"users": [
{
"value": "0",
"userId": "A"
}
]
}
I have run the following codes and have recorded the results:
cts.uris(“”, null, cts.jsonPropertyScopeQuery(
"users",
cts.andQuery(
[
cts.jsonPropertyValueQuery('userId', "A"),
cts.jsonPropertyValueQuery('value', "0"),
]
)
))
Result: test2.json, test4.json
cts.uris(“”, null, cts.jsonPropertyScopeQuery(
"users",
cts.andQuery(
[
cts.jsonPropertyValueQuery('userId', "A"),
cts.jsonPropertyValueQuery('value', 0),
]
)
))
Result: test3.json
I was wondering why test1.json did not return in the 2nd query while test3.json did. They both had the same values for fields but in different order. The order of the fields are different in test2.json and test4.json, however, the query returned both documents. The only difference between the 2 pairs that I can think of is that there are 2 data types for the field “value”, integer and string.
How would I go about resolving this issue?
https://docs.marklogic.com/cts.jsonPropertyValueQuery shows the value to match as an array.
If you want to keep the variants in data, maybe you can try something on the query side like cts.jsonPropertyValueQuery('value', ["0", 0])
I have as nested json object like this
{
"id": 1,
"parentId": null,
"name": "Product",
"children": [
{
"id": 50,
"parentId": 1,
"name": "Bicycle",
"children": [
{
"id": 100,
"parentId": 50,
"name": "Tire"
}
]
}
]
}
Oddly I have figured out how to build the nested tree from the result but not how to reverse it.
I have tried using lodash _.flatten and _.flattendeep but having one of those days where I can't get my head around this. Also the object can be of unknown depth. Any thoughts ?
My desired result is this.
[
{"id" : 1, "parentId" : null, "Product" },
{"id" : 50, "parentId" : 1 , "Bicycle"},
{"id" : 100, "parentId" : 50 , "Tire"}
]
not a very optimal solution but just an idea, NOTE: if dataset is very large there might be some performance issues.
resultsArray = [];
function flatten(obj) {
const { id, parentId, name, children} = obj;
if(children && children.length) {
children.map(child => flatten(child));
}
resultsArray.push({id, parentId, name});
}