简体   繁体   中英

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 SELECT s 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 |
+--------+--------+---------------------------+

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM