سؤال

I've been playing around with a method to return counts for users in multiple tables.

<?php

    $stmt = $db->prepare("SELECT `computer_username`, `computer_name`, COUNT(`computer_name`) `totalsum` FROM `table1`
        WHERE `account_id` = ? AND (`computer_name` = 'comp1' OR `computer_name` = 'comp2' OR `computer_name` = 'comp3')
        GROUP BY `computer_username`, `computer_name`
    ");

    $stmt->execute(array($_SESSION['user']['account_id']));
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);   
    //print out the array
    echo 'table1<br /><pre>',print_r($results,true),'</pre><br /><br />';

    $stmt = $db->prepare("SELECT `computer_username`, `computer_name`, COUNT(`computer_name`) `totalsum` FROM `table2`
        WHERE `account_id` = ? AND (`computer_name` = 'comp1' OR `computer_name` = 'comp2' OR `computer_name` = 'comp3')
        GROUP BY `computer_username`, `computer_name`
    ");

    $stmt->execute(array($_SESSION['user']['account_id']));
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);   
    //print out the array
    echo 'table2<br /><pre>',print_r($results,true),'</pre><br /><br />';

    $stmt = $db->prepare("SELECT `computer_username`, `computer_name`, COUNT(`computer_name`) `totalsum` FROM `table3`
        WHERE `account_id` = ? AND (`computer_name` = 'comp1' OR `computer_name` = 'comp2' OR `computer_name` = 'comp3')
        GROUP BY `computer_username`, `computer_name`
    ");

    $stmt->execute(array($_SESSION['user']['account_id']));
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);   
    //print out the array
    echo 'table3<br /><pre>',print_r($results,true),'</pre><br /><br />';

?>

This results in something similar to the following for each array :

Array
(
    [0] => Array
        (
            [computer_username] => Bob
            [computer_name] => comp1
            [totalsum] => 1
        )

    [1] => Array
        (
            [computer_username] => Steve
            [computer_name] => comp1
            [totalsum] => 27
        )

    [2] => Array
        (
            [computer_username] => Sue
            [computer_name] => comp2
            [totalsum] => 7
        )

)

I am just trying to return each groups total row count in the database for each table. Since the conditions are exactly the same and only the table names are different is there a way to return this all in one call? I have been playing around with it all day, but using a query for each has been the only way I can get results so far.

Ideally I am looking for a one array result with something like :

Array
(
    [0] => Array
        (
            [computer_username] => Bob
            [computer_name] => comp1
            [table1] => 15
            [table2] => 34
            [table3] => 131
        )

        ... and so on for each computer_name/computer_username group

)

EDIT :

I made some progress with this...

SELECT * FROM

(SELECT computer_name, username, COUNT(computer_name) usercount
FROM users
WHERE `account_id` = ?
GROUP BY `username`, `computer_name`) a

JOIN 

(SELECT computer_name, computer_username, COUNT(computer_name) t1count
FROM t1
WHERE `account_id` = ?
GROUP BY `computer_username`, `computer_name`) b

JOIN

(SELECT computer_name, computer_username, COUNT(computer_name) t2count
FROM t2
WHERE `account_id` = ?
GROUP BY `computer_username`, `computer_name`) c

JOIN

(SELECT computer_name, computer_username, COUNT(computer_name) t3count
FROM t3
WHERE `account_id` = ?
GROUP BY `computer_username`, `computer_name`) d

ON a.username = b.computer_username AND a.username = c.computer_username AND a.username = d.computer_username

I start with users table as this will always have all username/computer group combinations listed. The problem is for any results to be returned in the array the username/computer group must have entries in every other table as well (t1,t2,t3).

So say, Bob on computer1 has 5 rows in t1, 10 in t2, and 50 in t3 I will get those counts back in my array as t1count, t2count, t3count. Sue on computer4 has 5 in t1, 0 and t2, and 12 in t3... because there were no rows in t2 none of her results are returned.

Is there any way around this or do joins explicitly require a matching value from one table to the next?

EXAMPLE DATA AND expected result :

