SQL query using GROUP_CONCAT() function - sql

I have two tables:
1.Activity-- which stores all the activities from a user
2.User-- which stores all the registered users
I want to fetch all the posts and the likes to all posts in one query. A row is a post or like is decided by the value of type column.
Table Name - Activity
| actId | parentId | type | postedby |
---------------------------------------------------
| 100 | NULL | post | 100 |
| 200 | 100 | like | 200 |
| 300 | 100 | like | 300 |
| 400 | 100 | like | 400 |
| 500 | NULL | post | 100 |
| 600 | 500 | like | 600 |
Table Name - User
| userId | name |
-------------------
| 100 | Amit |
| 200 | Alok |
| 300 | Arjun |
| 400 | Arpeet |
| 600 | Amaan |
The output should be
| actId | name | LikedBy |
------------------------------------------
| 100 | Amit | Alok, Arjun, Arpeet|
| 500 | Amit | Amaan |
NOTE - I don't want this to be achieved using FOR XML PATH since it is not supported in SQLite which I am working on.
My query attempt was
SELECT a.id, u.name,
(select group_concat(u.name) from activity a, user u where a.id = u.id and a.type = 'like'
group by a.parent) as likedby
FROM activity a, user u
WHERE a.id = u.id and a.type = 'post'
The result I got was
| Id | name | LikedBy |
---------------------------------------
| 100 | Amit | Alok, Arjun, Arpeet|
You can see that the other row was missing from result.

Try this:
select t.id4id Id, n1.Name Name, group_concat(n2.name) Groups
from (select t1.actid id4id, t1.postedby id4name, t2.postedby id4groups
from Activity t1 join Activity t2 on t1.actid = t2.parentid) t join "user" n1 on t.id4name = n1.userid join "User" n2 on t.id4groups = n2.userid
group by id4id
Notes: 1. I assume that a post will always have a null value in parent

You do not need a subquery for this. You simply need two joins in order to get the values for the original name and the liked name:
select a.parentid, u.name, group_concat(ul.name separator ', ') as likedby
from activity a join
user ul
on a.postedby = ul.userid join
user u
on a.parentid = u.userid
where a.type = 'like'
group by a.parentid, u.name;

Related

How do I receive a pair of ids of entities in many-to-many relation with null value for the second id if condition is not met

I've got the following tables: person (id), person_agency (person_id, agency_id) and agency(id, type)
this is my query:
select p.id, a.id from person p
left join person_agency pa on p.id = pa.person_id
left join agency a on pa.agency_id = a.id
where a.type = 'agency_type1'
However, with the query I get only the persons who have a relation with an agency of "agency_type1". Instead, I would like to get a list of ids of ALL persons with ids of agencies, where the relation exists and null where it doesn't. I tried naive outer joins but it did not work.
For this content of the tables:
Person:
+-------+
| id |
+-------+
| 1 |
| 2 |
| 3 |
| 4 |
+-------+
Person_agency:
+-----------+-----------+
| person_id | agency_id |
+-----------+-----------+
| 1 | 1 |
| 1 | 2 |
| 2 | 4 |
| 4 | 5 |
+-----------+-----------+
Agency:
+--------+------------------+
| id | type |
+--------+------------------+
| 1 | agency_type1 |
| 2 | some_other_type |
| 3 | agency_type1 |
| 4 | agency_type1 |
| 5 | some_other_type |
+--------+------------------+
I receive the folloing output of my query:
+----------+------+
| p.id | a.id |
+----------+------+
| 1 | 1 |
| 2 | 4 |
+----------+------+
The desired output would be:
+----------+------+
| p.id | a.id |
+----------+------+
| 1 | 1 |
| 2 | 4 |
| 3 | null |
| 4 | null |
+----------+------+
It looks like you don't want to distinguish between an agency which is missing and an agency which is present but the wrong type. So you would want a regular JOIN not a LEFT JOIN for the pa/a pair, and also want to filter out the unwanted type directly on that join. Then you want to do a LEFT JOIN from person to the results of that just-described join.
select p.id p_id, a.id a_id from person p
left join (person_agency pa join agency a on pa.agency_id = a.id and a.type='agency_type1')
on p.id = pa.person_id;
p_id | a_id
------+--------
1 | 1
2 | 4
3 | (null)
4 | (null)
The parenthesis around the join pair are not necessary but I find they make it clearer.
If one person is associated to multiple agencies of the correct type, all of them will be shown. I assume this is what you want, although it was not a scenario covered in your example data.
Try to change left join
to
join (inner join).

Updating the column that the table was joined on

