Find similar/related data, order by match count - mysql

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!

Related

Count rows nin a column from one table do not appear in another table

I have TableA with 5 rows in column siteID ( so 5 different sites).
I have TableB that stores userIDs and which sites they have access to. I need to take all 5 siteIDs from TableA and check to see if any of the siteIDs are NOT in TableB for a specific user.
I'm trying something similar to this pseudocode but not sure how the syntax should go:
SET #invalidSites = (
SELECT COUNT(*)
FROM userSiteAccess AS usa
RIGHT JOIN customer.sitesVsUsers AS cust
ON usa.listOfSites = cust.siteID
WHERE cust.siteID IS NULL);
EXAMPLE:
TABLE A
listOfSites
1
2
3
TableB
userID siteAccess
50 3
The count should return 2 as the list of sites has 2 additional rows (site 1 and site 2) but the user only has access to site 3.
You need to use LEFT JOIN rather than RIGHT JOIN, and you need to specify the user ID in the ON condition.
SELECT COUNT(*)
FROM userSiteAccess AS usa
LEFT JOIN sitesVsUsers AS cust
ON usa.listOfSites = cust.siteID AND cust.userId = 2
WHERE cust.siteID IS NULL
DEMO
With NOT EXISTS:
select count(*) counter
from tablea a
where not exists (
select 1 from tableb
where userid = 50 and siteaccess = a.listofsites
)

MySQL query to count occurence of specific column value relating to id column

I'm wondering how to do a MySQL query that counts how many times a certain column value appears. For example I have a table with various columns, i'm interested in the id and prop_id columns. I want to count how many times a prop_id is 2, in relation to each id.
id - prop_id
1 - a
1 - b
2 - c
3 - b
3 - b
3 - c
The results of my query would be:
id - count(prop_id)
1 - 1
2 - 0
3 - 2
I'm having trouble translating this into a query despite it probably being fairly simple. I'm sure my terminology is off too, my knowledge of MySql is fairly basic, for now.
Since you want to list all the id values, you need to complicate your query by retrieving all ids in a subquery and left join that on your table:
select t.id, count(t2.id) as props_count
from (select distinct id from table) t
left join table t2 on t.id=t2.id and t2.prop_id='b'
group by t.id

MySQL Left Join with no matches on Table B, has no ID on Table A

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.

COUNT(*) return wrong number

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.

Getting value of Mapping table IDs when value is from same column

Im really struggling to get my head around what should be simple,
I have two tables, one contains records the other is a mapping table.
records
ID Title Description
1 record 1 desc 1
2 record 2 desc 2
3 record 3 desc 3
4 record 4 desc 4
mapping table
ID1 ID2
1 3
2 4
What I want to do is get the two titles of each row in the mapping table. So the above would output
record 1 record 3
record 2 record 4
Im missing something really obvious, trying multiple joins results in errors trying to link the same table twice.
The following returns NUll
SELECT records.title FROM mapping
LEFT JOIN records
ON mapping.ID1 = records.id
AND mapping.ID2 = records.id
try this one: (UNTESTED)
SELECT b.Title as TitleA,
c.Title as TitleB
FROM mapping a
INNER JOIN records b
on a.ID1 = b.ID
INNER JOIN records c
on a.ID2 = c.ID