简体   繁体   中英

SQL query to return most common, 2nd most common, 3rd most common occurrences

I can do this in Excel using a pivot table, but I'd like to figure out a way to do this directly from a single SQL query. Let's say I have a list of fruits and their freshness:

**Fruit   Freshness**
Banana  New
Banana  Ripe
Apple   Ripe
Orange  Old
Cherry  New
Orange  Ripe
Apple   Old
Banana  Old
Apple   New
Apple   New
Orange  Ripe
Banana  Old
Orange  New
Cherry  New
Cherry  Ripe

I want to count the "freshness" occurrences then rank them as the most frequent, 2nd most frequent, and so on. The result would look something like this:

**Fruit Most common 2nd most common 3rd most common**
Banana  New         Old             Ripe
Apple   Old         New             Ripe
Orange  Ripe        New             Old
Cherry  New         Ripe            NA

Is this possible in one query?

You can just use GROUP_CONCAT() aggregate function:

SELECT
  Fruit, GROUP_CONCAT(Freshness ORDER BY cnt DESC) as Common
FROM (
  SELECT Fruit, Freshness, COUNT(*) cnt
  FROM
    fruits
  GROUP BY
    Fruit, Freshness
) s

that will return values like:

Fruit  | Common
---------------------
Banana | New,Old,Ripe
Cherry | New,Ripe
...    | ...

but if you want to divide the result in three columns, you can combine the previous query and use SUBSTRING_INDEX() to extract the first, sencond, and third value from the comma separated values:

SELECT
  Fruit,
  SUBSTRING_INDEX(Common, ',', 1) AS most,
  CASE WHEN CommonLIKE '%,%'
       THEN SUBSTRING_INDEX(SUBSTRING_INDEX(Common, ',', 2), ',', -1) END AS second_most,
  CASE WHEN CommonLIKE '%,%,%'
       THEN SUBSTRING_INDEX(SUBSTRING_INDEX(Common, ',', 3), ',', -1) END AS third_most
FROM (
  SELECT
    Fruit, GROUP_CONCAT(Freshness ORDER BY cnt DESC) as Common
  FROM (
    SELECT Fruit, Freshness, COUNT(*) cnt
    FROM
      fruits
    GROUP BY
      Fruit, Freshness
  ) s
  GROUP BY
    Fruit
  ) s

SQL Server 2008 and up:

select fruit, [1], [2], [3] from
( select row_number() over (partition by fruit order by ct desc) as rn, fruit, freshness from (
select count(1) as ct,  fruit, freshness from f
group by fruit, freshness ) g ) src
PIVOT
(
MAX(Freshness)
FOR rn in ([1], [2], [3])
) pvt

Try this

create table #fr (Fruit  varchar(20), Freshness varchar(20))
insert #fr values
('Banana' , 'New'),('Banana' , 'Ripe'),('Apple'  , 'Ripe'),('Orange' , 'Old'),('Cherry' , 'New'),
('Orange' , 'Ripe'),('Apple'  , 'Old'),('Banana' , 'Old'),('Apple'  , 'New'),('Apple'  , 'New'),
('Orange' , 'Ripe'),('Banana', 'Old'),('Orange' , 'New'),('Cherry',  'New'),('Cherry',  'Ripe')


SELECT Fruit,
       [1] Most_Common,
       [2] Second_Common,
       [3] Third_common
FROM   (SELECT Fruit,Freshness,
               Row_number()OVER(partition BY Fruit ORDER BY Count(*) DESC) rn
        FROM   #fr
        GROUP  BY Fruit,Freshness) a
       PIVOT (Max(Freshness)
             FOR rn IN([1],[2],[3])) piv 

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