I want to count how frequent values appear in certain columns and create a new table, with the values as columns and the frequencies as data. Example:
create table users
(id number primary key,
name varchar2(255));
insert into users values (1, 'John');
insert into users values (2, 'Joe');
insert into users values (3, 'Max');
create table meals
(id number primary key,
user_id number,
food varchar2(255));
insert into meals values (1, 1, 'Apple');
insert into meals values (2, 1, 'Apple');
insert into meals values (3, 1, 'Orange');
insert into meals values (4, 1, 'Bread');
insert into meals values (5, 1, 'Apple');
insert into meals values (6, 2, 'Apple');
insert into meals values (7, 2, 'Bread');
insert into meals values (8, 2, 'Bread');
insert into meals values (9, 2, 'Apple');
insert into meals values (10, 3, 'Orange');
insert into meals values (11, 3, 'Bread');
insert into meals values (12, 3, 'Bread');
So I got different users and their meals (here Bread, Apple and Oranges). For every user I want to know how often did he eat the different food. The following query does exactly what I want:
select
(select count(id) from meals where meals.user_id = users.id and meals.food = 'Apple') as count_apple,
(select count(id) from meals where meals.user_id = users.id and meals.food = 'Orange') as count_orange,
(select count(id) from meals where meals.user_id = users.id and meals.food = 'Bread') as count_bread
from users;
The problem is, this is REALLY slow, especially when I got more than 100.000 users and dozens of different foods. I am sure that there is a faster way, but I am not experienced enough in SQL to solve this problem.
If you’re using 11g, then you can use the
pivotoperator, like so:Otherwise you’ll have to do a manual pivot:
In either case, these should be faster than your original approach as you’re only accessing the
mealstable once.