Getting duplicated sql result - mysql

I have 3 tables: Users, Articles and Votes
| Users | | Articles | | Votes |
| id | | id | | userId |
| name | | title | | articleId |
| email | | userId | | type |
I want to get users list with Count voteup and Count votedown for each one.
I'm testing this query:
SELECT u.id,u.name,u.email,
(SELECT COUNT(*) FROM votes as v WHERE v.type=1 AND v.articleId IN
(SELECT a.id From articles as a WHERE a.userId = u.id) ) AS totalvoteup,
(SELECT COUNT(*) FROM votes as v WHERE v.type=0 AND v.articleId IN
(SELECT a.id From articles as a WHERE a.userId = u.id) ) AS totalvotedown
FROM users as u
I have the list I want when I test it via phpmyadmin(the results number matches with the number of users in the table), but when I try to get through Node server(from AngularJs or Postman) I'm getting duplicate results:
{
"users": [
[
{
"id": 1,
"name": "John Lennon",
"email": "johnlennon#gmail.com",
"totalvoteup": 0,
"totalvotedown": 0
},
{
"id": 2,
"name": "John Lennon 2",
"email": "johnlennon2#gmail.com",
"totalvoteup": 0,
"totalvotedown": 0
},
{
"id": 3,
"name": "John Lennon 3",
"email": "johnlennon3#gmail.com",
"totalvoteup": 0,
"totalvotedown": 1
},
{
"id": 4,
"name": "John Lennon 4",
"email": "johnlennon4#gmail.com",
"totalvoteup": 0,
"totalvotedown": 0
}
],
[
{
"id": 1,
"name": "John Lennon 1",
"email": "johnlennon1#gmail.com",
"totalvoteup": 0,
"totalvotedown": 0
},
{
"id": 2,
"name": "John Lennon 2",
"email": "johnlennon2#gmail.com",
"totalvoteup": 0,
"totalvotedown": 0
},
{
"id": 3,
"name": "John Lennon 3",
"email": "johnlennon3#gmail.com",
"totalvoteup": 0,
"totalvotedown": 1
},
{
"id": 4,
"name": "John Lennon 4",
"email": "johnlennon4#gmail.com",
"totalvoteup": 0,
"totalvotedown": 0
}
]
]
}
Any ideas how to resolve this?

Am not a Java guy and am not sure about the problem in question, but the query can be written in better way
SELECT DISTINCT u.id,
u.name,
u.email,
coalesce(totalvoteup,0) as totalvoteup,
coalesce(totalvotedown,0) as totalvotedown
FROM users AS u
LEFT JOIN (SELECT DISTINCT id,userId FROM articles) a
ON a.userId = u.id
LEFT JOIN (SELECT Count(CASE WHEN v.type = 1 THEN 1 END) AS totalvoteup,
Count(CASE WHEN v.type = 0 THEN 1 END) AS totalvotedown,
v.articleId
FROM votes v
GROUP BY v.articleId) v
ON a.id = v.articleId
May not help you to solve the problem just thought of sharing since I like query optimization

Related

Parsing JSON data with LOOP

