mysql count table rows with count child tables rows - mysql

I have three tables. a>b>c tables. I want to totals separately each other and optimize query. My query is not giving the true counts.
TABLE: a
a
-----------
id
no
create_time
TABLE: b
b
-----------
id
no
TABLE: c
c
-----------
id
b_id
this query is not giving the true counts
SELECT
DATE( a.create_time ) AS date,
COUNT( a.id ) AS total_a,
COUNT( b.id ) AS total_b,
COUNT( c.id ) AS total_c
FROM
`a`
LEFT JOIN `b` ON `a`.`no` = `b`.`no`
LEFT JOIN `c` ON `b`.`id` = `c`.`b_id`
WHERE
( `a`.`status` = 1 )
GROUP BY
DATE( a.create_time )
ORDER BY
`date` DESC
LIMIT 20

A left join repeats each row on the left hand side for each matching row on the right hand side. So you get more rows than in the original.
An easy fix is to count just the unique identifiers:
SELECT
DATE( a.create_time ) AS date,
COUNT( DISTINCT a.id ) AS total_a,
COUNT( DISTINCT b.id ) AS total_b,
COUNT( DISTINCT c.id ) AS total_c

Related

Joining two columns in mysql

I want to add data from table b in table a but unfortunately full outer join do not work in mysql . I have also tried union but it is throwing errors because my statement has group by and order by keyword
SELECT COUNT( ReviewedBy ) AS TotalReviews, OrganizationId, SUM( Rating ) AS TotalStars, COUNT( Rating ) AS TotalRatings, (
SUM( Rating ) / COUNT( Rating )
) AS AverageRating
FROM `tbl_reviews`
WHERE ReviewType = 'shopper'
AND ReviewFor = 'org'
AND OrganizationId
IN (
SELECT OrganizationId
FROM tbl_organizations
WHERE CategoryID =79
)
GROUP BY OrganizationId
ORDER BY AverageRating DESC
This is what i'm getting from the above statement
I want to get organizationId 21 data in the result but i'm not getting result because it's not present in 'tbl_review' table
click here to see the table b
How can i get Desired result ?
You don't need a FULL, but a LEFT join:
SELECT COUNT( ReviewedBy ) AS TotalReviews, o.OrganizationId,
SUM( Rating ) AS TotalStars, COUNT( Rating ) AS TotalRatings,
(SUM( Rating ) / COUNT( Rating )) AS AverageRating
FROM tbl_organizations AS o
LEFT JOIN `tbl_reviews` AS r
ON o.OrganizationId = r.OrganizationId
AND ReviewType = 'shopper' -- conditions on inner table
AND ReviewFor = 'org' -- must be moved to ON
WHERE CategoryID =79
GROUP BY o.OrganizationId
ORDER BY AverageRating DESC
Why don't you use AVG instead of SUM/COUNT?
Have you tried:
from organization
left outer join tbl_reviews
on organization.ID = tbl_reviews.organization is
for your where clause? I don't think you need a full outer join in this case... A left outer join should do

MySQL SELECT subquery

