Postgresql - Merge field to JSON object in a query - sql

Hello everyone, I have the following query below which contains a sub query:
SELECT g.id, g.name, data.permissions, gp.has_permission
FROM groups g
RIGHT JOIN groups_permissions gp ON gp.group_id = g.id
RIGHT JOIN (SELECT p.id, array_to_json(array_agg(to_json(p.*)))
FROM permissions p
GROUP BY p.id) AS data (id, permissions) ON (gp.permission_id = data.id)
WHERE g.id=1
This query returns the result bellow:
[
{
"id": "7a588463-1780-459a-9646-8f19e9cb6ded",
"name": "Administradores",
"permissions": [
{
"id": "bf9d5ee3-d554-4faa-9cf4-9c60acb79801",
"name": "Criar Grupos",
"slug": "criar-grupos",
"created_at": "2020-12-07T00:50:05.017783",
"updated_at": "2020-12-07T00:50:05.017783"
}
],
"has_permission": true
}
]
I would like to have the has_permission field inside the object in the permissions array.
Could someone help merge that field with the object?
Thank you for now.

Don't you just need to add has_permission to the json subrecord?
SELECT g.id, g.name, data.permissions
FROM groups g
RIGHT JOIN groups_permissions gp ON gp.group_id = g.id
RIGHT JOIN (SELECT p.id, array_to_json(array_agg(to_json(p.*, gp.has_permission)))
FROM permissions p
GROUP BY p.id) AS data (id, permissions) ON (gp.permission_id = data.id)
WHERE g.id=1

Related

is there a way to extract duplicated row value in sql as the key/grouping value?

I have following two tables
users
id | name
1 | john
2 | ada
events
id | content | userId
1 | 'applied' | 1
2 | 'interviewed| 1
What would be the query that returns data in the following shape:
[
{name:'john', events:[{id:1, content:'applied'},{id:2, content:'interviewed'}]}
]
I have tried to run following queries
attempt 1
select events.id, content, users.name
from events
left join users
on users.id=events.userId
where events.userId = ?
but it return duplicated value for the name as following
[
{
"id": 1,
"content": "ronaldo",
"name": "Norman Zboncak"
},
{
"id": 2,
"content": "messi",
"name": "Norman Zboncak"
},
{
"id": 3,
"content": "messi",
"name": "Norman Zboncak"
}
]
attempt 2
I tried to use group_concat but apparently you cannot pas multiple arguments into it so couldn't get the result in the desired shape
You must do a LEFT join of users to events and aggregate with SQLite's JSON Functions:
SELECT json_object(
'name', u.name,
'events', json_group_array(json_object('id', e.id, 'content', e.content))
) result
FROM users u LEFT JOIN events e
ON e.userId = u.id
WHERE u.id = 1 -- remove this line to get results for all users
GROUP BY u.id;
See the demo.

How to transform a postgresql select with join to a json object?

