Merge 2 SQL query CodeIgniter - sql

I would like to merge these 2 queries to retrieve my datas in a view :
QUERY 1 :
$query = $this->db->query('SELECT ft_upload_data.*, ft_categories.*, ft_categories.category_name
FROM ft_upload_data
LEFT JOIN assigned_categories ON assigned_categories.ft_upload_data_id = ft_upload_data.post_id
LEFT JOIN ft_categories ON ft_categories.cat_id = assigned_categories.ft_categories_id
ORDER BY ft_upload_data.rank ASC
');
return $query->result();
QUERY 2 :
$query2 = $this->db->query('SELECT a.post_id,
COUNT(*) AS num_comments
FROM ft_upload_data a
JOIN ft_comments c ON c.post_id = a.post_id
GROUP BY a.post_id');
return $query2->result();
I can't figure it out :/ Any ideas to trick this?
Thanks !

The simplest (but not necessarily the most efficient) way would be to do it in an in-line query:
SELECT ft_upload_data.*, ft_categories.*,
(SELECT COUNT(*)
FROM ft_comments c
where c.post_id = ft_upload_data.post_id) AS num_comments
FROM ft_upload_data
LEFT JOIN assigned_categories
ON assigned_categories.ft_upload_data_id = ft_upload_data.post_id
LEFT JOIN ft_categories
ON ft_categories.cat_id = assigned_categories.ft_categories_id
ORDER BY ft_upload_data.rank ASC
A more efficient way would be to join to the ft_comments table and group by post_id (assuming that this uniquely identifies ft_upload_data rows), like so:
SELECT ft_upload_data.post_id,
/* include the maximum of each required field from ft_upload_data and
ft_categories here, with appropriate aliases */
COUNT(*) AS num_comments
FROM ft_upload_data
LEFT JOIN assigned_categories
ON assigned_categories.ft_upload_data_id = ft_upload_data.post_id
LEFT JOIN ft_categories
ON ft_categories.cat_id = assigned_categories.ft_categories_id
LEFT JOIN ft_comments c
on c.post_id = ft_upload_data.post_id
GROUP BY ft_upload_data.post_id
ORDER BY max(ft_upload_data.rank) ASC

Related

How to create distinct count from queries with several tables

I am trying to create one single query that will give me a distinct count for both the ActivityID and the CommentID. My query in MS Access looks like this:
SELECT
tbl_Category.Category, Count(tbl_Activity.ActivityID) AS CountOfActivityID,
Count(tbl_Comments.CommentID) AS CountOfCommentID
FROM tbl_Category LEFT JOIN
(tbl_Activity LEFT JOIN tbl_Comments ON
tbl_Activity.ActivityID = tbl_Comments.ActivityID) ON
tbl_Category.CategoryID = tbl_Activity.CategoryID
WHERE
(((tbl_Activity.UnitID)=5) AND ((tbl_Comments.PeriodID)=1))
GROUP BY
tbl_Category.Category;
I know the answer must somehow include SELECT DISTINCT but am not able to get it to work. Do I need to create multiple subqueries?
This is really painful in MS Access. I think the following does what you want to do:
SELECT ac.Category, ac.num_activities, aco.num_comments
FROM (SELECT ca.category, COUNT(*) as num_activities
FROM (SELECT DISTINCT c.Category, a.ActivityID
FROM (tbl_Category as c INNER JOIN
tbl_Activity as a
ON c.CategoryID = a.CategoryID
) INNER JOIN
tbl_Comments as co
ON a.ActivityID = co.ActivityID
WHERE a.UnitID = 5 AND co.PeriodID = 1
) as caa
GROUP BY ca.category
) as ca LEFT JOIN
(SELECT c.Category, COUNT(*) as num_comments
FROM (SELECT DISTINCT c.Category, co.CommentId
FROM (tbl_Category as c INNER JOIN
tbl_Activity as a
ON c.CategoryID = a.CategoryID
) INNER JOIN
tbl_Comments as co
ON a.ActivityID = co.ActivityID
WHERE a.UnitID = 5 AND co.PeriodID = 1
) as aco
GROUP BY c.Category
) as aco
ON aco.CommentId = ac.CommentId
Note that your LEFT JOINs are superfluous because the WHERE clause turns them into INNER JOINs. This adjusts the logic for that purpose. The filtering is also very tricky, because it uses both tables, requiring that both subqueries have both JOINs.
You can use DISTINCT:
SELECT
tbl_Category.Category, Count(DISTINCT tbl_Activity.ActivityID) AS CountOfActivityID,
Count(DISTINCT tbl_Comments.CommentID) AS CountOfCommentID
FROM tbl_Category LEFT JOIN
(tbl_Activity LEFT JOIN tbl_Comments ON
tbl_Activity.ActivityID = tbl_Comments.ActivityID) ON
tbl_Category.CategoryID = tbl_Activity.CategoryID
WHERE
(((tbl_Activity.UnitID)=5) AND ((tbl_Comments.PeriodID)=1))
GROUP BY
tbl_Category.Category;

Can this subquery be written as a join and still get the same result set/number of rows?

How do I write the below as a join and get the same number of rows?
SELECT
s.subjectid,
s.subjectname,
(SELECT
COUNT(*)
FROM dbo.Classes AS c
WHERE c.SubjectID = s.SubjectID
AND c.MondaySchedule = 1)
AS numofclasses
FROM dbo.subjects AS s
ORDER BY numofclasses DESC
I am trying to write it like below but getting a different answer:
SELECT
s.subjectid,
COUNT(ClassID) AS numberofclasses
FROM dbo.subjects AS s
LEFT JOIN dbo.classes AS c
ON s.SubjectID = c.SubjectID
WHERE c.MondaySchedule = 1
GROUP BY s.Subjectid
ORDER BY numberofclasses DESC
Move the where condition to the on condition. It is converting the outer join to an inner join:
select s.subjectid, count(ClassID) as numberofclasses
from dbo.subjects s left join
dbo.classes c
on s.SubjectID = c.SubjectID and c.MondaySchedule = 1
group by s.Subjectid
order by numberofclasses desc ;
This does assume that subjects(subjectid) is unique (or a primary key). If not, the two might return different results.

Limitting results in association

I want to limit the results in a lateral join, so that it only returns the N most recent matches.
This is my query, but the limit inside the join does not seem to work, as it returns all visitors
select am.id, am.title, ame.event, array_agg(row_to_json(visitors))
from auto_messages am
left join apps a on am.app_id = a.id
left join app_users au on a.id = au.app_id
left join auto_message_events ame on ame.auto_message_id = am.id
left join lateral (
select
id,
name,
avatar,
ame.inserted_at
from visitors v
where v.id = ame.visitor_id
order by ame.inserted_at desc
limit 1
) as visitors on visitors.id = ame.visitor_id
where am.id = '100'
group by am.id, ame.event
I am pretty sure the problem is with ame. That is where the rows are generated. The join to visitors is only picking up additional information.
So, this might solve your problem:
select am.id, am.title, visitors.event, array_agg(row_to_json(visitors))
from auto_messages am left join
apps a
on am.app_id = a.id left join
app_users au
on a.id = au.app_id left join lateral
(select v.id, v.name, v.avatar,
ame.event, ame.inserted_at, ame.auto_message_id
from auto_message_events ame join
visitors v
on v.id = ame.visitor_id
order by ame.inserted_at desc
limit 1
) visitors
on visitors.auto_message_id = am.id
where am.id = '100'
group by am.id, visitors.event;
You also might want to change your select clause, if you only want a subset of columns.

Postgresql distinct issue

It needs receiving unique profiles ordered by creation_date. There is following query:
SELECT DISTINCT profiles.id, COALESCE(occured_at, users_visitors.created_at, visitors.created_at) creation_date FROM "profiles"
JOIN "visitors" ON "visitors"."profile_id" = "profiles"."id"
LEFT JOIN events ON profiles.id = events.profile_id
LEFT JOIN event_kinds ON event_kinds.id = events.event_kind_id
LEFT JOIN users_visitors ON visitors.id = users_visitors.visitor_id
WHERE (event_kinds.name = 'enter') AND "users_visitors"."user_id" = 2
ORDER BY creation_date asc
DISTINCT ON (profiles.id) won't help once it should be used for ordering. GROUP BY profiles.id, ... doesn't work as well.
Could you help me, please?
Does this GROUP BY work? Or which creation_date do you want - if not the max one?
SELECT profiles.id,
MAX(COALESCE(occured_at,
users_visitors.created_at,
visitors.created_at)) creation_date
FROM "profiles"
JOIN "visitors" ON "visitors"."profile_id" = "profiles"."id"
LEFT JOIN events ON profiles.id = events.profile_id
LEFT JOIN event_kinds ON event_kinds.id = events.event_kind_id
AND event_kinds.name = 'enter'
LEFT JOIN users_visitors ON visitors.id = users_visitors.visitor_id
AND "users_visitors"."user_id" = 2
GROUP BY profiles.id
ORDER BY creation_date asc
Note how I've moved the where clause conditions to get the LEFT JOIN's to perform as LEFT JOIN's.

Left Join, Order by, MySQL Optimization

I have a query like this:
SELECT m...., a...., r....
FROM 0_member AS m
LEFT JOIN 0_area AS a ON a.user_id = (SELECT user_id
FROM `0_area`
WHERE user_id = m.id
ORDER BY sec_id ASC LIMIT 1)
LEFT JOIN 0_rank as r ON a.rank_id = r.id
WHERE m.login_userid = '$username'
The idea is to get the first row from 0_area table and hence the attempted inner join. However, it is not working as expected.
Between 0_area and 0_member, 0_member.id = 0_area.user_id. However, there are multiple rows of 0_area.user_id and I want the row having the lowest value of sec_id.
Any help please?
SELECT m...., a...., r....
FROM 0_member AS m
LEFT JOIN (SELECT user_id, min(sec_id) minsec
FROM `0_area`
GROUP BY user_id) g1 on g1.user_id=m.id
LEFT JOIN 0_area AS a ON a.user_id = g1.user_id and a.sec_id=minsec
LEFT JOIN 0_rank as r ON a.rank_id = r.id
WHERE m.login_userid = '$username'