I have a calendar and user_result table and I need to join these two queries.
calendar query
SELECT `week`, `date`, `time`, COUNT(*) as count
FROM `calendar`
WHERE `week` = 1
GROUP BY `date`
ORDER BY `date` DESC
and the result is
{"week":"1","date":"2014-08-21","time":"15:30:00","count":"4"}, {"week":"1","date":"2014-08-20","time":"17:30:00","count":"12"}
user_result query
SELECT `date`, SUM(`point`) as score
FROM `user_result`
WHERE `user_id` = 1
AND `date` = '2014-08-20'
and the result is just score 3
My goal is to always show calendar even if the user isn't present in the user_result table, but if he is, SUM his points for that day where calendar.date = user_result.date. Result should be:
{"week":"1","date":"2014-08-21","time":"15:30:00","count":"4","score":"3"}, {"week":"1","date":"2014-08-20","time":"17:30:00","count":"12","score":"0"}
I have tried this query below, but the result is just one row and unexpected count
SELECT c.`week`, c.`date`, c.`time`, COUNT(*) as count, SUM(p.`point`) as score
FROM `calendar` c
INNER JOIN `user_result` p ON c.`date` = p.`date`
WHERE c.`week` = 1
AND p.`user_id` = 1
GROUP BY c.`date`
ORDER BY c.`date` DESC
{"week":"1","date":"2014-08-20","time":"17:30:00","count":"4","score":"9"}
SQL Fiddle
ow sorry, i was edited, and i was try at your sqlfiddle, if you want to show all date from calendar you can use LEFT JOIN, but if you want to show just the same date between calendar and result you can use INNER JOIN, note: in this case INNER JOIN just show 1 result, and LEFT JOIN show 2 results
SELECT c.`week`, p.user_id, c.`date`, c.`time`, COUNT(*) as count, p.score
FROM `calendar` c
LEFT JOIN
(
SELECT `date`, SUM(`point`) score, user_id
FROM `result`
group by `date`
) p ON c.`date` = p.`date`
WHERE c.`week` = 1
GROUP BY c.`date`
ORDER BY c.`date` DESC
I put a pre-aggreate query / group by date as a select for the one person you were interested in... then did a left-join to it. Also, your column names of week, date and time (IMO) are poor choice column names as they can appear to be too close to reserved keywords in MySQL. They are not, but could be confusing..
SELECT
c.week,
c.date,
c.time,
coalesce( OnePerson.PointEntries, 0 ) as count,
coalesce( OnePerson.totPoints, 0 ) as score
FROM
calendar c
LEFT JOIN ( select
r.week,
r.date,
COUNT(*) as PointEntries,
SUM( r.point ) as totPoints
from
result r
where
r.week = 1
AND r.user_id = 1
group by
r.week,
r.date ) OnePerson
ON c.week = OnePerson.week
AND c.date = OnePerson.date
WHERE
c.week = 1
GROUP BY
c.date
ORDER BY
c.date DESC
Posted code to SQLFiddle

getting data from multiple tables in mysql

