How can I get data from 3 tables? - php

I have 3 tables: 'news', 'comments' and 'rub'. I need to get all data from 'news', get 'title' from 'rub' and count the number of comments for every news.
Now I'm not able to get 'title' from 'rub'. The code below works:
SELECT n.id,n.header,n.text, COUNT(c.news_id) AS comments
FROM news n
LEFT JOIN comments c ON n.id = c.news_id
GROUP BY n.id
ORDER by n.id
LIMIT 30
But I need something like that and this code doesn't work (Call to a member function fetch_array() on a non-object):
SELECT n.id,n.header,n.text,r.title COUNT(c.news_id) AS comments
FROM news n,rub r
LEFT JOIN comments c ON n.id = c.new_id AND r.news_id=n.id
GROUP BY n.id ORDER by n.id
LIMIT 30
How to fix it?

It's not really clear to me what you are asking, but you need another JOIN. And you need to move the join condition for the rub table to that JOIN keyword, not into the join condition for the comments table
SELECT n.id,
n.header,
n.text,
r.title, -- comma was missing (as halfer mentioned)
COUNT(c.news_id) AS comments
FROM news n
JOIN rub r ON r.news_id=n.id --- this is missing
LEFT JOIN comments c ON n.id = c.new_id -- no join condition for rub/news here
GROUP BY n.id
ORDER by n.id
LIMIT 30
Your usage of the GROUP BY operator is also wrong. The above query will (rightfully) be rejected by all other DBMS.
Please read the following to understand why your GROUP BY is wrong:
http://www.mysqlperformanceblog.com/2006/09/06/wrong-group-by-makes-your-queries-fragile/
http://rpbouman.blogspot.de/2007/05/debunking-group-by-myths.html

Related

is there a way of joining two tables with the clause, "inner join," then followed by multiple "left join" clause