I am parsing data from JSON with UNION ALL, but I need repeated it more times. Try to use LOOP, but it doesn't works. :(
I need to parse every element from array in JSON to rows from statements.
I change the number of element in: statements::json->0 and than UNION the data.
The CODE I want to replace with some LOOP:
(
SELECT
execution_entry_id,
account,
trim('"' FROM (account::json->'startBalance')::text) AS startBalance,
trim('"' FROM (account::json->'endBalance')::text) AS endBalance
FROM (
SELECT
execution_entry_id,
statements::json->0 AS account
FROM(
SELECT
e.id AS execution_entry_id,
response_body,
response_body::json->'statements' AS statements
FROM stage_cz.cb_data_execution_entry e
LEFT JOIN stage_cz.cb_data_execution_entry_details d
ON d.execution_entry_id = e.id
WHERE provider_name = 'sokordiatech'
) a
) b WHERE account IS NOT NULL
)
UNION ALL
(
SELECT
execution_entry_id,
account,
trim('"' FROM (account::json->'startBalance')::text) AS startBalance,
trim('"' FROM (account::json->'endBalance')::text) AS endBalance
FROM (
SELECT
execution_entry_id,
statements::json->1 AS account
FROM(
SELECT
e.id AS execution_entry_id,
response_body,
response_body::json->'statements' AS statements
FROM stage_cz.cb_data_execution_entry e
LEFT JOIN stage_cz.cb_data_execution_entry_details d
ON d.execution_entry_id = e.id
WHERE provider_name = 'sokordiatech'
) a
) b WHERE account IS NOT NULL
)
I try to use:
do $$
declare
counter integer := 0;
begin
while counter < 10 loop
SELECT
execution_entry_id,
statements::json->counter AS account
FROM(
SELECT
e.id AS execution_entry_id,
response_body,
response_body::json->'statements' AS statements
FROM stage_cz.cb_data_execution_entry e
LEFT JOIN stage_cz.cb_data_execution_entry_details d
ON d.execution_entry_id = e.id
WHERE provider_name = 'sokordiatech'
) a;
counter := counter + 1;
end loop;
end$$;
and it ends with error:
ERROR: query has no destination for result data
Hint: If you want to discard the results of a SELECT, use PERFORM instead.
Where: PL/pgSQL function inline_code_block line 6 at SQL statement
1 statement failed.
It's possible to get data with LOOP or how instead of 10x UNION ALL, please?
Thanks.
If you are use statements::json->0, so you have Json array in your Json string. For splitting array elements from Json array, you can use jsonb_array_elements_text function on PostgreSQL, this function will be extracting your array elements like as rows. For do this you don't need using loop. For example:
with tbl as (
select
'[
{
"employee_id": 2,
"full_name": "Megan Berry",
"manager_id": 1
},
{
"employee_id": 3,
"full_name": "Sarah Berry",
"manager_id": 1
},
{
"employee_id": 4,
"full_name": "Zoe Black",
"manager_id": 1
},
{
"employee_id": 5,
"full_name": "Tim James",
"manager_id": 1
},
{
"employee_id": 6,
"full_name": "Bella Tucker",
"manager_id": 2
}
]'::jsonb as jsondata
)
select jsondata->1 from tbl;
Result:
{"full_name": "Sarah Berry", "manager_id": 1, "employee_id": 3}
This is getting second element of Json array.
But you need all elements, for getting all elements and extracting key values use this syntax:
with table1 as (
select
'[
{
"employee_id": 2,
"full_name": "Megan Berry",
"manager_id": 1
},
{
"employee_id": 3,
"full_name": "Sarah Berry",
"manager_id": 1
},
{
"employee_id": 4,
"full_name": "Zoe Black",
"manager_id": 1
},
{
"employee_id": 5,
"full_name": "Tim James",
"manager_id": 1
},
{
"employee_id": 6,
"full_name": "Bella Tucker",
"manager_id": 2
}
]'::jsonb as jsondata
)
select
tb1.a1->>'full_name' as fullname,
tb1.a1->>'manager_id' as managerid,
tb1.a1->>'employee_id' as employeeid
from (
select jsonb_array_elements_text(jsondata)::jsonb as a1 from table1
) tb1
Result:
fullname managerid employeeid
Megan Berry 1 2
Sarah Berry 1 3
Zoe Black 1 4
Tim James 1 5
Bella Tucker 2 6

postgresql How to generate nested json objects by one table

