从多个表中获取行计数

时间:2014-06-04 01:25:10

标签: mysql

我正在尝试根据user_id值为不同的表返回行计数。 users是具有唯一user_id列的所有用户的表。所有其他表都有一个相应的user_id列,可以与它一起加入。

我认为这会相当容易,但出于某种原因,我无法让计数返回正确。

我想要完成的是警报=?和位置=?哪里?是该表中user_id = 1,2,3,4,5,6,7或8的总行数。

$stmt = $db->prepare("
    SELECT
        count(t_alerts.user_id) as alerts,
        count(t_locations.user_id) as locations
    FROM users
    LEFT JOIN
        (SELECT user_id
        FROM alert_logs
        WHERE alert_logs.event_title LIKE '%blocked%'
        ) as t_alerts
            on t_alerts.user_id = users.user_id

    LEFT JOIN
        (SELECT user_id
        FROM location_logs
        ) as t_locations
            on t_locations.user_id = users.user_id

    WHERE users.user_id IN(1,2,3,4,5,6,7,8)
");

$stmt->execute();

//get results
$results = $stmt->fetch(PDO::FETCH_ASSOC);

编辑:

进行一些修改以消除提供IN值的需要......我在其他一些查询中使用它来仅获得“活跃”用户的结果......

$stmt = $db->prepare("
    SELECT
        (SELECT COUNT(*)
        FROM alert_logs al
        WHERE event_title LIKE '%blocked%' AND al.user_id = u.user_id
        ) as alerts,
        (SELECT COUNT(*)
        FROM location_logs ll
        WHERE ll.user_id = u.user_id
        ) as locations
    FROM
        ( SELECT account_id, computer_id
            FROM computers
            WHERE account_id = :account_id
            ORDER BY computer_id ASC LIMIT 0, :licenses
        ) as c
        INNER JOIN users as u
            on u.computer_id = c.computer_id
");

$binding = array(
    'account_id' => $_SESSION['user']['account_id'],
    'licenses' => $_SESSION['user']['licenses']
);
$stmt->execute($binding);

我正在使用此语句遇到下面提到的问题...它返回每个用户的计数数组,而不是所有计数合并为一个结果。

Array
(
    [0] => Array
        (
            [alerts] => 6
            [locations] => 4
        )

    [1] => Array
        (
            [alerts] => 3
            [locations] => 5
        )

    [2] => Array
        (
            [alerts] => 1
            [locations] => 4
        )

    [3] => Array
        (
            [alerts] => 0
            [locations] => 0
        )

    [4] => Array
        (
            [alerts] => 0
            [locations] => 0
        )

    [5] => Array
        (
            [alerts] => 0
            [locations] => 0
        )

    [6] => Array
        (
            [alerts] => 0
            [locations] => 0
        )

    [7] => Array
        (
            [alerts] => 0
            [locations] => 0
        )

)

我可以做些什么来“结合”结果?

1 个答案:

答案 0 :(得分:1)

问题是警报会与位置相乘。因此,如果有10个警报和5个位置,则结果为50行。这才算得上。

简单的解决方案是使用count(distinct)

SELECT
    count(distinct t_alerts.user_id) as alerts,
    count(distinct t_locations.user_id) as locations
. . . 

更好的解决方案通常是使用子查询对每个维度进行计数,然后将结果连接在一起。

编辑:

在您的情况下,select中的嵌套子查询可能是最好的方法,因为查询过滤了用户:

SELECT (SELECT COUNT(*)
        FROM alert_logs al
        WHERE event_title LIKE '%blocked%' AND
              al.user_id = u.user_id
       ) as alerts,
       (SELECT COUNT(*)
        FROM location_logs ll
        WHERE ll.user_id = u.user_id
       ) as locations
FROM users u
WHERE u.user_id IN (1,2,3,4,5,6,7,8)

编辑II:

我知道,查询结尾没有group by。在这种情况下,您可以这样做:

SELECT (SELECT COUNT(*)
        FROM alert_logs al
        WHERE event_title LIKE '%blocked%' AND
              al.user_id IN (1,2,3,4,5,6,7,8)
       ) as alerts,
       (SELECT COUNT(*)
        FROM location_logs ll
        WHERE ll.user_id IN (1,2,3,4,5,6,7,8)
       ) as locations;

您根本不需要users表。