What's wrong with my query:
SELECT
Articles.Name,
GroupOfArticles.Name,
(select GroupOfArticles.Name from GroupOfArticles
where GroupOfArticles.ParentGroup= Articles.Group)
FROM Articles
JOIN GroupOfArticles
ON Articles.Group = GroupOfArticles.ID
I want to show the name of the article and the name of the most basic group in the hierarchy...
databasemodel
You need to JOIN the subquery outside of the actual subquery like
SELECT a.Name, g.Name,
FROM Articles a
INNER JOIN (select Name,ParentGroup from GroupOfArticles) g
ON g.ID =a.Group
AND g.ParentGroup=a.group
The actual query shown can even be done without the subquery, like
SELECT a.Name, g.Name,
FROM Articles a
INNER JOIN GroupOfArticles g
ON g.ID =a.Group
AND g.ParentGroup=a.group
Although I doubt very much that you really want to join on both columns: ID and ParentGroup?
Obviously I haven't seen your schema, but I don't believe you need the sub-select at all. It appears that it would return the same as GroupOfArticles.Name does?
SELECT
Articles.Name,
GroupOfArticles.Name
FROM
Articles JOIN GroupOfArticles
ON Articles.Group = GroupOfArticles.ID
AND GroupOfArticles.ParentGroup = Articles.Group
Actually, the above assumes that every article returned will be part of a specific group, and will also have a parent group which is the same. Inception?
EDIT Based on more requirements / information, here is a second version:
SELECT DISTINCT
a.Name,
g.Name
FROM
GroupOfArticles g INNER JOIN GroupOfArticles g1
ON g1.ParentGroup = g.ID
INNER JOIN Articles a ON
CASE
WHEN g.ParentGroup IS NULL THEN g.ID
ELSE g1.ID
END
I also created an SQLFiddle for the above.
EDIT 2 An alternative version which doesn't include JOIN OR CASE:
SELECT DISTINCT
a.Name,
g.Name
FROM
Articles a, GroupOfArticles g, GroupOfArticles g1
WHERE
g.ID <> g1.ID
AND g.ParentGroup IS NULL
AND
(
a.Group = g.ID
OR a.Group = g1.ID AND g1.ParentGroup = g.ID
)
SQLFiddle
Note that in the two latest queries, you could replace the DISTINCT keyword with GROUP BY a.Name HAVING COUNT(*) > 0, If you really must use those constructs as well. Just remove DISTINCT from the top, and add the GROUP BY ... at the end.
Related
For this example I got 3 simple tables (Page, Subs and Followers):
For each page I need to know how many subs and followers it has.
My result is supposed to look like this:
I tried using the COUNT function in combination with a GROUP BY like this:
SELECT p.ID, COUNT(s.UID) AS SubCount, COUNT(f.UID) AS FollowCount
FROM page p, subs s, followers f
WHERE p.ID = s.ID AND p.ID = f.ID AND s.ID = f.ID
GROUP BY p.ID
Obviously this statement returns a wrong result.
My other attempt was using two different SELECT statements and then combining the two subresults into one table.
SELECT p.ID, COUNT(s.UID) AS SubCount FROM page p, subs s WHERE p.ID = s.ID GROUP BY p.ID
and
SELECT p.ID, COUNT(f.UID) AS FollowCount FROM page p, follow f WHERE p.ID = f.ID GROUP BY p.ID
I feel like there has to be a simpler / shorter way of doing it but I'm too unexperienced to find it.
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
Next, learn what COUNT() does. It counts the number of non-NULL values. So, your expressions are going to return the same value -- because f.UID and s.UID are never NULL (due to the JOIN conditions).
The issue is that the different dimensions are multiplying the amounts. A simple fix is to use COUNT(DISTINCT):
SELECT p.ID, COUNT(DISTINCT s.UID) AS SubCount, COUNT(DISTINCT f.UID) AS FollowCount
FROM page p JOIN
subs s
ON p.ID = s.ID JOIN
followers f
ON s.ID = f.ID
GROUP BY p.ID;
The inner joins are equivalent to the original query. You probably want left joins so you can get counts of zero:
SELECT p.ID, COUNT(DISTINCT s.UID) AS SubCount, COUNT(DISTINCT f.UID) AS FollowCount
FROM page p LEFT JOIN
subs s
ON p.ID = s.ID LEFT JOIN
followers f
ON p.ID = f.ID
GROUP BY p.ID;
Scalar subquery should work in this case.
SELECT p.id,
(SELECT Count(s_uid)
FROM subs s1
WHERE s1.s_id = p.id) AS cnt_subs,
(SELECT Count(f_uid)
FROM followers f1
WHERE f1.f_id = p.id) AS cnt_fol
FROM page p
GROUP BY p.id;
We are maintaining a history of Content. We want to get the updated entry of each content, with create Time and update Time should be of the first entry of the Content. The query contains multiple selects and where clauses with so many left joins. The dataset is very huge, thereby query is taking more than 60 seconds to execute. Kindly help in improving the same. Query:
select * from (select * from (
SELECT c.*, initCMS.initcreatetime, initCMS.initupdatetime, user.name as partnerName, r.name as rightsName, r1.name as copyRightsName, a.name as agelimitName, ct.type as contenttypename, cat.name as categoryname, lang.name as languagename FROM ContentCMS c
left join ContentCategoryType ct on ct.id = c.contentType
left join User user on c.contentPartnerId = user.id
left join Category cat on cat.id = c.categoryId
left join Language lang on lang.id = c.languageCode
left join CopyRights r on c.rights = r.id
left join CopyRights r1 on c.copyrights = r1.id
left join Age a on c.ageLimit = a.id
left outer join (
SELECT contentId, createTime as initcreatetime, updateTime as initupdatetime from ContentCMS cms where cms.deleted='0'
) as initCMS on initCMS.contentId = c.contentId WHERE c.deleted='0' order by c.id DESC
) as temp group by contentId) as c where c.editedBy='0'
Any help would be highly appreciated. Thank you.
Just a partial eval and suggestion because your query seems non properly formed
This left join seems unuseful
FROM ContentCMS c
......
left join (
SELECT contentId
, createTime as initcreatetime
, updateTime as initupdatetime
from ContentCMS cms
where cms.deleted='0'
) as initCMS on initCMS.contentId = c.contentId
same table
the order by (without limit) in a subquery in join is unuseful because join ordered values or unordered value produce the same result
the group by contentId is strange beacuse there aren't aggregation function and the sue of group by without aggregation function is deprecated is sql
and in the most recente version for mysql is not allowed (by deafult) if you need distinct value or just a rows for each contentId you should use distinct or retrive the value in a not casual manner (the use of group by without aggregation function retrive casual value for not aggregated column .
for a partial eval your query should be refactored as
SELECT c.*
, c.initcreatetime
, c.initupdatetime
, user.name as partnerName
, r.name as rightsName
, r1.name as copyRightsName
, a.name as agelimitName
, ct.type as contenttypename
, cat.name as categoryname
, lang.name as languagename
FROM ContentCMS c
left join ContentCategoryType ct on ct.id = c.contentType
left join User user on c.contentPartnerId = user.id
left join Category cat on cat.id = c.categoryId
left join Language lang on lang.id = c.languageCode
left join CopyRights r on c.rights = r.id
left join CopyRights r1 on c.copyrights = r1.id
WHERE c.deleted='0'
) as temp
for the rest you should expiclitally select the column you effectively need add proper aggregation function for the others
Also the nested subquery just for improperly reduce the rows don't help performance ... you should also re-eval you data modelling and design.
I have 3 tables concerning complains. The first table consists of the complain information itself, 2nd one is the complain_review with status_id, and the 3rd is the status_id table consisting status information. I'm trying to select the complain_desc from complain and latest status_id from complain_review (sort by date desc) and couple that with complain_status information.
This is what I've tried (no success so far):
SELECT c1.complain_desc, c2.status_id, c2.name as statusDesc from complain c1
left join
(SELECT c3.status_id, c4.name, c3.complain_id FROM complain_review c3
inner join complain_status c4 on c4.id=c3.status_id ORDER by c3.date DESC) c2
on c2.complain_id=c1.id
this is the updated example provided by #maheshiv
.. I've searched through the site but I don't exactly know what keyword to search concerning this matter :(
Edit: I've build a schema at http://sqlfiddle.com/#!9/d86a7a/2 so perhaps somebody could give take a better look at the tables
Edit: Perhaps this would be the closest as I could get .. and working!
SELECT c.complain_desc, cr1.status_id, cs.name
FROM complain c
INNER JOIN complain_review cr1 ON c.id=cr1.complain_id
INNER JOIN complain_status cs ON cs.id=cr1.status_id
WHERE cr1.date = (SELECT MAX(cr2.date) FROM complain_review cr2
WHERE cr1.complain_id=cr2.complain_id)
I'm trying to select the complain_desc from complain and latest status_id from complain_review (sort by date desc) and couple that with complain_status information.
This is a very common question on Stack Overflow. You can follow the greatest-n-per-group to find many solutions.
Here's a solution using your example:
SELECT c.complain_desc, latest_cr.status_id, cs.name AS status_desc
FROM complain AS c
INNER JOIN (
SELECT complain_id, status_id
FROM (
SELECT cr.complain_id, cr.status_id,
IF(#cgroup=cr.complain_id, #rownum:=#rownum+1, 1) AS rownum,
(#cgroup:=cr.complain_id)
FROM (SELECT #cgroup:=0, #rownum:=1) AS _init
CROSS JOIN complain_review AS cr
ORDER BY cr.complain_id DESC, cr.date DESC
) AS n
WHERE n.rownum = 1
) AS latest_cr
ON c.id=latest_cr.complain_id
INNER JOIN complain_status AS cs
ON cs.id = latest_cr.status_id;
Here's a different solution using no subqueries:
SELECT c.complain_desc, cr1.status_id, cs.name AS status_desc
FROM complain AS c
INNER JOIN complain_review AS cr1
ON cr1.complain_id = c.id
LEFT OUTER JOIN complain_review AS cr2
ON cr2.complain_id = c.id AND (cr2.date > cr1.date OR cr2.date = cr1.date AND cr2.id > cr1.id)
INNER JOIN complain_status AS cs
ON cs.id = cr1.status_id
WHERE cr2.id IS NULL;
I think you may need this query,
I believe max status_id is the latest status for complaint. As per http://sqlfiddle.com/#!9/d86a7a/15
select c1.complain_desc, c2.status_id, c3.name from complain c1 inner join (select complain_id, max(status_id) from complain_review group by complain_id) c2 on c1.id=c2.complain_id inner join complain_status c3 on c3.id=c2.status_id;
I have 5 tables: a, b, c, d and e.
Each table is joined by an INNER JOIN on the id field.
My query is working perfectly fine as it is but I need to enhance it to count the result so I can echo it to the screen. I have not been able to get the count working.
There are very specific fields I am querying:
state_nm
status
loc_type
These are all parameters I enter manually into the query like so:
$_POST["state_nm"] = 'AZ'; ... // and for all other below values..
SELECT *
FROM main_table AS a
INNER JOIN table_1 AS b ON a.id = b.id
INNER JOIN table_2 AS c ON b.id = c.id
INNER JOIN blm table_3 AS d ON c.id = d.id
INNER JOIN table_4 AS e ON d.id = e.id
WHERE a.trq != ''
AND b.state_nm = '".$_POST["state_nm"]."'
AND b.loc_type LIKE \ "%".$_ POST ["loc_type"]."%\"
AND b.STATUS = '".$_POST["status"]."'
GROUP BY b.NAME
ORDER BY c.county ASC;
not sure I get exactly what is your goal here.
anyway, using "select *" and group by in the same query is not recommended and in some databases will raise an error
what I would do is something like that:
select a.name, count(*) from (
SELECT * FROM main_table as a
INNER JOIN table_1 as b
ON a.id=b.id
INNER JOIN table_2 as c
ON b.id=c.id
INNER JOIN blm table_3 as d
ON c.id=d.id
INNER JOIN table_4 as e
ON d.id=e.id
WHERE a.trq != ''
AND b.state_nm = '".$_POST["state_nm"]."'
AND b.loc_type LIKE \"%".$_POST["loc_type"]."%\"
AND b.status = '".$_POST["status"]."'
)a
group by a.name
the basic idea is to add an outer query and use group by on it...
hopefully this solves your problem.
In place of
SELECT *
in your query, you could replace that with
SELECT COUNT(*)
That query should return the number of rows that would be in the resultset for the query using SELECT *. Pretty easy to test, and compare the results.
I think that answers the question you asked. If not, I didn't understand your question.
I didn't notice the GROUP BY in your query.
If you want to get a count of rows returned by that query, wrap it in outer query.
SELECT COUNT(1) FROM (
/* your query here */
) c
That will give you a count of rows returned by your query.
I have a query to pull a total number for a given publisher ID. I'd like to use it as a subquery so I can iterate over all publisher IDs.
My working query for a given ID is:
SELECT SUM( d.our_cost )
FROM articles a
CROSS JOIN domains d ON a.domain_id = d.id
AND d.publisher_id = '1094'
I'd like to pull this figure for all ID's in publisher p table where d.publisher_id = p.id
So far I've tried the following to no avail:
SELECT p.id, p.contact_name, p.contact_email,
(SELECT SUM(d.our_cost)
FROM articles a
CROSS JOIN domains d ON a.domain_id = d.id and d.publisher_id = p.id) total
FROM publishers p
The specific error I'm getting is: Unknown column 'p.id' in 'on clause'
I think you should modify your query and put the subquery in the from clause, something like this:
SELECT p.id, p.contact_name, p.contact_email, total.total_cost
FROM
(
SELECT SUM(d.our_cost) as total_cost, d.publisher_id
FROM articles a CROSS JOIN domains d ON a.domain_id = d.id ) total
JOIN publishers p on total.publisher_id = p.id
I'm assuming you've gotten an error about your syntax, try:
SELECT p.id, p.contact_name, p.contact_email, SUM(d.our_cost) as total
FROM articles a
CROSS JOIN domains d ON a.domain_id = d.id
JOIN publishers p ON d.publisher_id = p.id
seems like a group by would be handy here instead
Also it seems like you dont need articles table at all (unless you have additional business rules)
SELECT p.id, p.contact_name, p.contact_email, IFNULL(SUM(d.our_cost),0) AS total
FROM publishers p
LEFT JOIN domains d ON d.publisher_id = p.id
GROUP BY p.id