Home > database >  write a SQL query that shows frequency of each number (1-9) in columns A, B, and C
write a SQL query that shows frequency of each number (1-9) in columns A, B, and C

Time:10-01

A B C
1 1 2
3 6 1
2 4 5
6 8 6
1 4 9
9 5 7
2 5 7

My data looks something like that. I want to get a table that shows the frequency of each number in each column.

Value Frequency in A Frequency in B Frequency in C
1 2 1 2
2 2 0 1
3 1 0 1
4 0 2 0
5 0 2 1
6 1 1 1
7 0 0 2
8 0 1 0
9 1 0 1

The furthest I have gotten is

select A, count(*)
from table
group by A
order by A asc;

This only gives me the first two columns of this table.

CodePudding user response:

SELECT `Value`,
   (select count(*) from `table` where A = `Value`) as `Freq in A`,
   (select count(*) from `table` where B = `Value`) as `Freq in B`,
   (select count(*) from `table` where C = `Value`) as `Freq in C`,
FROM (
    select distinct A as `Value` from `table`
    union
    select distinct B from `table`
    union 
    select distinct C from `table`
) t
GROUP BY `Value`

CodePudding user response:

The following uses a cross join and group by to determine the frequency in each. The first query assumes that not all desired values i.e. 1-9 are present in either of the 3 columns in the table. The second query assumes that these values must occur atleast 1 and performs a union similar to JoelCoehoorn's answer. A case expression is used to check whether the values are present in the column before it is aggregated using count.

Query #1

SELECT
    Val,
    COUNT(
        CASE WHEN v.Val=tb.A THEN 1 END
    ) as `Frequency in A`,
    COUNT(
        CASE WHEN v.Val=tb.B THEN 1 END
    ) as `Frequency in B`,
    COUNT(
        CASE WHEN v.Val=tb.C THEN 1 END
    ) as `Frequency in C`
FROM (
     SELECT 1 as Val
     UNION ALL
     SELECT 2
     UNION ALL
     SELECT 3
     UNION ALL
     SELECT 4
     UNION ALL
     SELECT 5
     UNION ALL
     SELECT 6
     UNION ALL
     SELECT 7
     UNION ALL
     SELECT 8
     UNION ALL
     SELECT 9
) v
CROSS JOIN tb
GROUP BY Val
ORDER BY Val;
Val Frequency in A Frequency in B Frequency in C
1 2 1 1
2 2 0 1
3 1 0 0
4 0 2 0
5 0 2 1
6 1 1 1
7 0 0 2
8 0 1 0
9 1 0 1

Query #2

SELECT
    Val,
    COUNT(
        CASE WHEN v.Val=tb.A THEN 1 END
    ) as `Frequency in A`,
    COUNT(
        CASE WHEN v.Val=tb.B THEN 1 END
    ) as `Frequency in B`,
    COUNT(
        CASE WHEN v.Val=tb.C THEN 1 END
    ) as `Frequency in C`
FROM (
  SELECT DISTINCT Val FROM (
     SELECT A as Val FROM tb UNION ALL
     SELECT B FROM tb UNION ALL
     SELECT C FROM tb
  ) v1
) v
CROSS JOIN tb
GROUP BY Val
ORDER BY Val;
Val Frequency in A Frequency in B Frequency in C
1 2 1 1
2 2 0 1
3 1 0 0
4 0 2 0
5 0 2 1
6 1 1 1
7 0 0 2
8 0 1 0
9 1 0 1

Query #3

Uses recursive CTE for newer mysql versions.

WITH RECURSIVE numbers as (
    SELECT 1 as Val
    UNION ALL
    SELECT Val 1 FROM numbers WHERE Val < 9
)
SELECT
    Val,
    COUNT(
        CASE WHEN v.Val=tb.A THEN 1 END
    ) as `Frequency in A`,
    COUNT(
        CASE WHEN v.Val=tb.B THEN 1 END
    ) as `Frequency in B`,
    COUNT(
        CASE WHEN v.Val=tb.C THEN 1 END
    ) as `Frequency in C`
FROM tb
CROSS JOIN numbers v
GROUP BY Val
Val Frequency in A Frequency in B Frequency in C
1 2 1 1
2 2 0 1
3 1 0 0
4 0 2 0
5 0 2 1
6 1 1 1
7 0 0 2
8 0 1 0
9 1 0 1

View working demo on DB Fiddle

Let me know if this works for you.

CodePudding user response:

Here's another approach using window functions

with f as (
    select *,
    Count(A) over(partition by A)Fa,
    Count(B) over(partition by B)Fb,
    Count(C) over(partition by C)Fc
    from t
),v as (
    select a Val from t
    union
    select b from t
    union
    select c from t
)

select distinct v.Val, Coalesce(fa.fa,0) FrequencyA, Coalesce(fb.fb,0)FrequencyB, coalesce(fc.fc,0) FrequencyC
from v
left join f fa on fa.A=v.val
left join f fb on fb.B=v.val
left join f fc on fc.C=v.val
order by val
  • Related