I'm trying to fetch all the rows from table_m which also have an index in table_mi and I'm expecting to get 2 rows as a result (with m.id=3 and m.id=9) - but if I add GROUP_CONCAT to my select then I only get one row returned. Am I having a misshap somewhere within those joins of mine?
Query:
SELECT
m.id,
m.name,
m.keyword,
IFNULL(GROUP_CONCAT(r.keyword),'TEST') AS restrictions
FROM
table_m AS m
INNER JOIN
table_mi as mi ON m.id=mi.m_id
LEFT JOIN
table_ri as ri ON m.id=ri.m_id
LEFT JOIN
table_r AS r ON ri.r_id=r.id
WHERE
(
m.id>0
AND m.active=1
AND mi.p_id=0
AND (mi.pa_id="11" OR (mi.pa_id=0 AND mi.id!=0))
AND mi.u_id=IF((SELECT id FROM table_mi WHERE p_id=0 AND pa_id="11" AND u_id="2")>0,"2",0)
) OR mi.id=0
ORDER BY
mi.priority;
This is what I'm getting as a result:
ID NAME KEYWORD RESTRICTIONS
9 test_a key_a r_key_2,r_key_3,r_key_4
This is what I'm expecting:
ID NAME KEYWORD RESTRICTIONS
9 test_a key_a r_key_2,r_key_3,r_key_4
3 test_b key_b TEST
Please see my full example with schema on sql fiddle: http://sqlfiddle.com/#!2/359d9/1
GROUP_CONCAT is an aggregate function. It will bring back a single row UNLESS you specify a GROUP BY clause (with any fields that are not in the GROUP BY being aggregate fields)
Before the ORDER BY add the following:-
GROUP BY m.id, m.name, m.keyword
That said it looks like you might want to use CONCAT to join 2 values together rather than GROUP_CONCAT
As an aside, your SQL might be easier to read if you eliminate the subselect. Assuming it is bringing back a single record then possibly as follows
SELECT
m.id,
m.name,
m.keyword,
IFNULL(GROUP_CONCAT(r.keyword),'TEST') AS restrictions
FROM
table_m AS m
INNER JOIN
table_mi as mi ON m.id=mi.m_id
LEFT JOIN
table_ri as ri ON m.id=ri.m_id
LEFT JOIN
table_r AS r ON ri.r_id=r.id
LEFT OUTER JOIN
table_mi AS mi2 ON mi2.p_id=0 AND mi2.pa_id="11" AND mi2.u_id="2"
WHERE
(
m.id>0
AND m.active=1
AND mi.p_id=0
AND (mi.pa_id="11" OR (mi.pa_id=0 AND mi.id!=0))
AND mi.u_id=IF(mi2.id >0,"2",0)
) OR mi.id=0
ORDER BY
mi.priority;
You do no need GROUP_CONCAT to achieve what you want.
Instead of :
IFNULL(GROUP_CONCAT(r.keyword),'TEST') AS restrictions
use
IFNULL(r.keyword,'TEST') AS restrictions
OR:
Keep the query as it is and add GROUP BY m.id before ORDER BY
Related
I have the following select query. I want to avoid getting the duplicated "EN" row when "ES" row is present. Like prefer ES over EN.
SELECT s.soft_id,s.groupby,s.packageid,s.name,s.area,l.min,GROUP_CONCAT(DISTINCT JSON_ARRAY(s.version,s.detailid,s.filesize,s.updatetime)) versions
FROM software s
INNER JOIN langs l ON s.lang_id=l.lang_id
INNER JOIN devices_type t ON (s.familylock_id=t.familylock_id OR (s.familylock_id=0 AND s.devicelock_id=t.device_type_id))
INNER JOIN devices d ON t.device_type_id=d.device_type_id
INNER JOIN users u ON d.user_id=u.user_id
WHERE s.groupby IN(1,2,3)
AND u.token="abc"
AND d.serialno="123456789"
AND l.min IN("ES","EN")
GROUP BY s.soft_id,s.groupby,s.packageid,s.name,s.area,l.min ORDER BY s.name ASC
This is the example result:
image
You can test your query here: http://185.27.134.10/login.php?2=epiz_26706010wejghelqwdtg3e54gVGtSRk1VMUVRVE5QVkdzeFRWaDNhRWxUUldoSldIZzRaa2g0T0daSWVEaG1TSGhvVjIxc1JGb3lkRk5rV0U1cFZsRTlQUT09wejghelqwdtg3e54gsql102.epizy.comwejghelqwdtg3e54gepiz_26706010_test&db=epiz_26706010_test
I'd do it in two steps, count how many duplicate rows you have. And by duplicate, I mean identical on one column but differ in ES vs EN. have the table sorted
select the last among the duplicates
Get top first record from duplicate records having no unique identity
Outer join the table twice, looking for a single specific value with each join, and then coalesce the fields in the order you prefer:
SELECT s.soft_id, coalesce(les.min, len.min) As min, ...
FROM software s
LEFT JOIN langs les ON s.lang_id=les.lang_id AND les.min = 'ES'
LEFT JOIN langs len ON s.lang_id=len.lang_id AND len.min = 'EN'
...
WHERE s.groupby IN(1,2,3)
AND coalesce(les.lang_id, len.lang_id) IS NOT NULL
...
Windowing functions can do it more efficiently, but they're still not support on lots of MySql servers in the wild. If you're using 8.0 or later, you should look into that option.
You can use window functions as:
with q as (
<your query here>
)
select q.*
from (select q.*,
row_number() over (partition by soft_id order by field(l.min, 'ES', 'EN')) as seqnum
from q
) q
where seqnum = 1;
I have 3 tables which are interconnected and i want to select columns from two tables and counts from table 3. If anyone is aware on this, any hint would be appreciated.
Below is the sql i tried, but the count is getting repeated
SELECT distinct p.p_id, p.p_f6, p.p_l4,m.m_id, (
SELECT COUNT(*)
FROM ttokens t where t.pdetail_id = p.pdetail_id
) AS token_count
FROM tparking p,ttokens t LEFT join ttokens_md m ON t.trefn_id = m.trefn_id
WHERE t.pdetail_id = p.pdetail_id
You can try to use JOIN with subquery to get your count instead of selcet subquery.
SELECT p.p_id, p.p_f6, p.p_l4,m.m_id,t.cnt
FROM tparking p
JOIN (
SELECT pdetail_id,COUNT(*) cnt
FROM ttokens
GROUP BY pdetail_id
) t ON t.pdetail_id = p.pdetail_id
LEFT join ttokens_md m ON t.trefn_id = m.trefn_id
Note
I would use JOIN instead of , comma with where condition to connect two tables,, is an old style.
I am attempting to create a subquery in Access but I am receiving an error stating that one record can be returned by this subquery. I am wanting to find the top 10 companies that have the most pets then I want to know the name of those pets. I have never created a subquery before so I am not sure where I am going wrong. Here is what I have:
SELECT TOP 10 dbo_tGovenrnmentRegulatoryAgency.GovernmentRegulatoryAgency
(SELECT dbo_tPet.Pet
FROM dbo_tPet)
FROM dbo_tPet INNER JOIN dbo_tGovenrnmentRegulatoryAgency ON
dbo_tPet.GovernmentRegulatoryAgencyID =
dbo_tGovenrnmentRegulatoryAgency.GovernmentRegulatoryAgencyID
GROUP BY dbo_tGovenrnmentRegulatoryAgency.GovernmentRegulatoryAgency
ORDER BY Count(dbo_tPet.PetID) DESC;
Consider this solution, requiring a subquery in the WHERE IN () clause:
SELECT t1.GovernmentRegulatoryAgency, dbo_tPet.Pet,
FROM dbo_tPet
INNER JOIN dbo_tGovenrnmentRegulatoryAgency t1 ON
dbo_tPet.GovernmentRegulatoryAgencyID = t1.GovernmentRegulatoryAgencyID
WHERE t1.GovernmentRegulatoryAgency IN
(SELECT TOP 10 t2.GovernmentRegulatoryAgency
FROM dbo_tPet
INNER JOIN dbo_tGovenrnmentRegulatoryAgency t2 ON
dbo_tPet.GovernmentRegulatoryAgencyID = t2.GovernmentRegulatoryAgencyID
GROUP BY t2.GovernmentRegulatoryAgency
ORDER BY Count(dbo_tPet.Pet) DESC);
Table aliases are not needed but I include them for demonstration.
This should hopefully do it:
SELECT a.GovernmentRegulatoryAgency, t.NumOfPets
FROM dbo_tGovenrnmentRegulatoryAgency a
INNER JOIN (
SELECT TOP 10 p.GovernmentRegulatoryAgencyID, COUNT(p.PetID) AS NumOfPets
FROM dbo_tPet p
GROUP BY p.GovernmentRegulatoryAgencyID
ORDER BY COUNT(p.PetID) DESC
) t
ON a.GovernmentRegulatoryAgencyID = t.GovernmentRegulatoryAgencyID
In a nutshell, first get the nested query sorted, identifying what the relevant agencies are, then inner join back to the agency table to get the detail of the agencies so picked.
I have written SQL query with a INNER JOIN and Sub-query:
SELECT c.*,
ar.ArticleName,
ar.idArticle,
du.DetailToUsersName,
du.DetailToUsersPhoto,
COUNT(c.idCommentToArticle) AS CNT,
CASE WHEN d.Count IS NULL THEN 0 ELSE d.Count END AS CountLikes
from (select *
from commenttoarticle g
inner join (select distinct(s.idCommentToArticle)
from commenttoarticle s
order by s.CommentToArticlePID limit 3) as gh) as c
LEFT JOIN article ar ON c.CommentToArticleIdArticle = ar.idArticle
LEFT JOIN detailtousers du ON du.idDetailToUsers = c.CommentToArticleIdUser
LEFT JOIN `likes` d ON (d.IdNote = c.idCommentToArticle AND d.LikeType = 6)
WHERE c.CommentToArticleIdArticle = 11
GROUP BY c.idCommentToArticle
ORDER BY c.idCommentToArticle DESC
So, I get error:
Duplicate column name 'idCommentToArticle'
I can not find where the duplication is?
you can specify in the alias table query c
select g.* from commenttoarticle g
instead of
select * from commenttoarticle g
Also you should specify Join condition to limit the rows to 3 as per your intention, with out the ON clause it will be like a cross join.
select g.* from commenttoarticle g
inner join (select distinct(s.idCommentToArticle) from commenttoarticle s order by s.CommentToArticlePID limit 3) as gh
on g.idcommenttoarticle = gh.idcommenttoarticle
As #RADAR has suggested, your inner query joins don't seem to be complete. And I see from comments that once you place the JOIN condition in, then you lose all data. I think this is because neither part of the subqueries were doing what they were supposed to do.
Here is my attempt at a total solution (note, without dataset and table definition I can't show it working). OK, so you have asked the question again over here and provided a SQL-Fiddle, I have updated with a working version, but minus the additional JOIN tables, since they are not defined.
SELECT c.*,
ar.ArticleName,
ar.idArticle,
du.DetailToUsersName,
du.DetailToUsersPhoto,
COUNT(c.idCommentToArticle) AS CNT,
CASE WHEN d.Count IS NULL THEN 0 ELSE d.Count END AS CountLikes
FROM commenttoarticle c -- one layer of subquery not required.
INNER JOIN (select s.idCommentToArticle, s.CommentToArticlePID -- added both the id and the parent id
FROM commenttoarticle s
WHERE s.CommentToArticleIdArticle = 11 -- moved to inner query, instead of outer query
ORDER BY s.idCommentToArticle DESC limit 3) as gh
ON c.idcommenttoarticle = gh.idcommenttoarticle -- add join condition
OR c.idcommenttoarticle = gh.CommentToArticlePID -- which matches id and parent id
LEFT JOIN article ar ON c.CommentToArticleIdArticle = ar.idArticle
LEFT JOIN detailtousers du ON du.idDetailToUsers = c.CommentToArticleIdUser
LEFT JOIN `likes` d ON (d.IdNote = c.idCommentToArticle AND d.LikeType = 6)
GROUP BY c.idCommentToArticle
ORDER BY c.idCommentToArticle DESC
But let me explain a little further, the following code from your original query was selecting the top 3 idCommentToArticlePID,
(select *
from commenttoarticle g
inner join (select distinct(s.idCommentToArticle)
from commenttoarticle s
order by s.CommentToArticlePID limit 3) as gh)
but then because there was no ON specified the 3 records were then joined to every single record from the g reference. This resulted in the full dataset being returned.
And then you you specified WHERE c.CommentToArticleIdArticle = 11 this filtered the result set back down again to something that looked correct.
When you then added the ON (as per #RADAR's suggestion) the inner query did not contain any values that matched the WHERE c.CommentToArticleIdArticle = 11 filter and thus you lost all your results. If you move this filter into the inner query as shown above, then these will work together and not conflict.
Within the JOIN condition, you indicate that you want both the matching articles and their parents, so I added both to the return of the inner query, and checked for either in the join condition.
Also I think the whole g table reference is redundant and can be removed. You should be able to access this table directly as c.
I also have some concerns about the GROUP BY and COUNT (c.idCommentToArticle) - there seem a little strange, but I have no supporting context (ie data examples), so they may be correct. If you still have issues, I would comment the GROUP BY and COUNT statements out, and test to see what data you are getting, before adding these back in.
This is my query. The output looks fine except the COUNT function is returning numbers which seem totally arbitrary (e.g. 7-digit numbers where I'd expect 3-digit numbers):
SELECT tc.tableName, m.fieldName, COUNT(m.fieldName)
FROM apiResult, (
SELECT cc.surveyID, cc.fieldName
FROM apiResult as ar
INNER JOIN columnConversion as cc
ON substring(ar.triggerName,-10)=cc.fieldID
) AS m
INNER JOIN tableConversion as tc
ON m.surveyID=tc.surveyID
GROUP BY tc.tableName, m.fieldName;
I think, for a start, that COUNT(m.fieldName) is probably wrong, since it doesn't correspond with GROUP BY tc.tableName, m.fieldName.
Here's what the query is meant to do: one of the tables in the sub-query, apiResult, has a column called 'triggerName' which contains an ID I call 'fieldID', plus a column called 'surveyID'. The tables columnConversion and tableConversion are tables which match the IDs to human readble names. So, the follow query produces the count that I want, but, I want the IDs replaced by the human readable names, hence the above query:
SELECT cc.surveyID, cc.fieldName, COUNT(ar.triggerName)
FROM apiResult as ar
INNER JOIN columnConversion as cc
ON substring(ar.triggerName,-10)=cc.fieldID
GROUP BY (ar.triggerName)
Any ideas what I've done wrong?
Why are you mixing explicit and implicit joins? You appear to have missed a join condition on the first table. Well, actually, I don't think it is needed. This should work:
SELECT tc.tableName, m.fieldName, COUNT(m.fieldName)
FROM (SELECT cc.surveyID, cc.fieldName
FROM apiResult ar INNER JOIN
columnConversion cc
ON substring(ar.triggerName, -10) = cc.fieldID
) m INNER JOIN
tableConversion as tc
ON m.surveyID = tc.surveyID
GROUP BY tc.tableName, m.fieldName;