Merge two MySQL queries working fine separately - php

SELECT sum(monthly_target) as month_target
FROM `tbl_goal`
inner join user
on tbl_goal.uid=user.id where user.store=1 and month='February'
result: month_target = 9000
SELECT
sum(net) as achieved,
sum(hairs_total) as hairs_total,
sum(beard_total) as beard_total,
sum(product_total) as product_total
FROM `data`
inner join user
on data.uid=user.id where user.store=1 and month='February'
result: achieved =103 hairs_total =63 beard_total = 40 product_total = 0
please give me any hint how can join these into one?

Tricky one. Your current join condition implies that you want to aggregate by user, but the WHERE clause makes it clear that you want store-level aggregates. So, we can try rewriting your query to aggregate by store. Each of the two subqueries below performs separate aggregations, bringing in the store id via a join to the user table. Then, on the outside we join the user table to each of these subqueries.
SELECT
u.store,
COALESCE(t1.achieved, 0) AS achieved,
COALESCE(t1.hairs_total, 0) AS hairs_total,
COALESCE(t1.beard_total, 0) AS beard_total,
COALESCE(t1.product_total, 0) AS product_total,
COALESCE(t2.month_target 0) AS month_target
FROM user u
LEFT JOIN
(
SELECT
usr.store,
SUM(d.net) AS achieved,
SUM(d.hairs_total) AS hairs_total,
SUM(d.beard_total) AS beard_total,
SUM(d.product_total) AS product_total
FROM data d
INNER JOIN user usr
ON d.uid = usr.id
WHERE d.month = 'February'
GROUP BY usr.store
) t1
ON u.store = t1.store
LEFT JOIN
(
SELECT
usr.store,
SUM(t.monthly_target) AS month_target
FROM tbl_goal t
INNER JOIN user usr
ON t.uid = usr.id
WHERE t.month = 'February'
GROUP BY usr.store
) t2
ON u.store = t2.store;
WHERE
u.store = 1;
If you wanted a report of all stores, just remove the outer WHERE clause.

Use multiple inner join to achieve this .
Try this
SELECT sum(tbl_goal.monthly_target) as month_target, sum(data.net) as achieved,
sum(data.hairs_total) as hairs_total,
sum(data.beard_total) as beard_total,
sum(data.product_total) as product_total
FROM `tbl_goal`
inner join user
on tbl_goal.uid=user.id
inner join data on tbl_goal.uid=data.uid
where user.store=1 and data.month='February'

SELECT
sum(monthly_target) as month_target,
sum(net) as achieved,
sum(hairs_total) as hairs_total,
sum(beard_total) as beard_total,
sum(product_total) as product_total
FROM
user
inner join `tbl_goal` on tbl_goal.uid = user.id
inner join `data` on data.uid = user.id
where
user.store = 1
and month = 'February'

Related

How to perform inner join in mysql

I have to write a query such that ,I need to get events whose start date is of 30 min from now.
My conditions are:
1) get the event from events table
2)Join created by of events with id in users table.
3)Comments from comment table with user ser id
But the problem here is if there is no comment for event then the event it self is not coming.If any comment is present it is coming.I dont want this.If comment is not there just fetch it as empty but not hide the total event .Can anyone please help me,.Thanks.
select u.email ,group_members.user_id,users.first_name,u.first_name
as host_name,events.name,events.start_date,comments.comments,c.first_name as
comment_user,comments.id from events
inner join users as u on u.id = events.created_by
inner join comments on events.id = comments.event_id
inner join group_members on events.group_id = group_members.group_id
inner join users as c on comments.from_user = c.id
inner join users on group_members.user_id = users.id
where events.start_date between date_add(now(),interval 1 minute) and date_add(
now(),interval 30 minute)
and group_members.user_status = 2
and events.status = 2
You need a left join to the comments table. I would put that table last in the from clause.
select u.email, gm.user_id, gu.first_name, u.first_name as host_name,
e.name, e.start_date, c.comments, uc.first_name as comment_user,
c.id
from events e inner join
users u
on u.id = e.created_by inner join
group_members gm
on e.events.group_id = gm.group_id inner join
users gu
on gm.user_id = gu.id left join
comments c
on e.id = c.event_id left join
users uc
on c.from_user = uc.id
where e.start_date between date_add(now(),interval 1 minute) and date_add(now(),interval 30 minute) and
gm.user_status = 2 and
e.status = 2;
Once you use a left join on comments, you also need a left join for the from user. I replaced all table names with aliases -- this makes it easier to track which table is used for which purpose.
Use the INNER JOIN Keyword and select the two columns by putting them with keyword ON.
SELECT EMP.EMP_ID, EMP.EMP_NAME, DEPT.DEPT_NAME FROM EMP
INNER JOIN DEPT ON DEPT.DEPT_ID = EMP.DEPT_ID;

