It seems I don't get it something. Please consider this query
SELECT COUNT(*) AS `numrows`
FROM (`exp_channel_titles` ch)
JOIN `exp_channel_data` cd ON `cd`.`entry_id`=`ch`.`entry_id`
LEFT JOIN `exp_matrix_data` md ON `md`.`entry_id`=`ch`.`entry_id` and field_id = 14
LEFT JOIN `exp_assessment_users` au ON `au`.`entry_id`=`ch`.`entry_id`
WHERE ch.channel_id = 4 GROUP BY `ch`.`entry_id`
it returns 2
but if I change it to
SELECT *
FROM (`exp_channel_titles` ch)
JOIN `exp_channel_data` cd ON `cd`.`entry_id`=`ch`.`entry_id`
LEFT JOIN `exp_matrix_data` md ON `md`.`entry_id`=`ch`.`entry_id` and field_id = 14
LEFT JOIN `exp_assessment_users` au ON `au`.`entry_id`=`ch`.`entry_id`
WHERE ch.channel_id = 4 GROUP BY `ch`.`entry_id`
result is 1 row only. How so?
You're grouping, which means internally matching rows are collapsed into a single entity. e.g. consider a fake table like this:
field
-----
a
a
Yes, a one field table, with two records, both of which have the value a in them.
SELECT *
FROM table
GROUP BY field
group by will find all fields which have the same value, and collapse them down into a SINGLE record, so your two records of a become one row in the result set, and you end up with
field
-----
a
But doing
SELECT count(*)
FROM table
GROUP BY field
changes things. Now the DB will literally count how many records were collapsed down into the single row of result set. So you still get a SINGLE row in the result set, which contains a count of how many rows were collapsed by the group by:
count(*)
--------
2
One row, with a value of 2, because there were two rows with a.
Now if you had a table with more records:
field
-----
a
a
b
c
c
c
You would get:
SELECT * ... GROUP BY field
field
-----
a
b
c
SELECT count(*), field ... GROUP BY field
count(*) field
----------------
2 a
1 b
3 c
again, 3 rows of results, but note how the count represents how many of each grouped field there are in the original table.
Related
I try doing somethin like this:
Table A
NameID | name | other rows
1 | name1
2 | nameA
3 | nameX
Table B
UniqueID | NameID | other rows
1 | 1
2 | 2
3 | 6
4 | 17
5 | 22
No I want to do a select like this:
SELECT tablea.ID, tablea.name, tableb.*
FROM tablea
LEFT JOIN tableb ON tablea.ID = tableb.ID
WHERE
tablea.ID != '0'
I search now for the ID and the name.
I get allways the name, but not allways the ID, only if the ID is in table B also. why?
My result is like this:
ID | name
1 | name1
2 | nameA
NULL | nameX
I have this situation:
I have in TABLE A films (with names, datas, etc.). In table B I have
ratings of these movies. Now I search with a form and want to see all movies, that have an incomplete rating, or no ratings at all, or any film despite of it has or not ratings.
With a LEFT JOIN on TABLE A (all movies) and with the addition ON-Condition I search if the movie has a rating or not (is or is not in TABLE B).
My result get me the name of the movie, allways. But if the movieID is not in table B (= no ratings recorded), I do not get the ID of the Movie in table A in the result.
So not my entire result is NULL only the movieID, I can pull any other DATA out of TABLE A for this movie, but not the ID.
so why?
Is it not possible to ask for the tablea.ID, if the ID is in the ON - term?
Left join will show all rows form the first table and add data from the second table when a matching rows is found.
If no matching row is found, left join will return null (which means "unknown") for those rows.
If you want to discard rows from you result that have no matching row in the other table, you have to use "inner join" instead of "left join".
Check visual representation of joins for more info: https://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins
The solution is, to set an alias for the row in table one, which is duplicated in the second table and has due to no "rows" in second table the outcome NULL.
If I put an alias into it, I can select it and LEFT JOIN will do the rest.
What to know: mysql_fetch_object will always select the last mention of a row, if the row name is identic in other tables of the select. In my case I LEFT JOIN a second table with the same row-name. Due to LEFT JOIN I have no results on the ON condition and the correct outcome for my query is NULL.
there are students and their marks:
Student:
ID NAME
1 a
2 b
3 c
4 d
Mark:
ID STUDENT_ID MARK
1 1 4
1 1 2
1 3 4
I would like to get an ordered list about their average marks, to get:
a, (4+2)/2
b, -,
c, 4/1
d, -
I must not calculate it while SELECT-ing, not even store it in a column in Students table. The interesting part is when I would want to order and limit (paging) the result. To have a correct ordering, I must know all averages - so I wont use SELECT query without LIMIT. But how to? Ideally, ordering by ID or NAME is easy.
You can order by an expression, including a subquery:
order by (select avg(mark) from marks m where m.student_id = s.id)
I'm not sure I would want to do this as part of paging, unless the underlying data is pretty small.
You can get users with their average marks with this query:
SELECT student.*, AVG(mark.mark) as average_mark
FROM users
LEFT OUTER JOIN mark m on m.student_id= users.id
GROUP BY users.id
ORDER BY average_mark DESC
I had lots of tables and had performed multiple join lefts all the tables without incorrect or duplicate results. One of my table is multi-values, can accept duplicate same ids. When I left joins all the tables, the result shows correct, but that particular column show one of the values from multi-values table.
Currently I'm doing filtering the multi-values table, but the result is unforseen because it only output single one of the value from multi-values table.
Menu Table
id cuisine_id
1 1
CuisineMenu Table (Multi-values / Accept duplicated menu's id)
cuisine_id menu_id
1 1
2 2 (Ignore)
3 1
Query
SELECT * FROM menu
LEFT JOIN (
SELECT *
FROM cuisinemenu
GROUP BY menu_id
) cuisinemenu ON cuisinemenu.menu_id = menu.id
WHERE ( cuisine_id = '3')
Output
Without Where Clause
id cuisine_id
1 1
With Where Clause
Empty
Expected Result (With Where Clause)
id cuisine_id
1 3
You can use simple LEFT JOIN, try below:
SELECT m.*
FROM Menu m LEFT JOIN CuisineMenu cm ON m.id = cm.menu.id
WHERE cm.cuisine_id = 3;
This should result in 1 row.
Change your sql code from following:
SELECT *
FROM cuisinemenu
GROUP BY menu_id
to this:
SELECT *
FROM cuisinemenu
GROUP BY cuisine_id
the first one shows only menu_id without showing the cuisine_id.
My data is spread across multiple tables. Each table looks like:
id | value
And there's one master table:
id | type
Now I want to select all id's, for a given id, that have at least one value-match in one of the tables, ordered by the number of matches, descending.
Example:
TableMaster (id,type):
1,typeA
2,typeA
3,typeA
4,typeA
5,typeB
TableA (id,value):
1,A
2,B
3,B
4,C
5,D
TableB (id,value):
1,Y
2,X
3,X
4,X
5,X
TableC (id,value):
1,K
2,L
3,L
4,L
5,M
The wanted sql statement for id=2 and type=typeA returns:
id
3 (1 match in TableA B=B, 1 match in TableB X=X, 1 match in TableC L=L => 3 matches)
4 (1 match in TableB X=X, 1 match in TableC L=L => 2 matches)
id=5 is not returned, because it's typeB.
Is there a efficient way to compare all tables without using a subselect for each table join and how do I count the matches, so I can use the value for ORDER BY?
Thanks!
SELECT art.*,arg. FROM rd_articles AS art
LEFT JOIN rd_argument AS arg ON art.cat=arg.id WHERE art.enabled=1 ORDER BY art.id DESC
LIMIT 10
This is simple join query
Article table structure is
ID cat Description Date
1 1 Abc 08-01-2014
2 1 Aaa 10-01-2014
3 2 Abcv 11-01-2014
4 3 Aaa 12-01-2014
5 3 Aaa 14-01-2014
Arguments table is
ID Name
1 A
2 B
3 C
I want pick last updated(Date) one item from each cat.
How ?
This assumes that the enabled column is in rd_articles:
SELECT art.*, arg.*
FROM (
SELECT * FROM rd_articles
INNER JOIN (
SELECT cat, MAX(date) AS maxdate
FROM rd_articles
WHERE enabled = 1
GROUP BY cat
) md ON rd_articles.cat = md.cat AND rd_articles.date = md.maxdate
) art
LEFT JOIN rd_argument AS arg ON art.cat = arg.id
The innermost query gets the maximum date for each category, then joins it to the rd_articles table to get only those rd_articles rows that have the latest date for each article. That becomes the cat alias, which is then left-joined to the arguments table just like in your original query. You can add the LIMIT 10 at the end if needed; I wasn't sure what to do with that.
Note that if there's a tie for a category's latest date, you'll get more than one row for each category. If a tie could happen you'll need to break the tie somehow, for example by using the description or the ID. Let me know if that's the case and I'll update my answer.
SELECT ART.*, ARG.*
FROM ARTICLE AS ART
INNER JOIN RD_AGRUEMENT AS ARG
ON ARG.ID = ART.ID
WHERE (ID, DATE) IN
(SELECT ID, MAX(DATE) FROM ARTICLE GROUP BY ID)