I want to aggregate the data from one table to a complex json. The elements should be grouped by id column. And nested json should be grouped by section column
I have a table with data:
-----------------------------
| id | section | subsection |
----------------------------
| 1 | s_1 | ss_1 |
----------------------------
| 1 | s_1 | ss_2 |
----------------------------
| 1 | s_2 | ss_3 |
----------------------------
| 2 | s_3 | ss_4 |
----------------------------
I want to create json like that:
[
{
"id": 1,
"sections": [
{
"section": "s_1",
"subsections": [
{
"subsection": "ss_1"
},
{
"subsection": "ss_2"
}
]
},
{
"section": "s_2",
"subsections": [
{
"subsection": "ss_3"
}
]
}
]
},
{
"id": 2,
"sections": [
{
"section": "s_3",
"subsections": [
{
"subsection": "ss_3"
}
]
}
]
}
]
I tried do it like that:
select
json_build_array(
json_build_object(
'id', a.id,
'sections', json_agg(
json_build_object(
'section', b.section,
'subsections', json_agg(
json_build_object(
'subsection', c.subsection
)
)
)
)
)
)
from table as a
inner join table as b on a.section = b.section
inner join table as c on b.subsection = c.subsection
group by a.id;
BUT there is a problem: Nested aggregate calls are not allowed
Is there any possible way to use nested aggregate calls? Or is there more elegant solution?
You'll need to use CTEs or nested queries for this. No JOINs necessary though:
SELECT json_agg(
json_build_object(
'id', a.id,
'sections', a.sections
)
)
FROM (
SELECT b.id, json_agg(
json_build_object(
'section', b.section,
'subsections', b.subsections
)
) AS sections
FROM (
SELECT c.id, c.section, json_agg(
json_build_object(
'subsection', c.subsection
)
) AS subsections
FROM table AS c
GROUP BY id, section
) AS b
GROUP BY id
) AS a;

How to join two tables in mysql with matching data and group in array

I need to join two tables (products and orders) in mysql with a matching data (order id) and different data (products ids) that should be in a array.
I tried with a simple JOIN but data are not being grouped. Does anyone can give me a light?
SELECT Order.id, Order.userId, Product.id AS productsIds
FROM Orders AS Order
JOIN Products AS Product
ON Order.id = Product.orderId
Result:
[
{
"id": 1,
"userId": 1,
"productsIds": 2
},
{
"id": 1,
"userId": 1,
"productsIds": 5
},
{
"id": 1,
"userId": 1,
"productsIds": 6
},
{
"id": 3,
"userId": 2,
"productsIds": 4
},
{
"id": 2,
"userId": 3,
"productsIds": 3
}
]
Expected:
[
{
"id": 1,
"userId": 1,
"productsIds": [2, 5, 6]
},
{
"id": 3,
"userId": 2,
"productsIds": 4
},
{
"id": 2,
"userId": 3,
"productsIds": 3
}
]
You need to use GROUP BY clause and GROUP_CONCAT in select statement, will give the expected result.
Following is the query.
SELECT Order.id, Order.userId, GROUP_CONCAT(Product.id) AS productsIds FROM Orders AS Order JOIN Products AS Product ON Order.id = Product.orderId GROUP BY Order.id, Order.userId ;

mysql jsonarrayagg for comma seperated id

i have two table casetemp and medicication_master
patient has fields
id
name
age
sex
medicineid
1
xyz
23
M
1,2
2
abc
20
f
3
medicine has fields
id
medname
desc
1
crosin
fever tab
2
etzaa
shampoo
3
zaanta
painkiller
i want the mysql left join output as following :
[{
"id":"1",
"name":"xyz",
"age":"23",
"sex":"M",
"medicine_id":"1,2",
"medicine_Data":[
{
"id":"1"
"medname":"crosin",
"desc":"fever tab"
},
{
"id":"2"
"medname":"etzaa",
"desc":"shampoo"
}]
},
{
"id":"2",
"name":"abc",
"age":"20",
"sex":"F",
"medicine_id":"3",
"medicine_Data":[{
"id":"3"
"medname":"zaanta",
"desc":"pain killer"
}]
}]
the query i used is
SELECT json_object(
'id', b.id,
'name',b.name,
'age',b.age,
'sex',b.sex,
'medicine_id',b.medicine_id,
'medicine_data', json_arrayagg(json_object(
'id', pt.id,
'medname', pt.medname,
'desc',pt.desc,
))
)
FROM patient b LEFT JOIN medication_master pt
ON b.medicine_id = pt.id
where b.id=1
GROUP BY b.id;
thanks in advance

JOIN three tables together and limit a row of thirst table - PDO