//always contains every unique username/computer_name combination
`users` (username, computer_name)

bob, computer1
bob, computer8
steve, computer1
joe, computer3
sal, computer4
cindy, computer4
bill, computer8
jack, computer2

//contains data by computer_username/computer_name combo (can repeat)
`table1` (computer_username, computer_name)

bob, computer1
bob, computer8
bob, computer8
bob, computer8
steve, computer1
joe, computer3
joe, computer3
joe, computer3
bill, computer8
sal, computer4
sal, computer4
sal, computer4
cindy, computer4
bill, computer8

//contains data by computer_username/computer_name combo (can repeat)
`table2` (computer_username, computer_name)

bob, computer1
bob, computer1
bob, computer1
bob, computer8
bob, computer8
joe, computer3
joe, computer3
bill, computer8
sal, computer4
sal, computer4
cindy, computer4
cindy, computer4
cindy, computer4

//contains data by computer_username/computer_name combo (can repeat)
`table3` (computer_username, computer_name)

bob, computer8
steve, computer1
steve, computer1
steve, computer1
bill, computer8
bill, computer8
steve, computer1
sal, computer4
cindy, computer4
cindy, computer4

// resulting array on account_id = 1 and computer_name = (computer1, computer2, computer3, or computer4)
Array
(
    [0] => Array
        (
            [computer_username] => bob
            [computer_name] => computer1
            [t1count] => 1
            [t2count] => 3
            [t3count] => 0
        )
    [1] => Array
        (
            [computer_username] => steve
            [computer_name] => computer1
            [t1count] => 1
            [t2count] => 0
            [t3count] => 3
        )
    [3] => Array
        (
            [computer_username] => joe
            [computer_name] => computer3
            [t1count] => 3
            [t2count] => 2
            [t3count] => 0
        )
    [4] => Array
        (
            [computer_username] => sal
            [computer_name] => computer4
            [t1count] => 3
            [t2count] => 2
            [t3count] => 1
        )
    [5] => Array
        (
            [computer_username] => cindy
            [computer_name] => computer4
            [t1count] => 1
            [t2count] => 3
            [t3count] => 2
        )
    [6] => Array
        (
            [computer_username] => jack
            [computer_name] => computer2
            [t1count] => 0
            [t2count] => 0
            [t3count] => 0
        )
)

Assume, all the tables above have a column called account_id = 1. You have an account_id which represents the 'owner' of a computer. Users is a table of all computers and all usernames on those computers. table1, table2, table3 are records tied to the specific computer and specific user of that computer. There can be zero or any amount of records for any specific user/computer pair in any of those tables.

The goal is to return counts for the records tables (table1, table2, table3) for each user given an account_id and list of computer_name's. No ordering of any kind is needed on the result.

هل كانت مفيدة؟

المحلول

with the data provided and no ID's provided to query off of this will do what you want. see working FIDDLE

SELECT 
  usr, 
  cmptr, 
  t1_count, 
  t2_count, 
  t3_count 
FROM (
  SELECT
    users.username AS usr,
    users.computer_name AS cmptr,
    count(t1.computer_name) AS t1_count
  FROM users
  JOIN t1 ON t1.computer_username = users.username AND t1.computer_name = users.computer_name
  GROUP BY users.username, users.computer_name
)AS t
LEFT JOIN(
  SELECT
    users.username,
    users.computer_name,
    count(t2.computer_name) AS t2_count
  FROM users
  JOIN t2 ON t2.computer_username = users.username AND t2.computer_name = users.computer_name
  GROUP BY users.username, users.computer_name
) AS te ON te.username = t.usr OR te.computer_name = t.cmptr
LEFT JOIN(
  SELECT
    users.username,
    users.computer_name,
    count(t3.computer_name) AS t3_count
  FROM users
  JOIN t3 ON t3.computer_username = users.username AND t3.computer_name = users.computer_name
  GROUP BY users.username, users.computer_name
) AS tem ON tem.username = t.usr OR tem.computer_name = t.cmptr
GROUP BY usr, cmptr
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top