I need to update a column that two tables were joined on and I'm having a difficult time wrapping my head around it. This is for SQL Server. Loose example below...
User
ID | Name | GroupID |
---------------------
1 | Bob | 100 |
2 | Alex | 300 |
3 | Sara | 300 |
Group
ID | Name |
----------------
100 | Produce |
200 | Cashier |
300 | Stocker |
GroupID is a foreign key to the Group table and they are being joined on that. I HAVE to update the GroupID column in User based on the Name column in Group. For example, I want Alex and Sara to change from 'Stocker' to 'Cashier'. My solution is below, but it doesn't seem to work.
UPDATE User
SET User.GroupID = G.ID
FROM User U
JOIN Group G ON U.GroupID = G.ID
WHERE User = 'Sara' OR User = 'Alex'
Expected Result
User
ID | Name | GroupID |
---------------------
1 | Bob | 100 |
2 | Alex | 200 |
3 | Sara | 200 |
You don't need and updated with join ..
but you could use a subquery for get the expected id from group
update user
set User.GroupID = (select id
from group where name = 'Cashier )
where User = 'Sara' OR User = 'Alex'

Access Queries comparing two tables

I have two tables in Access, Table A and Table B:
Table MasterLockInsNew:
+----+-------+----------+
| ID | Value | Date |
+----+-------+----------+
| 1 | 123 | 12/02/13 |
| 2 | 1231 | 11/02/13 |
| 4 | 1265 | 16/02/13 |
+----+-------+----------+
Table InitialPolData:
+----+-------+----------+---+
| ID | Value | Date |Type
+----+-------+----------+---+
| 1 | 123 | 12/02/13 | x |
| 2 | 1231 | 11/02/13 | x |
| 3 | 1238 | 10/02/13 | y |
| 4 | 1265 | 16/02/13 | a |
| 7 | 7649 | 18/02/13 | z |
+----+-------+----------+---+
All I want are the rows from table B for IDs not contained in A. My current code looks like this:
SELECT Distinct InitialPolData.*
FROM InitialPolData
WHERE InitialPolData.ID NOT IN (SELECT Distinct InitialPolData.ID
from InitialPolData INNER JOIN
MasterLockInsNew
ON InitialPolData.ID=MasterLockInsNew.ID);
But whenever I run this in Access it crashes!! The tables are fairly large but I don't think this is the reason.
Can anyone help?
Thanks
or try a left outer join:
SELECT b.*
FROM InitialPolData b left outer join
MasterLockInsNew a on
b.id = a.id
where
a.id is null
Simple subquery will do.
select * from InitialPolData
where id not in (
select id from MasterLockInsNew
);
Try using NOT EXISTS:
SELECT Distinct i.*
FROM InitialPolData AS i
WHERE NOT EXISTS (SELECT 1
FROM MasterLockInsNew AS m
WHERE m.ID = i.ID)

JOIN the table if records exist

is it possible if i want to do INNER JOIN only if the record exist on the 2nd table if not then dont join?
this is my table
User table
+--------+--------------+
| id | name |
+--------+--------------+
| 1 | John |
+--------+--------------+
| 2 | Josh |
+--------+--------------+
House table
+--------+-------------+--------------+
| id | owner_id | house_no |
+--------+-------------+--------------+
| 1 | 1 | 991 |
+--------+-------------+--------------+
this is my INNER JOIN query
SELECT h.owner_id, u.name, h.house_no FROM user u
INNER JOIN house h on u.id = h.owner_id
WHERE u.id = :id
it will return this result if id = 1
+--------+--------------+--------------+
| id | name | house_no |
+--------+--------------+--------------+
| 1 | John | 991 |
+--------+--------------+--------------+
but if i run with id = 2 no result returned.
what i want to do right now is it still return the result even when no data exist for id = 2 in table house
Use a left outer join instead.
SELECT u.id, u.name, h.house_no FROM user u
LEFT OUTER JOIN house h on u.id = h.owner_id
WHERE u.id = :id
The resulting record will be:
+--------+--------------+--------------+
| id | name | house_no |
+--------+--------------+--------------+
| 2 | Josh | null |
+--------+--------------+--------------+

PostgreSQL select all from one table and join count from table relation

I have two tables, post_categories and posts. I'm trying to select * from post_categories;, but also return a temporary column with the count for each time a post category is used on a post.
Posts
| id | name | post_category_id |
| 1 | test | 1 |
| 2 | nest | 1 |
| 3 | vest | 2 |
| 4 | zest | 3 |
Post Categories
| id | name |
| 1 | cat_1 |
| 2 | cat_2 |
| 3 | cat_3 |
Basically, I'm trying to do this without subqueries and with joins instead. Something like this, but in real psql.
select * from post_categories some-type-of-join posts, count(*)
Resulting in this, ideally.
| id | name | count |
| 1 | cat_1 | 2 |
| 2 | cat_2 | 1 |
| 3 | cat_3 | 1 |
Your help is greatly appreciated :D
You can use a derived table that contains the counts per post_category_id and left join it to the post_categories table
select p.*, coalesce(t1.p_count,0)
from post_categories p
left join (
select post_category_id, count(*) p_count
from posts
group by post_category_id
) t1 on t1.post_category_id = p.id
select post_categories.id, post_categories.name , count(posts.id)
from post_categories
inner join posts
on post_category_id = post_categories.id
group by post_categories.id, post_categories.name