I want to transform the result from a select with joins into a json object. I mean this query:
select
cm.*,
e.*,
u.*,
from
chat_messages cm,
events e,
users u
where
cm.event_id = e.id
and cm.user_id = u.id
should output this:
{
"id": 1,
"message": "whatever",
"time": "2021-12-02T00:21:10.571848",
"user": {
"id": 35,
"name": "John Smith"
},
"event": {
"id": 19,
"name": "Test event",
"time": "2021-09-22T00:00:00-03:00",
"local": "Planet Earth"
}
}
(there are more fields than these. I'm just making the example simple)
I found a solution this way:
select
json_build_object(
'id', cm.id,
'message', cm.message,
'time', cm.time,
'user', to_json(u.*),
'event', to_json(e.*)
)
from
chat_messages cm,
events e,
users u
where
cm.event_id = e.id
and cm.user_id = u.id
But I think there should be a much better way to do this. Imagine that chat_messages had a lot more fields. It would be lengthy to describe field by field.
What I want is a way to for the query to transform subqueries in json without me describing field by field.
Anyone knows a better way to do this ?
According to, Postgres document you can use the row_to_json function to transfer row to JSON and then append each table rows with an alias to be detected by row_to_json
with cte as (
select
cm.*,
e as event,
u as user
from
chat_messages cm,
events e,
users u
where
cm.event_id = e.id
and cm.user_id = u.id
)
select row_to_json(c) from cte c;

SQL JSON Help and Query Help needed

Good day Stackoverflow,
I have found myself in a bit of a weird query situation. You see, I have to come up with a stored procedure that returns a data set like so;
[
"TestCase1": {
"SetText": {
"Element":"Username"
"Value":"123456"
},
"SetText": {
"Element":"Username",
"Value":"Admin"
},
"OnClick": {
"Element":"SubmitButton"
},
"Login": {
"Username":"admin",
"Password":"123456"
}
}
]
As you can see the data set is held together by the TestCase1 which is in reference to a Table Column Name. Test.Name
Follow by, the function name holding multiple objects.
Each function has its Keys be the parameter name and the keys values are the parameters values
So in this example, Test Case 1 has 4 actions
SetText("Username", "123456")
SetText("Password", "Admin")
OnClick("SubmitButton")
Login("Admin","123456")
The problem is; the query list below I can't alter it to the way I have the JSON above
SELECT TD.ID, F.[Name] AS [Function], P.[Name] AS [Parameter], E.[Name] AS [Data] FROM [QA].[TestData] TD
LEFT JOIN QA.[Parameter] P ON P.ID = TD.ParameterID
INNER JOIN QA.[Function] F ON F.ID = P.FunctionID
INNER JOIN QA.[XREF_Parameter_Element] XPE ON (P.ParameterTypeID = 1) AND (XPE.ID = TD.DataID)
INNER JOIN QA.[Element] E ON E.ID = XPE.ElementID
UNION ALL
SELECT TD.ID, F.[Name] AS [Function], P.[Name] AS [Parameter], XPV.[Value] AS [Data] FROM [QA].[TestData] TD
LEFT JOIN QA.[Parameter] P ON P.ID = TD.ParameterID
INNER JOIN QA.[Function] F ON F.ID = P.FunctionID
INNER JOIN QA.[XREF_Parameter_Value] XPV ON (P.ParameterTypeID <> 1) AND (XPV.ID = TD.DataID)
ORDER BY TD.ID
FOR JSON PATH, ROOT('TestCase1')
Here is what the query above turns out to be
{
"TestCase1":[
{
"ID":1,
"Function":"SetText",
"Parameter":"Element",
"Data":"Username"
},{
"ID":2,
"Function":"SetText",
"Parameter":"Value",
"Data":"123456"
},{
"ID":3,
"Function":"SetText",
"Parameter":"Element",
"Data":"Username"
},{
"ID":4,
"Function":"SetText",
"Parameter":"Value",
"Data":"Admin"
},{
"ID":5,
"Function":"OnClick",
"Parameter":"Element",
"Data":"SubmitButton"
},{
"ID":6,
"Function":"Login",
"Parameter":"Username",
"Data":"Admin"
},{
"ID":7,
"Function":"Login",
"Parameter":"Password",
"Data":"123456"
}
]
}
Is anyone able to help me out. I am more than willing to share contact information to be more clear. This is just ripping my brain apart.

Format nested JSON object from Postgres query

I want to get a JSON object formatted similar to this:
{
"username": "USERNAME",
"teamname": "TEAMNAME",
"logs": [
{
"log": {
"log_id": 29,
"person_id": 3,
"activity_id": 3,
"shoe_id": null,
"logdate": "2016-11-29",
"distance": null,
"activitytime": null,
"sleep": null,
"heartrate": null,
"logtitle": null,
"description": null
},
"activity": "Swim",
"comments": {
"comment_id": 1,
"description": "This is a comment",
"person_id": 1,
"log_id": 29
}
}]
}
Currently I have everything formatted correctly except the comments. Here is the SQL query I am using:
SELECT p.username, t.teamname, json_agg(json_build_object('log', l.*, 'comments', c.*, 'activity', a.activity)) as logs
FROM person_tbl p
INNER JOIN log_tbl l ON p.person_id = l.person_id
INNER JOIN activity_tbl a ON l.activity_id = a.activity_id
INNER JOIN comment_tbl c ON c.log_id = l.log_id
INNER JOIN person_team_tbl pt ON p.person_id = pt.person_id
INNER JOIN team_tbl t on t.team_id = pt.team_id
WHERE t.team_id = 5
AND l.logdate > NOW()::date - 7
GROUP BY p.username, t.teamname
ORDER BY p.username
I'm having trouble getting the comments of each log. Right now, it is returning every comment and repeating the logs (they are not associated).
Also, how could I get this query to return the username and teamname when everything else is null (like when there are no logs in the past week)?
Without an SQLfiddle we do not know what your data (and structure) is so it is difficult to answer your question.
For the NULL case - please modify the WHERE clause like this (deliberately not using COALESCE)
WHERE t.team_id = 5 AND (l.logdate IS NULL OR l.logdate > NOW()::date - INTERVAL '7 day')

SQL query returning an extra record

I've tried both right and inner join, either I end up with an extra record or not record at all. Please suggest what to fix in this query.
Table structure
Event -> Day -> Session
session_attendee
SELECT session.id,
(SELECT count(*) from event e INNER JOIN day AS d ON e.id = d.event_id INNER JOIN session AS s ON d.id = s.day_id WHERE e.id = event.id AND d.id = day.id) AS total,
day.date, session.name, session.start, session.end, session.room,
(SELECT COUNT(distinct attendee_id) FROM session s LEFT JOIN session_attendee AS sa ON s.id = sa.session_id WHERE s.id = session.id) AS attendees
FROM event
LEFT JOIN day ON event.id = day.event_id
LEFT JOIN session ON day.id = session.day_id
LEFT JOIN session_attendee ON session.id = session_attendee.session_id
WHERE event.id = 12
GROUP BY session.id
ORDER BY day.date, session.start, event.name;
Resultset
[
{
"id": 9,
"total": 1,
"date": "2015-05-12T04:00:00.000Z",
"name": "test",
"start": "00:55:00",
"end": "00:55:00",
"room": "abc",
"attendees": 0
},
{
"id": null,
"total": 0,
"date": "2015-05-13T04:00:00.000Z",
"name": null,
"start": null,
"end": null,
"room": null,
"attendees": 0
}
]
Just try it on postgresql, you sql query will fail, because it's wrong.
You are trying to select fields without an aggregate function and why do you not have a GROUP BY?
But the main reason why it is an incorrect query, is that you must change it to something like this:
WHERE session.id in (
SELECT
session.id
FROM
event
LEFT JOIN
day ON event.id = day.event_id
LEFT JOIN
session ON day.id = session.day_id
WHERE
event.id = 12