Finding records that occur most commonly together in SQL - mysql

I have a table of ingredients:
ing_id, ing_name
1 , ing1
...
a table of recipes:
rec_id, rec_name
1 , rec1
...
and a table showing the connection between the two:
id, ing_id, rec_id
1, 1, 1
2, 1, 2
3, 2, 1
4, 3, 3
...
How can I find the ingredients that most commonly appear in the same recipe?

You can use a self join and group by:
select c1.ing_id, c2.ing_id, count(*)
from connections c1 join
connections c2
on c1.rec_id = c2.rec_id and c1.ing_id < c2.ing_id
group by c1.ing_id, c2.ing_id
order by count(*) desc;
If you actually want the names instead of the ids, you'll need two more joins to bring them in.

Related

How to count the number of entries in the list when requesting Select?

I apologize for the possible incorrectness in the presentation, I use a translator. Let's say there is a users table in which there is an id field. And there is a list that lists the id numbers and some of them are repeated. My query
select id, count(*)
from users
where id in (3, 10, 10, 10)
group by id;
returns the following 3 - 1, 10 - 1. And I would like to get 3 - 1, 10 - 3, and so on. Is it possible to get it somehow?
UPD.
The data in the list (3, 10, 10, 10) is just an example, the exact number of digits is not known because they are returned from another question.
You would need to use a join. You can put the values in a derived table for this:
select id, count(*)
from users u join
(select 3 as id union all
select 10 as id union all
select 10 as id union all
select 10 as id union all
) i
using(id)
group by id;

How to return records in MySQL with "custom" ordering

I'm trying to return records based on their IDs in MySQL without ordering.
But when I run the query it will order them from the lowest ID number to highest one.
SELECT * FROM events WHERE id=11 or id=4 or id=9 or id=5
The result will like these: 4,5,9,11
How can return like this : 11,4,9,5
Try using ORDER BY FIELD (id, ...):
SELECT *
FROM events
WHERE id IN (4, 5, 9, 11)
ORDER BY FIELD (id, 11, 4, 9, 5)
Demo
As to why your current query is showing the 4,5,9,11 order, even without your using an explicit ORDER BY clause, one explanation is that the id column is the clustered primary key for your table. In that case, the data would actually be stored in this order on disk, and when selecting, this would be the natural order returned.
Edit:
On other database vendors, which don't support FIELD, we can order using a CASE expression:
SELECT *
FROM events
WHERE id IN (4, 5, 9, 11)
ORDER BY
CASE WHEN id = 11 THEN 1
WHEN id = 4 THEN 2
WHEN id = 9 THEN 3
WHEN id = 5 THEN 4
ELSE 5 END;
I believe you want to use FIELD()
SELECT * FROM events WHERE id=11 or id=4 or id=9 or id=5
ORDER BY FIELD(id, 11,4,8,5)
Or the more ANSI SQL method (works also for other databases vendors)
SELECT
events.*
FROM (
SELECT
11 AS id
, 1 AS position
UNION ALL
SELECT
4 AS id
, 2 AS position
UNION ALL
SELECT
8 AS id
, 3 AS position
UNION ALL
SELECT
5 AS id
, 4 AS position
) AS sorting
INNER JOIN
events
ON
sorting.id = events.id
ORDER BY
sorting.position ASC
Or the better ANSI SQL like it should (works also for other databases vendors)
SELECT * FROM events WHERE id=11 or id=4 or id=9 or id=5
ORDER BY CASE WHEN id = 11 THEN 1
WHEN id = 4 THEN 2
WHEN id = 8 THEN 3
WHEN id = 5 THEN 4
ELSE 5
END
** Updateded
As you want fixed order, you can use ORDER BY FIELD :
SELECT * FROM events
WHERE id IN (4, 5, 9, 11)
ORDER BY FIELD (id, 11, 4, 9, 5)

mysql alternative for key value query with multiple self joins

I have a table with numerical filters (age, weight, salary, etc).
Since I do not know the filters in advance I have to use key value pairs:
company
id, name
1, ACME
users
id, name, company_id
1, jon doe, 1
filters
id, user_id, filter, value
1, 1, 'age', 30
2, 1, 'weight', 82
3, 2, 'salary', 50000
My queries retrieve users that belong to a specific company and match any combination of one or many filter criteria: e.g.
SELECT COUNT(*) FROM users, filters as age, filters as weight
WHERE age.user_id = users.id
AND weight.user_id = users.id
AND age.filter = 'age'
AND age.value = 30
AND weight.filter = 'weight'
AND weight.value = 100
AND users.company_id = 1
The table contains many million rows and I have tried all possible index combinations for the filter, value, user_id columns.
The queries take many seconds to minutes.
Is there a better solution for my usecase?
Is this what you want?
select f.user_id
from filters f
where (f.filter, f.value) in ( ('age', 20), ('weight', 100) )
group by f.user_id
having count(distinct f.filter) = 2;

MySQL count complex query results

I'm looking for a query to know how many times the value of a field is repeated in a select?
I prove with:
$queryIds ="select id,idpol,count(idpol) as qid from table WHERE id IN($idafectades) group by idpol";
But I'm looking for something like:
id, idpol, count_idpol (number of times that each idpol's value appears in the group of rows)
1, 1000, 3
2, 1000, 3
3, 1002, 1
4, 1003, 2
5, 1003, 2
6, 1000, 3
Thanks
This is one way without using a windowed set. Generate a set of data containing the counts grouped by the IDPOL, then join it back to the base set of each ID and IDpol.
SELECT foo.id, foo.idpol, B.cnt
FROM foo
INNER JOIN (SELECT count(*) cnt, IdPOL FROM Foo GROUP BY IDPOL) B
on Foo.IDPOL = B.IDPOL
SQL Fiddle

Merging data from another table column into 1 seperated column

I've got 3 tables (tbl_reservations / tbl_series / tbl_rooms), how can i return a with the matching rooms merged into 1 column separated by a space or a "|", along with data from the reservation table?
tbl_reservations
------------
id, startdate, enddate, series
1, 2014-05-20, 2014-05-22, 1
2, 2014-05-24, 2014-05-25, 2
tbl_series
--------
reservation, room
1, 1
1, 3
1, 4
2, 1
2, 2
tbl_rooms
-----
id, name
1, room a
2, room b
3, room c
4, room d
When i need returning is something like this...
startdate, enddate, rooms
2014-05-20, 2014-05-22, 1|3|4
2014-05-24, 2014-05-25, 1|2
as mentionned, use GROUP_CONCAT.
You don't seem to need tbl_rooms by the way...
select r.id,
r.startdate,
r.enddate,
GROUP_CONCAT(s.room order by s.room separator '|' ) as rooms
from tbl_reservations r
join tbl_series s on s.reservation = r.series
group by r.id, r.startdate, r.enddate
see SqlFiddle
do you want to have all this in one column? in which case this is a duplicate:
MySQL, Concatenate two columns
or
MySQL combine two columns and add into a new column
or do you want to have a table after the query which will have each individual reservation in its own row. in which case you need to look at using the
INNER JOIN
functionality something like this:
Select * from tbl_rooms t1
inner join
(select * from tbl_reservations st1
inner join
(select * from tblseries) st2
on st1.id=st2.reservation
) t2 on t1.id = t2.room