i'm setting up mysql query against four table, i want the result of the left not to have effect on the query of the inner join. what am i do wrong? forgive my naivety
the problem here is that when i remove the two left join in the query i get eight results as expected but with the left join in the query i get only one result even when there're more products in the product table.
$this->getAllRecords("SELECT t.content_type_name as type,
p.title,p.start_date, p.end_date, p.last_enroll_date,
p.seat, p.cost, p.description, COUNT(r.stars) as review_count,
AVG(r.stars) as stars, i.image, p.location
FROM content_type t
INNER JOIN product p ON t.content_type_id=c.content_type_id
LEFT JOIN product_review r ON p.product_id=r.product_id
LEFT JOIN image i ON p.uid=i.reference_page_or_product
AND p.active=1
ORDER BY RAND()
LIMIT 8"))
i want all product whether there are reviews and image or not
You are using aggreation function withou group by and this could produce unpredictable result (probaly you are using a mysql db version preceding 5.7)
The aggredated result could be related to null value and this also can reduce/omit the result
You should use group by for aggreation function and use a subquery for obtain the related valid result .. and use the subqiery for left join
SELECT t.content_type_name as type
, p.title,p.start_date
, p.end_date
, p.last_enroll_date
, p.seat
, p.cost
, p.description
, p.location
, i.image
, t.review_count
, t.stars
FROM content_type t
INNER JOIN product p ON t.content_type_id=c.content_type_id
AND p.active=1
LEFT JOIN (
SELECT r.product_id
, COUNT(r.stars) as review_count
, AVG(r.stars) as stars
FROM product_review r
GROUP BY r.product_id
) t ON ON p.product_id=t.product_id
LEFT JOIN image i ON p.uid=i.reference_page_or_product
ORDER BY RAND()
LIMIT 8
For better view The p.active=1 should be assigned to the on clause for product
See this page for proper nesting of joins, and use of parathesis: https://dev.mysql.com/doc/refman/8.0/en/nested-join-optimization.html
but there is a bug in the SQL, which should be expressed as WHERE:
SELECT t.content_type_name as type, p.title,p.start_date, p.end_date, p.last_enroll_date,
p.seat, p.cost, p.description, COUNT(r.stars) as review_count,
AVG(r.stars) as stars, i.image, p.location
FROM content_type t
INNER JOIN product p ON t.content_type_id=c.content_type_id
LEFT JOIN product_review r ON p.product_id=r.product_id
LEFT JOIN image i ON p.uid=i.reference_page_or_product
AND p.active=1
ORDER BY RAND()

MySQL Join for newsletters

I have a problem with mysql query. I am sending newsletters.
My mysql schema looks like to follwing http://sqlfiddle.com/#!2/178b7/18
How am I suppose to get from the database the COUNT of the mails that will be send.
For every List_ID in LISTS TAKE every base_id from lists_mailbases, and then count all of the base_id that are in email_database.
For example in my schema list1 should have 4 recipients, list 2 should have 2 recipients.
I wrote something like this:
SELECT l.id, COUNT(*) FROM lists l
JOIN lists_mailbases lm ON l.id = lm.list_id
JOIN email_database ed ON ed.base_id = lm.base_id
GROUP BY l.id;
but as a result, I have almost twice more results i should have. (on sqlfiddle it is ok but in my main database where i have a lot of records it gives me wrong data)
As you said, you are getting twice as much as you expect, it looks like one of the joins produces more than one record for the join. Diagnose that out.
SELECT ID, COUNT(*)
FROM
(
SELECT l.id, ED.BASE_ID FROM lists l
JOIN lists_mailbases lm ON l.id = lm.list_id
JOIN email_database ed ON ed.base_id = lm.base_id
GROUP BY l.id, ED.BASE_ID
) A;
nice question with SQLFiddle!
just add ed.base_id to your GROUP BY
SELECT l.id,ed.base_id, COUNT(*) , GROUP_CONCAT(ed.email)
FROM lists l JOIN lists_mailbases lm ON l.id = lm.list_id
JOIN email_database ed ON ed.base_id = lm.base_id
GROUP BY l.id,ed.base_id;
your lists_mailbases has repeated data by the way, it has 2 rows with the same base_id.
if your data is correct and you want to count DISTINCT base_id, just do COUNT(DISTINCT base_id)
like below
SELECT l.id, COUNT(DISTINCT ed.base_id) , GROUP_CONCAT(ed.email)
FROM lists l JOIN lists_mailbases lm ON l.id = lm.list_id
JOIN email_database ed ON ed.base_id = lm.base_id
GROUP BY l.id;

How to write JOIN QUERY for 4 tables in the below condition

I have 4 tables ACCOUNTS_TABLE , LINKS_TABLE, GROUPS_TABLE, KEYS_TABLE
I need to get all accounts details which is of acct_type xx with count of Links, groups& keywords . I have tried this query but it gives all count as 0
SELECT
acc.acct_id, acc.acct_type, count(link.id) as link_count, link.account,
groups.camp_id, count(groups.id) as group_count, count(keyword.key_id) as key_count
FROM ".ACCOUNTS_TABLE." as acc
LEFT JOIN ".LINKS_TABLE." as link ON link.account=acc.acct_id AND acct_type='xx'
LEFT JOIN ".GROUPS_TABLE." as groups ON groups.camp_id=link.id
LEFT JOIN ".KEYS_TABLE." as keyword ON keyword.camp_id=link.id
GROUP BY acc.acct_id
My required output should be like this
Any one please help me to slove this problem
You probably should use COUNT(DISTINCT ....).
SELECT acc.acct_id, COUNT(DISTINCT link.id), COUNT(DISTINCT groups.id), COUNT(DISTINCT keyword.key_id)
FROM ACCOUNTS_TABLE acc
LEFT OUTER JOIN LINKS_TABLE link ON link.account = acc.acct_id AND acct_type = 'advertiser'
LEFT OUTER JOIN GROUPS_TABLE groups ON groups.camp_id = link.id
LEFT JOIN KEYS_TABLE keyword ON keyword.id = link.id
WHERE acc.acct_type = 'xx'
GROUP BY acc.acct_id
EDIT
Amended to use the updated join conditions, etc:-
SELECT acc.acct_id, acc.acct_type, COUNT( DISTINCT link.id ) , COUNT( DISTINCT groups.id ) , COUNT( DISTINCT keyword.key_id )
FROM ACCOUNTS_TABLE acc
LEFT OUTER JOIN LINKS_TABLE link ON link.account = acc.acct_id
LEFT OUTER JOIN GROUPS_TABLE groups ON groups.camp_id = link.id
LEFT JOIN KEYS_TABLE keyword ON keyword.camp_id=link.id
WHERE acc.acct_type = 'xx'
GROUP BY acc.acct_id, acc.acct_type
You could try something like this:
SELECT ACC.Id
,( SELECT COUNT (*) FROM Links L WHERE L.AccountId = ACC.Id ) AS CountOfLinks
,( SELECT COUNT (*) FROM Groups G WHERE G.AccountId = ACC.Id ) AS CountOfGroups
FROM ( SELECT Id FROM Accounts Acc WHERE Acc.Type = 'some type' ) ACC
I've rejigged your code a bit (see below) for a few reasons:
It's helpful (for me anyway) to write my SELECT statements always in a certain way - with anything that is not being grouped placed first, and ideally putting things in same order as my JOINs and doing the same in my GROUP BY
I put anything which restricts my FROM table into the WHERE not the JOIN to make it clearer what I'm trying to do and also to make it easier to modify later on.
I also like to ensure it's well laid out to make it easier to scan for issues.
Take this rearranged query and read through it to make sure you are getting the behaviour you're expecting.
PS I'm not sure about your table names and quotation style - I usually use back ticks (`) and would never put dots (.) in my table names. If you put these in as placeholders that's fine but they could lead to trouble for you if they are real.
SELECT
acc.acct_id,
-- if you don't group by these then you need to remove them as they will just return the first values based on mysql behaviour
acc.acct_type,
link.account,
groups.camp_id,
-- these counts will only count where an ID is present which seems like what you're after
count(link.id) as link_count,
count(groups.id) as group_count,
count(keyword.key_id) as key_count
FROM ".ACCOUNTS_TABLE." as acc
LEFT JOIN ".LINKS_TABLE." as link ON link.account=acc.acct_id
LEFT JOIN ".GROUPS_TABLE." as groups ON groups.camp_id=link.id
LEFT JOIN ".KEYS_TABLE." as keyword ON keyword.id=link.id
WHERE acct_type='advertiser'
GROUP BY acc.acct_id,
-- only use these if you intend to group by them
acc.acct_type,
link.account,
groups.camp_id DESC
SELECT acct_type,
count(acct_type),
count(l.id),
count(g.id),
count(key_id)
FROM accounts a
LEFT JOIN links l ON (l.account = a.acct_id)
LEFT JOIN groups g ON (g.camp_id = l.id)
LEFT JOIN keysTable k ON k.group_id = g.id
GROUP BY acct_type HAVING acct_type = 'xx';
SQL Fiddle Validated: http://www.sqlfiddle.com/#!2/f4b6a/20
SELECT
accounts_table.acct_id,
accounts_table.acct_type,
COUNT(DISTINCT links_table.id) AS link_count,
COUNT(DISTINCT groups_table.id) AS group_count,
COUNT(DISTINCT keys_table.key_id) AS key_count
FROM
accounts_table
LEFT JOIN
links_table
ON links_table.account = accounts_table.acct_id
LEFT JOIN
groups_table
ON groups_table.camp_id = links_table.id
LEFT JOIN
keys_table
ON keys_table.camp_id = links_table.id
WHERE
acct_type = 'xx'
GROUP BY
accounts_table.acct_id,
accounts_table.acct_type
ORDER BY
link_count DESC,
group_count DESC,
key_count DESC
Edited answer to match updated question - this should do what you've asked for.
This should do what you've asked for, SQL fiddle here - http://www.sqlfiddle.com/#!2/f4b6a/20

Mysql Ranking based on Category and Branch

I'm having a hard time figuring out and trying how to fix this.
Can you help me give a logic or idea how can get the ranking of each category for each branch based on sales?
For example:
Rank 1 for branch_code_id = 9 is Accicular since it has 300,000 sales
Rank 2 for branch_code_id = 9 is WLO since it has only 200,000
sales.
Same as with other branches. I only need the rank of category for each branch_code_id.
I can't figure out how to loop this one. Rank will be placed in the "r" column as you can see in the excel output.
By the way, here's the sql statement i used to get the result you see in the screenshot.
SELECT
a.id,
a.date,
a.branch_code_id,
SUM(b.amount),
c.category
FROM
sales_add_h AS a
INNER JOIN sales_add_i AS b ON a.id = b.sales_h_id
INNER JOIN control_panel_item_create AS c ON b.item_code_id = c.id
GROUP BY c.category, a.branch_code_id, b.amount
ORDER BY SUM(b.amount) DESC
Thanks Guys!
Try this query
SELECT
#rn:=if(#prv=branch_code_id, #rn+1, 1) as rId,
#prv:= branch_code_id as branch_code_id,
val,
id,
date,
category
FROM
(SELECT
a.id,
a.date,
a.branch_code_id,
SUM(b.amount) as val,
c.category
FROM
sales_add_h AS a
INNER JOIN
sales_add_i AS b ON a.id = b.sales_h_id
INNER JOIN
control_panel_item_create AS c ON b.item_code_id = c.id
GROUP BY
c.category, a.branch_code_id, b.amount
ORDER BY
a.branch_code_id, SUM(b.amount) DESC)tmp
JOIN
(SELECT #rn:=0, #prv:=0)t
SQLFIDDLE to understand how ranking works.
I have done ranking for each branch_id as you have mentioned, if you want to rank for each category in a particular branch than you need to add another variable which stores the category and compare it within the if clause and also need to sort data within inner query accordingly order by c.category, a.branch_code_id, SUM(b.amount) DESC

Codeigniter 2.1 - join two tables and count in the same query

I have two tables:
news ->
id_news
title
body
date_created
image
category_id
comments ->
id_comments
news_id
body
date_created
How can I write query to get all news, count all the comments for every news and present that query in the view part?
select
N.ID_News,
N.Title,
N.Body,
N.Date_Created,
N.Image,
N.Category_ID,
count(C.ID_Comments) CommentCount
from
News N
LEFT JOIN Comments C
on N.ID_News = C.News_ID
group by
N.ID_News
order by
whatever column(s) are important to you
Since we are counting, we need to make a minor change to DRap's Query:
select
N.ID_News,
N.Title,
N.Body,
N.Date_Created,
N.Image,
N.Category_ID,
count(C.ID_Comments) CommentCount
from
News N
LEFT JOIN Comments C
on N.ID_News = C.News_ID
order by
whatever column(s) are important to you
That will only give you only one result.. as that query lacks a group by statement, I would recommend changing that query to this:
select
N.ID_News,
N.Title,
N.Body,
N.Date_Created,
N.Image,
N.Category_ID,
count(C.ID_Comments) CommentCount
from
News N
LEFT JOIN Comments C
on N.ID_News = C.News_ID
group by
N.title
order by
whatever column(s) are important to you
Writing this down in the Active Record format stays something like this:
$this->db->select('N.ID_News, N.Title, N.Body, N.Date_Created, N.Image')
$this->db->select('N.Category_ID, count(C.ID_Comments) AS CommentCount');
$this->db->from('News AS N');
$this->db->join('commentas AS C', 'N.ID_News = C.News_ID', 'left');
$this->db->group_by('N.title');
After this you can use the order by funtion, to order the resultsas you seefit.

Categories