简体   繁体   中英

MySQL Count Distinct value multiple column same row

I am new to MySQL and have been playing around with it recently.. I am here to see if someone can help me solve this issue I have been working on for the past few days. Basically I have the following Table

+------+----------+---------+----------+---------+
| City | Animal1  | Animal2 | Animal3  | Animal4 |
+------+----------+---------+----------+---------+
| ACY  | Lion     | Giraffe | Elephant | Gorilla |
| AMS  | Elephant | Gorilla | Gorilla  | Lion    |
| ATL  | Tiger    | Tiger   | Lion     | Tiger   |
| BYU  | Elephant | Tiger   | Elephant | Lion    |
| QNB  | Lemur    | Tiger   | Lemur    | Gorilla |
+------+----------+---------+----------+---------+

I am trying to find a logic that will only out put Cities with 3 or more of the same Animal.. in this case Atlanta with three Tiger

+------+----------+---------+----------+---------+
| City | Animal1  | Animal2 | Animal3  | Animal4 |
+------+----------+---------+----------+---------+
| ATL  | Tiger    | Tiger   | Lion     | Tiger   |
+------+----------+---------+----------+---------+


mysql> SELECT count(DISTINCT Animal1,Animal2,Animal3,Animal4) FROM zooAnimal;
+-------------------------------------------------+
| count(DISTINCT Animal1,Animal2,Animal3,Animal4) |
+-------------------------------------------------+
|                                               5 |
+-------------------------------------------------+  

I have been playing around with DISTINCT and GROUP BY without any luck, any help is appreciated.

Your table needs normalization. The existent table structure makes it hard and inefficient to query the table.

Having said that you can use a query like the following to get City codes having 3 or more of the same animal:

SELECT DISTINCT City
FROM (
   SELECT City, Animal1 AS Animal
   FROM mytable

   UNION ALL

   SELECT City, Animal2 AS Animal
   FROM mytable

   UNION ALL

   SELECT City, Animal3 AS Animal
   FROM mytable

   UNION ALL

   SELECT City, Animal4 AS Animal
   FROM mytable
) AS t
GROUP BY City, Animal
HAVING COUNT(*) >= 3

Edit: To get 2 + 2 matching records you can use;

SELECT City
FROM (
   SELECT City, Animal
   FROM (
      SELECT City, Animal1 AS Animal
      FROM mytable

      UNION ALL

      SELECT City, Animal2 AS Animal
      FROM mytable

      UNION ALL

      SELECT City, Animal3 AS Animal
      FROM mytable

      UNION ALL

      SELECT City, Animal4 AS Animal
      FROM mytable
   ) AS t
   GROUP BY City, Animal
   HAVING COUNT(*) >= 2) AS x
GROUP BY City
HAVING COUNT(*) >= 2

You can use the unpivoting trick (using cross join) to unpivot the table and then do aggregation like this:

select
    city,
    animal
from (
    select
        t.city,
        case x.i
            when 1 then Animal1
            when 2 then Animal2
            when 3 then Animal3
            when 4 then Animal4
        end animal
    from your_table t
    cross join (
        select 1 i union all
        select 2 i union all
        select 3 i union all
        select 4 i
    ) x
) t group by city, animal
having count(*) >= 3;

Note that this query reads the table only once.

Also, it would be way better to fix your design ie keep each animal in separate row.

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