I have problem when i use WHERE and COUNT together. I have 3 tables: T1 and T2 and in T3 t1.id and t2.id.
I need to print all result with specific CITY name from T1 and count how many employees are work on that project. SO i tried
SELECT t1.name, COUNT(t3.idP)
from t3
INNER JOIN t1 ON t1.idP = t3.idP
INNER JOIN t2 ON t2.idE = t3.idE
WHERE t2.city = 'SOME CITY NAME'
Result is just first project name with number of all employees. If i remove COUNT i can see all project in that city, or if i remove WHERE i can see number of employees in each project. But when have both COUNT and WHERE, i get just first project and number of all project's employees.
When you mix normal columns (t1.name) with aggregate functions (COUNT(t3.idP)), you need to use GROUP BY.
SELECT t1.name, COUNT(t3.idP)
from t3
INNER JOIN t1 ON t1.idP = t3.idP
INNER JOIN t2 ON t2.idE = t3.idE
WHERE t2.city = 'SOME CITY NAME'
GROUP BY t1.name
Related
I have 4 tables:
T1 {id, user_name, email, telephone, created_at, updated_at}
T2 {id, menu_name, town, district, t1_foreign, view_budget, view_menu, created_at, updated_at}
T3 {id, t2_foreign, menu_item_name, ingredients, calories, cost_ex, cost_in, selling_in, selling_ex, image_dir, img_caption, view_item, created_at, updated_at}
T4 {id, t1_foreign, t2_foreign, created_at, updated_at}
A user from T1 is linked to a menu in T2 on T2.t1_foreign. The idea was originally that only the linked user that is the rep in an area will be able to see the cost of menu items in table T3. But this changed so table T4 was created to link other users to T2 on T4.t2_foreign and T4.t1_foreign so they will also be able to view the cost for specific menus.
I am trying to create a summary query so I can view the menu's info as well as the number of linked users, but I am getting duplicate aggregate COUNT. I figured out that it is due to the double join with same alias for T2, but cannot seem to get a handle on getting around this problem.
SELECT t2.id t2.menu_name, t2.town, t2.district, t2.view_menu, t2.view_budget,
IF(COUNT(t4.t2_foreign)=0, "1", CONCAT("1+", COUNT(t4.t2_foreign), " Others")) AS linked, // <=== aggregate function
GREATEST(t2.updated_at, t2.created_at, COALESCE(t3.updated_at, \'1000-01-01\'), COALESCE(t3.created_at, \'1000-01-01\')) AS newest
FROM T2 AS t2
LEFT JOIN T3 AS t3
ON (t3.t2_foreign = t2.id)
INNER JOIN T1 AS t1
ON (t2.t1_foreign = t1.id)
LEFT JOIN T4 AS t4
ON (t4.t2_foreign = t2.id) // this creates duplicate count
GROUP BY t2.id
ORDER BY (newest, ASC)
I have tried a subquery join
SELECT t2.id t2.menu_name, t2.town, t2.district, t2.view_menu, t2.view_budget,
tt.linked,
GREATEST(t2.updated_at, t2.created_at, COALESCE(t3.updated_at, \'1000-01-01\'), COALESCE(t3.created_at, \'1000-01-01\')) AS newest
FROM T2 AS t2
LEFT JOIN T3 AS t3
ON (t3.t2_foreign = t2.id)
INNER JOIN T1 AS t1
ON (t2.t1_foreign = t1.id)
LEFT JOIN (
SELECT IF(COUNT(t4.t2_foreign)=0, "1", CONCAT("1+", COUNT(t4.t2_foreign), " Others")) AS linked
FROM T4
) AS t4 ON (t4.t2_foreign = t2.id) // this give not unique table/alias error
GROUP BY t2.id
ORDER BY (newest, ASC)
Can someone please point me in the right direction to get the correct aggregate COUNT result?
UPDATE : Result albeit not the expected
After fiddling around with my subquery effort I got it to return a result, but the result is the aggregate for all the records and not for each record. Had to change it to :
LEFT JOIN (
SELECT IF(COUNT(t4.t2_foreign)=0, "1", CONCAT("1+", COUNT(t4.t2_foreign), " Others")) AS linked, t4.t2_foreign
FROM T4 as t4
) AS tt ON (tt.t2_foreign = t2.id)
On the right track though.
In the end a Join was not needed, I used a correlated subquery as a sub-SELECT as suggested in the comments. Subquery :
( SELECT IF(COUNT(t4.t2_foreign)=0, "1", CONCAT("1+", COUNT(t4.t2_foreign), " Others")) AS linked
FROM T4 as t4
WHERE t4.t2_foreign=t2.id
) AS linked
This retrieved an aggregate COUNT for the number of linked users in table T4 to table T2 for each primary key in T2.
I have 2 tables in my database, let's say t1 and t2.
There are 2 rows in both of them.
1s is id and 2nd is Name
Table t1:
Id. Name
1. abc
2. def
3. ghi
Table t2:
Id. Name
1. abc
2. abc
3. abc
4. def
4. def
Now , I need this type of output in MySQL
Total. Name
3. abc
2. def
0. ghi
I tried this so far
Select Count(*) as Total, Name
from t1 Inner Join
t2
Group By t2.Name
Having t1.Name = t2.Name
SELECT COUNT(t2.Id) as Total, t1.Name
FROM t1 LEFT JOIN t2
ON t2.Name = t1.Name
GROUP BY t1.Name;
The same answer like Yogesh, but with the comma and caps correctly set.
regarding the SELECT you made
Select Count(*) as Total, Name
from t1 Inner Join
t2
Group By t2.Name
Having t1.Name = t2.Name
here my 2 cents
1st.) as there are two tables with the same column you will receive ambiguous column error, so you have to write "t1.Name" instead of just "Name"
2nd.) with an INNER JOIN you select always and only the rows that exist in both tables linked with fields at the ON part of the join
3rd.) and the HAVING clause is not a appropriate way to link tables together, use just the complete JOIN syntax with the ON and the according fields
Hope that helps a bit.
Simply you can do LEFT JOIN & aggregation :
SELECT COUNT(t2.id), as total t1.name
FROM t1 LEFT JOIN
t2
ON t2.name = t1.name
GROUP BY t1.name;
Good evening,
I have two tables t1 and t2
In t1, I have two variables, ID (which uniquely identify each row) and DOC (which can be common to several IDs)
In t2, I have three variables, ID (which does not necessarily uniquely identify the rows here), AUTH , and TYPE. Each ID has a maximum of 1 distinct AUTH.
Sample data:
What I would like to do is to select the DOCs that have an ID with AUTH='EP', and that also have an ID with AUTH='US'. They could have additional IDs with other AUTH, but they have to have at least these two.
Thus, i would have a final table with the DOC, ID,and AUTH (there should be at least 2 IDs per doc, but it can be more if there exists an additional AUTH to US and EP for this DOC)
The desired results:
This should work:
SELECT DISTINCT (T1.ID), T1.DOC, T2.AUTH FROM T1
LEFT JOIN T2 ON T2.ID = T1.ID
WHERE T1.DOC IN( SELECT T1.DOC FROM T2
LEFT JOIN T1 ON T1.ID = T2.ID
WHERE T2.AUTH IN('EP','US')
GROUP BY T1.DOC HAVING COUNT(DISTINCT T2.AUTH) = 2) ;
If I could understand correctly the query is going to be something like that:
select t1.doc, t1.id, t2.auth from t1
left join t2 on t2.id = t1.id
where t1.doc in( select t1.doc from t2
left join t1 on t1.id = t2.id
where t2.auth in('EP','US') );
Although, the result set is basically going to be the first sample data table, due to the ID 6 which has a AUTH = "EP" and, consequently, the ID 7 which has the same DOC from ID 6.
I am searching one student from each class from one group. There are different class groups and every group has different classes and every class has multiple students. See below:
Group1 --> Class1, Class2 etc
Class1 --> GreenStudent1, GreenStudent2 etc
Class2 --> RedStudent1, RedStudent2 etc
------------------------------------------------------
SELECT
table1.id,
table1.myname,
table1.marks
table2.studentid,
table2.studentname
FROM table1
INNER JOIN table3 ON table1.oldid = table3.id
INNER JOIN table2 ON table2.studentid = table3.newid
WHERE
table1.classgroup = 'SCI79'
GROUP BY table1.oldid
ORDER BY table1.marks DESC
There are different joins applied in the query. Above mentioned query giving me correct results but I need little modification in it. Current query returning me one student from each class.
What I need? I need one student from each class but only that student who has MAXIMUM
table1.marks
So I should have one student from each class who has maximum number in their relevant classes. Can anyone suggest some solution or rewrite this query? Thanks :)
A subquery on an INNER JOIN should handle this:
SELECT t1.id
,t1.myname
,maxMarks.marks
,t2.studentid
,t2.studentname
FROM table1 t1
INNER JOIN table3 t3 ON t1.oldid = t3.id
INNER JOIN table2 t2 ON t2.studentid = t3.newid
INNER JOIN (
SELECT id
,MAX(marks) AS marks
FROM table1
GROUP BY id
) maxMarks ON t1.id = maxMarks.id
AND t1.marks = maxMarks.marks
WHERE t1.classgroup = 'SCI79'
GROUP BY t1.oldid
ORDER BY t1.marks DESC
Joining the aggregated table with MAX back on itself should filter down the result set to each student and their individual highest marks.
EDIT
I think I misread your original question ... you wanted students only that have the MAX(marks) period? in that case, use this query:
SELECT t1.id
,t1.myname
,t1.marks
,t2.studentid
,t2.studentname
FROM table1 t1
INNER JOIN table3 t3 ON t1.oldid = t3.id
INNER JOIN table2 t2 ON t2.studentid = t3.newid
WHERE t1.classgroup = 'SCI79'
AND t1.marks = (
SELECT MAX(marks) AS marks
FROM table1
)
GROUP BY t1.oldid
ORDER BY t1.marks DESC
This WHERE clause will only return students that have marks matching the MAX mark in the entire table.
You could use the max function, something like:
where table1.marks = max(table1.marks)
I have the following two tables:
Table1 {T1ID, Name}
Table2 {T2ID, T1ID, Date, Value}
Date is of type DATE.
and I am looking for a SQL query to fetch only the latest value (by Date) for each T1ID for which the Name matches a specific string.
SELECT`Table2`.`T1ID`,
`Table2`.`Value`,
`Table2`.`Date`,
`Table1`.`Name`,
FROM `Table1`
INNER JOIN `Table2` ON `Table2`.`T1ID` = `Table1`.`T1ID`
WHERE `Table1`.`Name` LIKE 'Smith'
but this returns the value for several dates for the same T1ID.
How do I get only the latest value by Date?
Edit:
I am using MySQL 5.5.8
If I've understodd the question correctly:
Assuming MySQL:
SELECT`Table2`.`T1ID`,
`Table2`.`Value`,
`Table2`.`Date`,
`Table1`.`Name`
FROM `Table1`
INNER JOIN `Table2` ON `Table2`.`T1ID` = `Table1`.`ID`,
(SELECT T1ID, MAX(Date) AS 'Date' FROM Table2 GROUP BY T1ID) Table3
WHERE
`Table3`.`T1ID` = `Table2`.`T1ID`
AND
`Table3`.`Date` = `Table2`.`Date`
AND
`Table1`.`Name` LIKE 'Smith'
EDIT: Updated the code to bring back the correct result set. Removed MSSQL answer as it wasn't relevant
You have two options.
select t1.t1id, max(t1.Name) Name, max(t2.date) Date,
(select Value from table2 t22
where t22.date = max(t2.date) and t22.t1id = t2.t1id) Value
from table1 t1 left join table2 t2 on t1.t1id = t2.t1id
where Name like '%Smith%'
group by t2.t1id order by 2
OR
select mx.t1id, mx.Name, mx.Date, t2.Value
from
(
select t1.t1id, max(t1.Name) Name, max(t2.date) Date
from table1 t1 left join table2 t2 on t1.t1id = t2.t1id
where Name like '%Smith%'
group by t2.t1id
) mx left join table2 t2 on (t2.t1id = mx.t1id and t2.date = mx.date)
order by 2
Both will produce the same result. The first one takes less code but you might have performance issues with a huge set of data. The second one takes a little more code, but it is also a little more optimized. Notes on the JOIN option:
If you go LEFT JOIN (as the example shows), items in Table1 with no correspondent records on Table2 will be displayed in the result, but the values in columns Date and Value will be NULL
If you go INNER JOIN, items in Table1 with no correspondent records on Table2 will not be displayed.
EDIT
I missed one of the requirements, which was the Name matching a specific string. The code is now updated. The '%' acts like a wildcard, so it will match names like 'Will Smith' and 'Wail Smithers'. If you want a exact match, remove the wildcards ('%').
Add this to your SQL:
ORDER BY 'Date' DESC LIMIT 1