My goal is to get from the following tables - the user's unique group names and ids, the latest comments for the user's groups, the latest "done" article for the user's groups, the SUM of done articles, and total articles. Basically what is presented in the bottom sheet.
So far I've managed to get the data from the groups table and from the articles, but I can't get the latest comment.
Here is my query
SELECT `groups`.`name` , `groups`.`id` , (
SELECT MAX( `articles`.`written` )
FROM `articles`
WHERE `group` = `groups`.`id`
AND `articles`.`done` = '1'
) AS latestArt, (
SELECT MAX( `comments`.`date_added` )
FROM `comments`
WHERE `comments`.`article_id` = `a`.`id`
AND `comments`.`active` = '1'
) AS latestComm, SUM( `a`.`done` = '1' ) articlesAchieved, COUNT( `a`.`id` ) AS totalArticles
FROM `groups`
LEFT JOIN `articles` AS `a` ON `a`.`group` = `groups`.`id`
LEFT JOIN `comments` AS `c` ON `c`.`note_id` = `a`.`id`
WHERE `groups`.`user_id` = '6'
AND `n`.`active` = '1'
GROUP BY `groups`.`id`
I've also tried to get the data by joining everything to the article table but I wasn't successful with that either :(
UPDATED Your query might look like this
SELECT g.id group_id, g.name group_name,
a.last_written, a.total_articles, a.total_done,
c.last_comment
FROM groups g LEFT JOIN
(
SELECT `group`,
MAX(CASE WHEN done = 1 THEN written END) last_written,
COUNT(*) total_articles,
SUM(done) total_done
FROM articles
WHERE active = 1
AND user_id = 1
GROUP BY `group`
) a
ON g.id = a.`group` LEFT JOIN
(
SELECT a.`group`,
MAX(date_added) last_comment
FROM commants c JOIN articles a
ON c.article_id = a.id
WHERE a.active = 1
AND a.user_id = 1
GROUP BY a.`group`
) c
ON g.id = c.`group`
WHERE user_id = 1

MySQL: SELECT if non of group by members is equal to x

I have troubles getting proper data.
I have table structure like:
id INT(11) AI
order_id INT(11)
status varchar(45)
This table log status changes for orders.
So order_id's will have few statuses.
Now I need to select rows and group them by order_id, where order never had status (not even one status with given order_id) != 'example'
We don't show orders, where one of members had status = example
Sample data
1 12 ready
1 12 example
2 13 ready
2 13 sent
So I don't want order 12 to show at all, because one of it members have "example" status
I've tried grouping results, but it's not enough.
you can do it by simple join query :
select a.order_id
from ordrstatus as a left outer join (select orderid , count(*) as status from orderstatus where status = 'example' group by orderid) as b on a.orderid = b.orderid
where b.status = 0 or b.status is NUll
Join query always run faster then IN query . by using Join in query it will run only one time .
You can try like this...it will return all order id which never had status -example
Select
Order_id,
from TableName A where Not Exists(
Select id from TableName B where
status='example' and
a.Order_id=b.Order_id
)
group by Order_id
Not quite sure if you want the records for order which have had a status of example, or ones which have never had a status of example
To get a list of orders (with the status grouped up) which have had a status of example:-
SELECT a.order_id, GROUP_CONCAT(a.status)
FROM SomeTable a
INNER JOIN
(
SELECT order_id, COUNT(*)
FROM SomeTable
WHERE status = 'example'
GROUP BY order_id
) b
ON a.order_id = b.order_id
GROUP BY order_id
To get those which have NEVER had a status of exmaple
SELECT a.order_id, GROUP_CONCAT(a.status)
FROM SomeTable a
LEFT OUTER JOIN
(
SELECT order_id, COUNT(*)
FROM SomeTable
WHERE status = 'example'
GROUP BY order_id
) b
ON a.order_id = b.order_id
WHERE b.order_id IS NULL
GROUP BY order_id
EDIT
SELECT a.order_id, GROUP_CONCAT(a.status)
FROM SomeTable a -- Statuses
LEFT OUTER JOIN
(
SELECT order_id, COUNT(*)
FROM SomeTable
WHERE status = 'example'
GROUP BY order_id
) b -- Get any order id which has had a status of example (as a LEFT JOIN)
ON a.order_id = b.order_id
INNER JOIN
(
SELECT order_id, MAX(id) AS Latestid
FROM SomeTable
GROUP BY order_id
) c -- Get the latest status for each order (ie, max id)
ON a.order_id = c.order_id
LEFT OUTER JOIN
(
SELECT order_id, id
FROM SomeTable
WHERE status = 'example2'
) d -- Get the id of the order status of example2
ON a.order_id = d.order_id AND c.Latestid = d.id -- join on the same order id and that the record id matches the latest record id
WHERE b.order_id IS NULL -- reject those where a match was found on example for any status
AND d.order_id IS NULL -- reject those where a match was found on example2 for the latest status
GROUP BY order_id
try this
SELECT Order_ID FROM tbl_Orders
WHERE Status NOT IN ('example')
GROUP BY Order_ID
SELECT DISTINCT x.order_id
FROM order_status x
LEFT
JOIN order_status y
ON y.order_id = x.order_id
AND y.status = 'example'
WHERE y.id IS NULL;

GROUP_CONCAT multiple values from table

I just added a table which holds a url and description for each item in place. The below query works ok ... but it's only returning the url and I need the desc also. I m not sure how to make this work.
$query_str = "SELECT a.userid, a.cat, a.id, a.name, a.image,
a.desc, a.country, b.user_id, c.username,
c.fbook, d.cat_id,
(
SELECT GROUP_CONCAT(url)
FROM one_add o
WHERE a.id=o.one_id
) AS url,
(
SELECT COUNT(id)
FROM one_msg m
WHERE m.guest_id = ? AND
m.one_id=a.id
) AS count
FROM place a
LEFT OUTER JOIN wait b
ON a.id=b.post_id AND
b.user_id= ?
JOIN users c
ON a.userid=c.id
LEFT JOIN (
SELECT userid, user_id,
GROUP_CONCAT( cat_id ) AS cat_id
FROM user_cat
WHERE userid='$user_id'
GROUP BY user_id
) AS d ON d.userid='$user_id' AND
d.user_id=a.userid
WHERE a.cat != ? ORDER BY a.date desc";
This is what I want to accomplish: desc
You can achibe this by using CONCAT inside GROUP_CONCAT function as:
(SELECT GROUP_CONCAT(CONCAT('',desc,''))
FROM one_add o
WHERE a.id=o.one_id) AS url
full query:
(SELECT COUNT(id) FROM one_msg m WHERE m.guest_id = ? AND m.one_id=a.id ) AS count
FROM place a
LEFT OUTER JOIN wait b ON a.id=b.post_id AND b.user_id= ?
JOIN users c ON a.userid=c.id
LEFT JOIN ( SELECT userid, user_id, GROUP_CONCAT( cat_id ) AS cat_id FROM user_cat WHERE userid='$user_id' GROUP BY user_id ) AS d ON d.userid='$user_id' AND d.user_id=a.userid
WHERE a.cat != ? ORDER BY a.date desc";