Trying to JOIN an empty table nothing returns

I have a problem trying to JOIN an empty table (comments table) to my existing prepared statement.
This is working perfectly:
// prepare images
if ($stmt = $mysqli->prepare(" SELECT uu.*, m.*,
(
SELECT COUNT(*)
FROM img_likes AS t
WHERE t.img_id = uu.imgID AND t.user_id = ?
) AS user_likes,
(
SELECT COUNT(*)
FROM img_likes AS t
WHERE t.img_id = uu.imgID
) AS total_likes
FROM user_uploads AS uu
INNER JOIN members AS m ON m.id = uu.user_id
ORDER BY up_time DESC")) {
$stmt->bind_param('i', $user_id);
$stmt->execute(); // get imgs
// foreach print images
// working as expected
}
And I don't know why if I JOIN another table (img_comments) that is empty, the images are not printed... if I add a row to the table and refresh the page, one image is printed...
The statement that I'm trying and it's not working is this:
SELECT uu.*, m.*, ic.*,
(
SELECT COUNT(*)
FROM img_likes AS t
WHERE t.img_id = uu.imgID AND t.user_id = ?
) AS user_likes,
(
SELECT COUNT(*)
FROM img_likes AS t
WHERE t.img_id = uu.imgID
) AS total_likes
FROM user_uploads AS uu
INNER JOIN members AS m ON m.id = uu.user_id
INNER JOIN img_comments AS ic ON ic.img_id = uu.imgID
ORDER BY up_time DESC
Why is only printing images based on the number of the table rows?? I also tried LEFT JOIN but I'm not too familiareize with this. I only use INNER JOIN in other scripts and I never had a problem like this.
I would appreciate any optimization to my query.
What does an inner join do? It joins all records of table a with all matching records of table b. So when there are no records in table b, there is no match for any record of table a, hence no result at all. Why does this surprise you?
A left join is an outer join (short for LEFT OUTER JOIN). It means: Give me all records of table a with all matching records of table b, and when there is no match then give me the record of table a anyhow. This seems to be what you are wanting here. But you say you tried it. I don't see how this would fail in your query.
A typical error for an outer join not to work would be to have some field of b in your where clause (e.g. where b.id > 100). As the outer-joined records have no matching b record, all b fields are null, so that such a where clause would fail. You'd just get matches again, just like with the inner join.
EDIT: As to optimization, you can get the two counts in one pass by counting conditionally:
SELECT
uu.*, m.*, ic.*,
il.count_user AS user_likes,
il.count_total AS total_likes
FROM user_uploads AS uu
INNER JOIN members AS m ON m.id = uu.user_id
LEFT OUTER JOIN img_comments AS ic ON ic.img_id = uu.imgID
LEFT OUTER JOIN
(
select
img_id,
count(*) as count_total,
count(case when t.user_id = ? then 1 end) as count_user
from img_likes
group by img_id
) AS il ON il.img_id = uu.imgID
ORDER BY uu.up_time DESC;
As far as I know, INNER JOIN will only retrieve data which have both data. So if let say the table that you join have no data with that join condition. It will not return any data at all.
LEFT JOIN is just a normal join. It will retrieve data on both table. But if the joined table is empty, then only the primary table will have data, the secondary table will have null as its data.
You can just modify your code, replacing INNER JOIN with LEFT JOIN and see if it works/

select count of rows from 2 tables and merge into one row (mysqli)

i create a web app like facebook by php and mysqli
in my app i have a table for posts , one table for likes , and one table for comments
i want to get the number of comments and likes of each post in one row with his post_id!!!
i try some querys likes this :
select `tblpost`.`post_id`, COALESCE(TCOMM.`comment_num`,0) as `c_num`, COALESCE(TLIKE.`like_num`,0) as `l_num`
from
(select `tblpost`.`post_id`, count(*) as `like_num` from `tblpost` join `tbllikes` on `tbllikes`.`post_id` = `tblpost`.`post_id` group by `tblpost`.`post_id`
) TLIKE
inner join
(select `tblpost`.`post_id`, count(*) as `comment_num` from `tblpost` join `tblcomments` on `tblcomments`.`post_id` = `tblpost`.`post_id` group by `tblpost`.`post_id`) TCOMM
on
TCOMM.`post_id` = TLIKE.`post_id`
but i don't know what's my problem
You can do count distincts with two left joins.
Something like this would work if there are fields like_id and comment_id in the tables tbllikes and tblcomments
SELECT
tblpost.post_id AS post_id,
COUNT(DISTINCT tbllikes.like_id) AS likes,
COUNT(DiSTINCT tblcomments.comment_id) AS comments
FROM tblpost
LEFT JOIN tbllikes ON tbllikes.post_id = tblpost.post_id
LEFT JOIN tblcomments on tblcomments.post_id = tblpost.post_id
GROUP BY tblpost.post_id
First, I think you can greatly simplify your query:
select l.post_id,
COALESCE(c.comment_num, 0) as c_num, COALESCE(l.like_num, 0) as l_num
from (select l.post_id, count(*) as like_num
from tbllikes l
group by l.post_id
) l inner join
(select c.post_id, count(*) as comment_num
from tblcomments c
group by c.post_id
) c
on l.post_id = c.post_id;
This will only get you posts that have both likes and comments. To get what you want, use a left join:
select p.post_id,
COALESCE(c.comment_num, 0) as c_num, COALESCE(l.like_num, 0) as l_num
from tblpost p left join
(select l.post_id, count(*) as like_num
from tbllikes l
group by l.post_id
) l
on l.post_id = p.post_id left join
(select c.post_id, count(*) as comment_num
from tblcomments c
group by c.post_id
) c
on c.post_id = p.post_id;

return a total count of counts in prepared statement

The following statement gets row counts for user_ids from various tables/conditions where the users are within specific computers of a specific account. It works as expected. An example output would be something like this :
Array
(
[0] => Array
(
[computer_name] => COMPUTER_1
[username] => Steve
[t1count] => 13
[t2count] =>
[t3count] => 23
[t4count] => 64
)
... and so on for each
the statement :
$stmt = $db->prepare("
SELECT c.computer_name, users.username, t1count, t2count, t3count, t4count
FROM
( SELECT account_id, computer_id, computer_name
FROM computers
WHERE account_id = ".$_SESSION['user']['account_id']."
ORDER BY computer_id ASC LIMIT 0, ".$_SESSION['user']['licenses']."
) as c
LEFT JOIN users
on users.computer_id = c.computer_id
LEFT JOIN
(SELECT user_id, COUNT(user_id) as t1count
FROM t1
WHERE t1.title LIKE 'started'
GROUP BY user_id) as t_t1
on t_t1.user_id = users.user_id
LEFT JOIN
(SELECT user_id, COUNT(user_id) as t2count
FROM t2
GROUP BY user_id) as t_t2
on t_t2.user_id = users.user_id
LEFT JOIN
(SELECT user_id, COUNT(user_id) as t3count
FROM t1
WHERE t1.title LIKE 'blocked'
GROUP BY user_id) as t_t3
on t_t3.user_id = users.user_id
LEFT JOIN
(SELECT user_id, COUNT(user_id) as t4count
FROM t1
WHERE t1.title LIKE 'closed'
GROUP BY user_id) as t_t4
on t_t4.user_id = users.user_id
... and so on for each
WHERE c.account_id = ?
");
I want to also return a totalsum = t1count + t2count + t3count + t4count in this statement as well, but can't seem to get anything working. In this situation I cannot do outside processing (adding the values that are returned)... it needs to be in the statement. I am also open to any suggestions in what I already have if there are better options.
What are you trying to do with these values? SUM(t1count,t2count,t3count,t4count) AS totalsum should work to get a count of counts.
Your query is a bit hard to read. You have implicit and explicit JOINs. You are grouping numerous times and pulling columns when you can generally do this all in one shot. If you share an SQLFiddle, I will be able to clean this up, but in short:
SELECT
c.computer_name,
users.username,
count(t_t1.user_id) AS t1count,
count(t_t2.user_id) AS t2count,
count(t_t3.user_id) AS t3count,
count(t_t4.user_id) AS t4count,
(count(t_t1.user_id)+count(t_t2.user_id)+count(t_t3.user_id)+count(t_t4.user_id)) AS totalsum FROM users
LEFT JOIN computers AS c ON users.computer_id=c.computer_id AND c.account_id=?
LEFT JOIN t1 AS t_t1 ON t_t1.user_id = users.user_id AND t_t1.title LIKE "started"
LEFT JOIN t2 AS t_t2 ON t_t2.user_id = users.user_id
LEFT JOIN t1 AS t_t3 ON t_t3.user_id = users.user_id AND t_t3.title LIKE 'blocked'
LEFT JOIN t1 AS t_t4 ON t_t4.user_id = users.user_id AND t_t4.title LIKE 'closed'
WHERE c.account_id = ?
AND t_t1.title LIKE started
GROUP BY users.user_id;
This may need tweaking, as I stated, but it is a lot cleaner and easier to read and should accomplish something very similar.
Alternately, if you can't get the query to run the way you want it to when you change it to entirely explicit joins, rather than using SUM, try adding the values together like I did in the example above. It should prevent them from aggregating in the same way.
EDIT
After viewing your SQLFiddle, I have doctored up a solution which does away with nested queries. The positive is that it is cleaner. The negative is that it requires you to specify the users using an IN clause.
SELECT computers.account_id,computers.computer_id,computers.computer_name,users.user_id,users.username,count(distinct t_count1.log_id) AS count1,count(distinct t_count2.log_id) AS count2,count(distinct t_count3.log_id) AS count3, count(distinct t_count4.event_id) AS count4,
(count(distinct t_count1.log_id) + count(distinct t_count2.log_id) + count(distinct t_count3.log_id) + count(distinct t_count4.event_id)) AS totalcount
FROM users
INNER JOIN computers ON computers.computer_id=users.computer_id
LEFT JOIN logs AS t_count1 ON t_count1.type LIKE 'type1' AND t_count1.user_id=users.user_id
LEFT JOIN logs AS t_count2 ON t_count2.type LIKE 'type2' AND t_count2.user_id=users.user_id
LEFT JOIN logs AS t_count3 ON t_count3.type LIKE 'type3' AND t_count3.user_id=users.user_id
LEFT JOIN events AS t_count4 ON t_count4.user_id = users.user_id
WHERE computers.account_id=1 AND computers.computer_id in (1,2)
GROUP BY users.user_id
ORDER BY users.user_id ASC,computers.computer_id ASC;
If you choose to keep your current query structure for any reason, adapting it like so should make it work for you:
select *,ifnull(count1,0)+ifnull(count2,0)+ifnull(count3,0)+ifnull(count4,0) AS totalcount from
( select account_id, computer_id, computer_name
from computers
order by computer_id asc limit 0, 2
) as c
left join users
on users.computer_id = c.computer_id
left join
(select user_id, count(user_id) as count1
from logs
where logs.type like 'type1'
group by user_id) as t_count1
on t_count1.user_id = users.user_id
left join
(select user_id, ifnull(count(user_id),0) as count2
from logs
where logs.type like 'type2'
group by user_id) as t_count2
on t_count2.user_id = users.user_id
left join
(select user_id, count(user_id) as count3
from logs
where logs.type like 'type3'
group by user_id) as t_count3
on t_count3.user_id = users.user_id
left join
(select user_id, count(user_id) as count4
from events
group by user_id) as t_count4
on t_count4.user_id = users.user_id
where c.account_id = 1;
My advice would be to follow along each query to understand what you are asking SQL to do. To actually add all values together, you should be counting the number of records that are returned. Counting values of your primary keys helps you to count records. Also, using your other example, ifnull in the second example make sure that null values are not going to interfere with adding. "If a value is null make it 0 instead."

MySQL Query left join repeated records

With a Left Join i have this result.
Here the screen
http://f.cl.ly/items/373Y141r1K131d0n3f1q/Schermata%202013-04-01%20alle%2016.51.18.png
i want to show only record once time, without repeat it, but with a left join all my records are different.
what i have to do for show once all my records?
the query.
SELECT * FROM login_users
LEFT JOIN login_users_seguaci
ON login_users.user_id = login_users_seguaci.following
WHERE name LIKE ""
AND user_id != '1'
ORDER BY data DESC
SELECT x.*, y.*
FROM login_users x
LEFT JOIN
(
SELECT a.*
FROM login_users_seguaci a
INNER JOIN
(
SELECT following, MAX(DATA) max_data
FROM login_users_seguaci
GROUP BY following
) b ON a.following = b.following AND
a.DATA = b.max_date
) y ON x.user_id = y.following
// WHERE ... your condition here ...
ORDER BY t.data DESC

Categories