简体   繁体   中英

MySQL select Distinct records in 1 table and count each group based on values in another table

Table 1:

| user           | bid |
---------------------------
|    may    |      0.06      |
|    dee    |      0.05      |
|    jay    |      0.04      |
|    mac    |      0.03      |
|    dee    |      0.02      |
|    mac    |      0.01      |

Table 2:

| user          | ratio|
---------------------------
|    dee    |      .25      |
|    jay    |      .45      |
|    mac    |      .85      |
|    fil    |      .75      |
|    may    |      .95      |

I want to count how many distinct users from table 1 fall within certain ranges (0-.99) based on their ration in table 2.

Output:

| Ratio_Group     | Count|
---------------------------
|    0.00-0.25 |      1     |
|    0.25-0.50 |      1     |
|    0.50-0.75 |      0     |
|    0.75-0.99 |      2     |

Is there 1 query per ratio grouping I can use to count the distinct users in table 1 based on what grouping they fall into in table 2? I was using a combination of a IF and COUNT statement, but each row in table 1 was evaluated and counted instead of just the DISTINCT users and therefore I got an inflated result.

Ex:

 COUNT((IF table1.user <0.25,1,0))
 COUNT((IF table1.user BETWEEN 0.25 AND 0.50,1,0))
 etc...

Each of the 4 queries will be used in a stored proc so I need 1 query per ratio grouping so I may assign the result of each group to a variable in the stored proc.

You can use SUM with a combination of BETWEEN and DISTINCT

SELECT
SUM(DISTINCT `table2`.`ratio` BETWEEN 0.00 AND 0.25) `count`
FROM table1 JOIN table2 ON (table1.user =table2.user) GROUP BY table1.user

SELECT
SUM(DISTINCT `table2`.`ratio` BETWEEN 0.25 AND 0.50) `count`
FROM table1 JOIN table2 ON (table1.user =table2.user) GROUP BY table1.user

SELECT
SUM(DISTINCT `table2`.`ratio` BETWEEN 0.50 AND 0.75 ) `count`
FROM table1 JOIN table2 ON (table1.user =table2.user) GROUP BY table1.user

SELECT
SUM(DISTINCT `table2`.`ratio` BETWEEN 0.75 AND 0.99) `count`
FROM table1 JOIN table2 ON (table1.user =table2.user) GROUP BY table1.user

Or you can just combine them one as

SELECT  '0.00 - 0.25' Ratio_Group ,
SUM(DISTINCT `table2`.`ratio` BETWEEN 0.00 AND 0.25) `count`
FROM table1 JOIN table2 ON (table1.user =table2.user) GROUP BY table1.user
UNION ALL
SELECT '0.25 - 0.50' Ratio_Group ,
SUM(DISTINCT `table2`.`ratio` BETWEEN 0.25 AND 0.50) `count`
FROM table1 JOIN table2 ON (table1.user =table2.user) GROUP BY table1.user
UNION ALL
SELECT '0.50 - 0.75' Ratio_Group ,
SUM(DISTINCT `table2`.`ratio` BETWEEN 0.50 AND 0.75 ) `count`
FROM table1 JOIN table2 ON (table1.user =table2.user) GROUP BY table1.user
UNION ALL
SELECT '0.75 - 0.99' Ratio_Group ,
SUM(DISTINCT `table2`.`ratio` BETWEEN 0.75 AND 0.99) `count`
FROM table1 JOIN table2 ON (table1.user =table2.user) GROUP BY table1.user

EDIT Below query will count the distinct users for each ratio group

SELECT  '0.00 - 0.25' Ratio_Group ,
COUNT(DISTINCT `table2`.`user` ) `count`
FROM table1 JOIN table2 ON (table1.user =table2.user) 
WHERE `table2`.`ratio` BETWEEN 0.00 AND 0.25

UNION ALL

SELECT '0.25 - 0.50' Ratio_Group ,
COUNT(DISTINCT `table2`.`user`) `count`
FROM table1 JOIN table2 ON (table1.user =table2.user) 
WHERE  `table2`.`ratio` BETWEEN 0.25 AND 0.50

UNION ALL

SELECT '0.50 - 0.75' Ratio_Group ,
COUNT(DISTINCT `table2`.`user` ) `count`
FROM table1 JOIN table2 ON (table1.user =table2.user) 
WHERE `table2`.`ratio` BETWEEN 0.50 AND 0.75
UNION ALL

SELECT '0.75 - 0.99' Ratio_Group ,
COUNT(DISTINCT `table2`.`user`) `count`
FROM table1 JOIN table2 ON (table1.user =table2.user) 
WHERE `table2`.`ratio` BETWEEN 0.75 AND 0.99

See Fiddle Demo

If you don't mind only grabbing the groups that have members, you can do something like this. It uses an inner query to grab unique members and their corresponding ratios, then uses a containing table to group them into ratio groups by those ratios. The nice thing is you don't hard code row groups, which isn't very SQL-like; the downside is you don't see row "members" that have a count of 0.

SELECT
    CONCAT(
        ((CEIL(ratio * 4) * 0.25 ) - 0.25),
        " - ",
        (CEIL( ratio *4 ) * 0.25)
    ) AS ratio_group,
    COUNT(user) AS user_count
FROM (
    SELECT
        t1.user,
        t2.ratio
    FROM
        `table1` t1
    INNER JOIN
        `table2` t2 ON t2.user = t1.user
    GROUP BY
        t1.user
) virtual_table
GROUP BY
    CEIL(ratio * 4)

Per your additional comments, you can combine all the data into a string, and assign to a variable like so. This is a hell of a bastardization. What you do with that data (it's essentially a CSV string at that point) is up to YOU, haha.

@data = 
(SELECT
    GROUP_CONCAT(combined SEPARATOR ';')
FROM (
    SELECT
        CONCAT(
            '"',
            CONCAT(
                ((CEIL(ratio * 4) * 0.25) - 0.25),
                " - ",
                (CEIL( ratio *4 ) * 0.25)
            ),
            '",',
            COUNT( user )
        ) AS combined
    FROM (
        SELECT
            t1.user,
            t2.ratio
        FROM 
            `table1` t1
        INNER JOIN
            `table2` t2 ON t2.user = t1.user
        GROUP BY
            t1.user
    ) virtual_table
    GROUP BY
        CEIL( ratio *4 )
) virtual_table2 )

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