I have three tables :
table1
id title name user token
1 supermarket big market user1.example#gmail.com aaaaa
2 hear styler stylist user2.example#gmail.com bbbbb
table2
id country city user token
1 USA New York user1.example#gmail.com aaaaa
2 UK London user2.example#gmail.com bbbbb
table3
id url user token
1 uploadPic/image1.jpg user1.example#gmail.com aaaaa
2 uploadPic/image2.jpg user1.example#gmail.com aaaaa
3 uploadPic/image3.jpg user2.example#gmail.com bbbbb
4 uploadPic/image4.jpg user2.example#gmail.com bbbbb
5 uploadPic/image5.jpg user2.example#gmail.com bbbbb
6 uploadPic/image6.jpg user2.example#gmail.com bbbbb
and I used INNER JOIN to merge tables together:
$response['info'] = array();
$sql = "SELECT * FROM `table1` as tb1
INNER JOIN `table2` as tb2 ON tb1.token = tb2.token
INNER JOIN table3 as tb3 ON tb3.token = tb1.token
ORDER BY tb1.id DESC";
$run = $connect->prepare($sql);
$run->execute();
$record = $run->fetchAll(PDO::FETCH_ASSOC);
$response['info'] = $recordAdvert;
echo json_encode($response,JSON_PRETTY_PRINT);
and the result is :
{
"info": [
{
"id": "6",
"title": "superMarket",
"name": "big market",
"user": "user2.example#gmail.com",
"token": "bbbbb",
"country": "UK",
"city": "London",
"url": "uploadPic/image2.jpg"
},
{
"id": "5",
"title": "superMarket",
"name": "big market",
"user": "user2.example#gmail.com",
"token": "bbbbb",
"country": "UK",
"city": "London",
"url": "uploadPic/image1.jpg"
},
{
"id": "4",
"title": "superMarket",
"name": "big market",
"user": "user2.example#gmail.com",
"token": "bbbbb",
"country": "UK",
"city": "London",
"url": "uploadPic/image6.jpg"
},
{
"id": "3",
"title": "hear styler",
"name": "stylist",
"user": "user1.example#gmail.com",
"token": "aaaaa",
"country": "USA",
"city": "NEW YORK",
"url": "uploadPic/image5.jpg"
},
{
"id": "2",
"title": "hear styler",
"name": "stylist",
"user": "user1.example#gmail.com",
"token": "aaaaa",
"country": "USA",
"city": "NEW YORK",
"url": "uploadPic/image4.jpg"
},
{
"id": "1",
"title": "hear styler",
"name": "stylist",
"user": "user1.example#gmail.com",
"token": "aaaaa",
"country": "USA",
"city": "NEW YORK",
"url": "uploadPic/image3.jpg"
}
]
}
but this is not that i want. there are must be just two rows because i have just two user and two token so i want to limit image to 1 but i can't due to when i used limit in image table to just limit image to one for both of users it limit total table.
the result must be something like this:
{
"advert": [
{
"id": "2",
"title": "hear styler",
"name": "stylist",
"user": "user2.example#gmail.com",
"token": "bbbbb",
"country": "UK",
"city": "London",
"url": "uploadPic/image3.jpg"
},
{
"id": "1",
"title": "supermarket",
"name": "big market",
"user": "user1.example#gmail.com",
"token": "aaaaa",
"country": "USA",
"city": "New york",
"url": "uploadPic/image1.jpg"
}
]
}
I edit the select query like this :
$sql = "SELECT * FROM `table1` as tb1
INNER JOIN `table2` as tb2 ON tb1.token = tb2.token
INNER JOIN (SELECT * FROM table3 LIMIT 1) as tb3 ON tb3.token = tb1.token
ORDER BY tb1.id DESC";
but it limit the total row not just table 3 row.
{
"info": [
{
"id": "6",
"title": "superMarket",
"name": "big market",
"user": "user2.example#gmail.com",
"token": "bbbbb",
"country": "UK",
"city": "London",
"url": "uploadPic/image2.jpg"
}
]
}
You can use a correlated subquery that use LIMIT to get just one URL per user.
SELECT t1.id,
t1.title,
t1.name,
t1.user,
t1.token,
t1.country,
t2.city,
(SELECT t3.url
FROM table3 t3
WHERE t3.token = t1.token
ORDER BY t3.id DESC
LIMIT 1) url
FROM table1 t1
INNER JOIN table2 t2
ON t2.token = t1.token
ORDER BY t1.id DESC;