Selecting the most popular destination of my database on mysql - mysql

I've created 3 tables:
CREATE TABLE participe
(
IDadherent INTEGER,
IDsortie INTEGER,
CONSTRAINT pk2 PRIMARY KEY (IDadherent, IDsortie)
);
CREATE TABLE sortie
(
IDsortie INTEGER PRIMARY KEY,
jour DATE,
Latitude_sortie FLOAT,
Longitude_sortie FLOAT
);
CREATE TABLE adherent
(
IDadherent INTEGER PRIMARY KEY,
nom VARCHAR(30),
prenom VARCHAR(30)
);
TL;DR:
Table 1) Adherent (this is the people potentially going to a set of destinations with adherentID as a primary key)
Table 2) Sortie (this is the table with the potential destinations with destinationID as a primary key)
Table 3) Participe (this table links both primary keys: AdherentID and destinationID
If I select the content of the table "participe" I get something like this:
+----------+------------+
| IDsortie | IDadherent |
+----------+------------+
| 5 | 1 |
| 5 | 3 |
| 5 | 5 |
| 4 | 2 |
| 3 | 1 |
| 3 | 4 |
| 3 | 5 |
| 2 | 3 |
| 2 | 5 |
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 0 | 6 |
+----------+------------+
I've attempted to order the above table and get a new table with the most popular destinations (IDsortie), expecting to get something like this:
+----------+----------------+
| IDsortie | Numeroadherent |
+----------+----------------+
| 5 | 3 |
| 4 | 1 |
| 3 | 3 |
| 2 | 2 |
| 1 | 3 |
| 0 | 1 |
+----------+----------------+
In order to achieve that glorious table I've used these queries (and failed miserably):
SELECT IDsortie, IDadherent
FROM participe
ORDER BY IDsortie DESC;
SELECT COUNT(IDsortie)
FROM participe
GROUP BY IDadherent
ORDER BY COUNT(IDadherent) ASC;
SELECT COUNT(IDsortie)
FROM
(SELECT COUNT(*) AS IDsortie
FROM participe
GROUP BY IDadherent) AS Results
One of the mysql mods has very kindly redirected me to other similar questions but I don't understand their answers, could someone please walk e through this (sorry for the inconvenience).

It looks like you want a single query:
SELECT IDsortie, COUNT(*) as Numeroadherent
FROM participe
GROUP BY IDsortie DESC
ORDER BY IDsortie DESC;
I'm not quite sure what your queries have to do with answering the question. Hence, it is unclear what your confusion is. The answer to your question is a simple GROUP BY query.

Try using the below query,
SELECT IDSortie
, COUNT(IDSortie) [Numeroadherent]
FROM Participe
GROUP
BY IDSortie
ORDER
BY IDSortie;

Related

Random record from the table

I have customer table with 10 columns. In the table customer id is repeated. I need to take only one record every customer but randomly.
Let suppose customer table contain total 10000 records. But distinct customers is only 500.
So i need only 500 distinct customer data randomly.
I am using mysql 5.7.
Consider the following...
SELECT * FROM my_table;
+----+-------------+
| id | customer_id |
+----+-------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 3 |
| 4 | 5 |
| 5 | 3 |
| 6 | 2 |
| 7 | 1 |
| 8 | 4 |
| 9 | 5 |
| 10 | 2 |
| 11 | 3 |
| 12 | 1 |
| 13 | 4 |
+----+-------------+
SELECT id
, customer_id
FROM
( SELECT id
, customer_id
, CASE WHEN #prev=customer_id THEN #i:=#i+1 ELSE #i:=1 END i
, #prev:=customer_id
FROM
( SELECT id
, customer_id
FROM my_table
ORDER
BY customer_id
, RAND()
) x
JOIN (SELECT #prev:=null,#i:=0) vars
) n
WHERE i = 1
ORDER
BY customer_id;
-- sample output, different each time --
+----+-------------+
| id | customer_id |
+----+-------------+
| 12 | 1 |
| 10 | 2 |
| 3 | 3 |
| 8 | 4 |
| 9 | 5 |
+----+-------------+
You do not want to ORDER BY RAND() because that will be extremely slow for a large table because it will actually sort all of those random records.
Instead pick a random int less than the number of rows in the table (random_num_less_than_row_count) and do this which is faster but not perfect.
SELECT * FROM atable LIMIT $random_num_less_than_row_count, 1
Or if u have a primary key that is an auto_increment you can pick a random int less than the highest id in the table (random_num_less_than_last_id) do the following which is pretty fast.
SELECT * FROM atable WHERE id >= $random_num_less_than_last_id ORDER BY id ASC LIMIT 1
I did a >= and an ORDER BY id ASC so that if you are missing ids you'll still get a result. But if you have many large gaps you need the slower first option above.
Not sure about it but it is a beginner level query which might to get the desired result
SELECT Distinct column FROM table
ORDER BY RAND()
LIMIT 500
PS: This code isn't in mysql 5.7. And if anyone have a better query more than happy to get corrected

MySQL: COUNT with implicit GROUP BY

I've been trying to guess how to solve my problem for some time and I cannot seem to find a solution, so I come to you, experts.
What I've got
A MySQL table with the following structure and values (as an example):
+----+---------+----------------+-----------------+--------------+
| id | item_id | attribute_name | attribute_value | deleted_date |
+----+---------+----------------+-----------------+--------------+
| 1 | 2 | action | call | NULL |
| 2 | 2 | person | Joseph | NULL |
| 3 | 2 | action | fault | NULL |
| 4 | 2 | otherattr | otherval | NULL |
| 5 | 5 | action | call | NULL |
| 6 | 5 | person | Mike | NULL |
| 7 | 5 | action | sprint | NULL |
| 8 | 8 | action | call | NULL |
| 9 | 8 | person | Joseph | NULL |
| 10 | 8 | action | block | NULL |
| 11 | 8 | action | call | NULL |
+----+---------+----------------+-----------------+--------------+
What I need
I'd like a query to return me how many items (item_id) have at least one attribute_name with 'action' and with attribute_value as 'call', grouped by 'person', but only counting one of them.
So, if - like in the example, at ids 8 and 11 - there is an item_id with two "action" = "call", only COUNT one of them.
The query should return something like this:
+--------+--------------+
| person | action_calls |
+--------+--------------+
| Joseph | 2 |
| Mike | 1 |
+--------+--------------+
The problem
The problem is that I don't know how to do that in a simple way that would not make a huge performance increment, as this query will be returning and searching along a lot of rows - and returning a lot of them, too, in some cases.
The only thing that comes to my mind is with nested and nested queries, and I'd like to avoid that.
If I make a COUNT(DISTINCT), it only returns '1' in 'Joseph', because the value is always 'call', and if I GROUP BY b.item_id, it returns me two rows with Joseph (and, in this case too, it counts both 'call' attributes, so it wouldn't be the solution neither).
What I've tried
The query that I've tried is the following:
SELECT a.attribute_value AS person, COUNT(b.attribute_value) AS action_calls
FROM `er_item_attributes` a, `er_item_attributes` b
WHERE a.attribute_name = 'person'
AND b.item_id IN (SELECT DISTINCT item_id FROM er_item_parents WHERE parent_id IN (1234,4567))
AND b.item_id = a.item_id
AND b.attribute_name = 'action'
AND b.attribute_value = 'call'
AND b.deleted_date IS NULL
GROUP BY a.attribute_value, b.attribute_name
Additional information
The item_id, as you can see, will be also chosen from an inner WHERE clause, because the ones that are valid are in another table (just like a parent - son table). The parent_id numbers are for an example and are not relevant.
To sum up
How can I make a COUNT in MySQL to behave like a COUNT GROUP BY without nesting SELECTs that could deteriorate the performance?
If any further information was needed, comment it and I will try to add it.
Also, any recommendations on another way to query the information needed to improve performance will be welcome.
Thank you everyone for your time and help!
Kind regards.
Try this!
SELECT attribute_value AS person, COUNT(*) FROM `stack_1239`
WHERE item_id IN (
SELECT item_id FROM `stack_1239` WHERE attribute_name = 'action' AND attribute_value = 'call'
)
AND attribute_name = 'person'
GROUP BY person;
:)
DROP TABLE IF EXISTS eav_hell;
CREATE TABLE eav_hell
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,entity INT NOT NULL
,attribute VARCHAR(20) NOT NULL
,value VARCHAR(20) NOT NULL
);
INSERT INTO eav_hell
VALUES
( 1 ,2 ,'action','call'),
( 2 ,2 ,'person','Joseph'),
( 3 ,2 ,'action','fault'),
( 4 ,2 ,'otherattr','otherval'),
( 5 ,5 ,'action','call'),
( 6 ,5 ,'person','Mike'),
( 7 ,5 ,'action','sprint'),
( 8 ,8 ,'action','call'),
( 9 ,8 ,'person','Joseph'),
(10 ,8 ,'action','block'),
(11 ,8 ,'action','call');
SELECT e1.entity
, e1.value person
, e2.value action
, COUNT(*)
FROM eav_hell e1
LEFT
JOIN eav_hell e2
ON e2.entity = e1.entity
AND e2.attribute = 'action'
AND e2.value = 'call'
WHERE e1.attribute = 'person'
GROUP
BY entity
, person
, action;
+--------+--------+--------+----------+
| entity | person | action | COUNT(*) |
+--------+--------+--------+----------+
| 2 | Joseph | call | 1 |
| 5 | Mike | call | 1 |
| 8 | Joseph | call | 2 |
+--------+--------+--------+----------+
Edit:
SELECT e1.value person
, e2.value action
, COUNT(DISTINCT e1.entity)
FROM eav_hell e1
LEFT
JOIN eav_hell e2
ON e2.entity = e1.entity
AND e2.attribute = 'action'
AND e2.value = 'call'
WHERE e1.attribute = 'person'
GROUP
BY person
, action;
+--------+--------+---------------------------+
| person | action | COUNT(DISTINCT e1.entity) |
+--------+--------+---------------------------+
| Joseph | call | 2 |
| Mike | call | 1 |
+--------+--------+---------------------------+

sum count as a column in mysql

I have a table:
id | type | subtype
how shall I create a query to output as following
type1 | subtype1 | count-subtype1 | count-type1
type1 | subtype2 | count-subtype2 | count-type1
type2 | subtype3 | count-subtype3 | count-type2
type2 | subtype4 | count-subtype4 | count-type2
Namely subtotal as a column in output.
With no "WITH ROLLUP"
To awnser this query sucessfully (and this is where some awsers fails) is that you need to know what a roollup does. If you don't want to perform a "manual" sql rollup, there is another answer around which solves your query.
what do you need is two queries, one to count the subtypes within the types and another to count the types.
first count the subtypes (and lets call this query s).
select count(*) count_subtype, type, subtype from Foo group by type, subtype;
and another query to count the types (and lets call this query t).
select count(*) count_type, type from Foo froup by type
and now you need to merge the two queries:
select t.type, s.subtype, s.count_subtype, t.conttype from
(select count(*) count_subtype, type, subtype from Foo group by type, subtype) as s
join
(select count(*) count_type, type from Foo froup by type) as t
on (t.type=s.type);
Assuming that I have this structure of table:
CREATE TABLE `test` (
`id` int(11) NOT NULL auto_increment,
`type` varchar(128) default NULL,
`subtype` varchar(128) default NULL,
KEY `id` (`id`));
And this data:
INSERT INTO `test` VALUES (1,'a','1'),(2,'a','2'),(3,'a','3'),(4,'a','4'),(5,'b','4'),
(6,'c','4'),(7,'c','1'),(8,'c','2'),(9,'c','2');
I can do this:
SELECT test.type, test.subtype, count(test.subtype) as countsubtype, testbytype.counttype
FROM (test)
LEFT JOIN (SELECT type, count(type) AS counttype FROM test group by type) AS testbytype ON test.type = testbytype.type
GROUP by type, subtype;
+------+---------+--------------+-----------+
| type | subtype | countsubtype | counttype |
+------+---------+--------------+-----------+
| a | 1 | 1 | 4 |
| a | 2 | 1 | 4 |
| a | 3 | 1 | 4 |
| a | 4 | 1 | 4 |
| b | 4 | 1 | 1 |
| c | 1 | 1 | 4 |
| c | 2 | 2 | 4 |
| c | 4 | 1 | 4 |
+------+---------+--------------+-----------+
Query:
SELECT type, subtype, sum(type), sum(subtype) from table_name GROUP BY id

how to merge 2 tables with one request

so i got 2 tables with following structure:
CREATE TABLE courses(
id bigint not null auto_increment,
title varchar(255) default '',
primary key(id)
);
CREATE TABLE course_dates(
id bigint not null auto_increment,
course_id bigint,
`date` date,
key idx(course_id,date),
primary key(id)
);
so courses are stored in first table and course dates in second (each course can have unlimited number of dates)
i need to get all course rows (with all its dates) at one time using one query
for example, if i have tables with such data:
courses:
id | title
1 | course#1
2 | course#2
course_dates:
id | course_id | date
1 | 1 | 2012-12-25
2 | 1 | 2012-12-27
3 | 1 | 2012-12-31
4 | 2 | 2012-12-23
5 | 2 | 2012-12-30
then i need result rows like this:
id | course_id | date | title
1 | 1 | 2012-12-25 | course#1
2 | 1 | 2012-12-27 | course#1
3 | 1 | 2012-12-31 | course#1
4 | 2 | 2012-12-23 | course#2
5 | 2 | 2012-12-30 | course#2
A simple INNER JOIN will do.
SELECT b.*, a.title
FROM Courses a
INNER JOIN Courses_Dates b
ON a.id = b.Course_ID
SQLFiddle Demo
SQLFiddle Demo (with ORDER BY clause)
To learn more about joins, see the link below
Visual Representation of SQL Joins

How to speed up this slow query?

I'm having some issue with this query that seems to be too slow...
SELECT SUM(c) FROM (
(
SELECT COUNT( id ) AS c
FROM QueueOne
WHERE id = my_id
)
UNION ALL (
SELECT COUNT( id ) AS c
FROM QueueTwo
WHERE id = my_id
)
UNION ALL (
SELECT COUNT( id ) AS c
FROM QueueThree
WHERE id = my_id
)
UNION ALL (
SELECT COUNT( id ) AS c
FROM QueueFour
WHERE id = my_id
)
) AS d
It is actually quite simple :
QueueOne, QueueTwo, QueueThree, QueueFour
Are four queue with different type of column and unfortunately can not be squizzed to One column.
This query give us the number of all waiting queue from every Queue table.
It seems that is too slow for mysql since it log it on the slow-query.log file
Any help would be appreciated.
EDIT
Here's the explain :
+----+--------------+-------------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+-------------------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 4 | |
| 2 | DERIVED | QueueOne | ref | ID | ID | 4 | | 1 | Using index |
| 3 | UNION | QueueTwo | ref | ID | ID | 4 | | 1 | Using index |
| 4 | UNION | QueueThree | ref | ID | ID | 4 | | 1 | Using index |
| 5 | UNION | QueueFour | ref | ID | ID | 4 | | 1 | Using index |
| NULL | UNION RESULT | <union2,3,4,5> | ALL | NULL | NULL | NULL | NULL | NULL | |
+----+--------------+-------------------+------+---------------+------+---------+------+------+-------------+
6 rows in set (0.82 sec)
EDIT 2:
A little more information, some tables have almost 15 000 000 records
Add an index on id, and rewrite into count(*)
SELECT SUM(c)
FROM ((SELECT COUNT(*) AS c
FROM queueone
WHERE id = my_id)
UNION ALL
(SELECT COUNT(*) AS c
FROM queuetwo
WHERE id = my_id)
UNION ALL
(SELECT COUNT(*) AS c
FROM queuethree
WHERE id = my_id)
UNION ALL
(SELECT COUNT(*) AS c
FROM queuefour
WHERE id = my_id)) AS d
UPDATE
You should also look into parallelization and partitioning
Other benefits usually associated with partitioning include those in the following list. These features are not currently implemented in MySQL Partitioning, but are high on our list of priorities.
Queries involving aggregate functions such as SUM() and COUNT() can easily be parallelized. A simple example of such a query might be SELECT salesperson_id, COUNT(orders) as order_total FROM sales GROUP BY salesperson_id;. By “parallelized,” we mean that the query can be run simultaneously on each partition, and the final result obtained merely by summing the results obtained for all partitions.
Make sure that there is an index for id in each table.
Use count(*) instead of count(id). The result is the same as there are no null-values in the id in the result, but it doesn't have to do the check for null values.