简体   繁体   English

MySQL JOIN->即使没有匹配项,也从右表中获取所有数据

[英]MySQL JOIN -> Get all data from right table even if there is no match

I have two tables, one with data (A) and other with categories (B) which is in one of those categories or uncategorized. 我有两个表,一个表包含数据(A) ,另一个表具有类别(B) ,这些类别属于其中一个类别或未分类。 I need to make simple stats, so I am using JOIN to get all data from table A and join it with table B. 我需要进行简单的统计,因此我正在使用JOIN从表A获取所有数据并将其与表B联接。

What I need is, that even if there is no match in A, I want to show all categories from B on graph (with count = 0, but I need them to be shown). 我需要的是,即使A中没有匹配项,我也想在图表上显示B中的所有类别(计数= 0,但需要显示它们)。

So if there are no items with that category id, it does not show that category at all, but I need to show it, even if it has 0 items. 因此,如果没有具有该类别ID的项目,它根本不会显示该类别,但是即使它有0个项目,我也需要显示它。

I tried LEFT JOIN, RIGHT JOIN, both of them with UNION and nothing worked. 我用UNION尝试了LEFT JOIN,RIGHT JOIN,但都没有用。

Table A 表A

id | some | irrelevant | data | category
-----------------------------------------
1  |      |            |      | 0
2  |      |            |      | 0
3  |      |            |      | 1
4  |      |            |      | 2
5  |      |            |      | 3
6  |      |            |      | 3
. . . . . . . . . . .

Table B 表B

id | title  | color
---------------------
1  | Cat 1  | #FFFFFF
2  | Cat 2  | #FF00FF
3  | Cat 3  | #FF0000
4  | Cat 4  | #00FF00
5  | Cat 5  | #00FFFF
6  | Cat 6  | #000000
7  | Cat 7  | #FFFF00

With those data I want to get something like: 有了这些数据,我想得到类似的东西:

Array ( [category] => 0 [count] => 3 [title] => [color] => ) 
Array ( [category] => 1 [count] => 1 [title] => Cat 1 [color] => #FFFFFF ) 
Array ( [category] => 2 [count] => 1 [title] => Cat 2 [color] => #FF00FF ) 
Array ( [category] => 3 [count] => 2 [title] => Cat 3 [color] => #FF0000 ) 
Array ( [category] => 4 [count] => 0 [title] => Cat 4 [color] => #00FF00 ) 
Array ( [category] => 5 [count] => 0 [title] => Cat 5 [color] => #00FFFF ) 
Array ( [category] => 6 [count] => 0 [title] => Cat 6 [color] => #000000 ) 
Array ( [category] => 7 [count] => 0 [title] => Cat 7 [color] => #FFFF00 ) 

But thats what I actually get: 但这就是我真正得到的:

Array ( [category] => 0 [count] => 3 [title] => [color] => ) 
Array ( [category] => 1 [count] => 1 [title] => Cat 1 [color] => #FFFFFF ) 
Array ( [category] => 2 [count] => 1 [title] => Cat 2 [color] => #FF00FF ) 
Array ( [category] => 3 [count] => 2 [title] => Cat 3 [color] => #FF0000 )

This is the call : 这是电话

"SELECT category, COUNT(*) AS count, title, color FROM A LEFT JOIN B ON B.id=A.category GROUP BY category"

PS.: Once more, I trued RIGHT join too and UNION of RIGHT and LEFT join. PS .:再一次,我也实现了RIGHT连接,并且实现了RIGHT和LEFT连接的UNION。 Also, the names of tables are really long, cant really use them in call as A.category etc. 另外,表的名称很长,不能在调用中作为A.category等真正使用它们。

Is there some way to do that without using two SQL calls and two loops? 有没有不用两个SQL调用和两个循环的方法吗? I really don't want to do that. 我真的不想这么做。

Thanks. 谢谢。

And what about this : 那呢:

SQL Fiddle SQL小提琴

MySQL 5.5.32 Schema Setup : MySQL 5.5.32模式设置

CREATE TABLE TableA
    (`id` int, `category` int)
;

INSERT INTO TableA
    (`id`, `category`)
VALUES
    (1, 0),
    (2, 0),
    (3, 1),
    (4, 2),
    (5, 3),
    (6, 3)
;

CREATE TABLE TableB
    (`id` int, `title` varchar(5), `color` varchar(7))
;

INSERT INTO TableB
    (`id`, `title`, `color`)
VALUES
    (1, 'Cat 1', '#FFFFFF'),
    (2, 'Cat 2', '#FF00FF'),
    (3, 'Cat 3', '#FF0000'),
    (4, 'Cat 4', '#00FF00'),
    (5, 'Cat 5', '#00FFFF'),
    (6, 'Cat 6', '#000000'),
    (7, 'Cat 7', '#FFFF00')
;

Query 1 : 查询1

SELECT TableB.id as category, count(distinct TableA.id) as count,title,color
FROM
(SELECT * FROM TableB
UNION
SELECT 0 as id, '' as title, '' as color) AS TableB
LEFT OUTER JOIN TableA on TableB.id = TableA.category
GROUP BY TableB.id, title, color
ORDER BY TableB.id

Results : 结果

| CATEGORY | COUNT | TITLE |   COLOR |
|----------|-------|-------|---------|
|        0 |     2 |       |         |
|        1 |     1 | Cat 1 | #FFFFFF |
|        2 |     1 | Cat 2 | #FF00FF |
|        3 |     2 | Cat 3 | #FF0000 |
|        4 |     0 | Cat 4 | #00FF00 |
|        5 |     0 | Cat 5 | #00FFFF |
|        6 |     0 | Cat 6 | #000000 |
|        7 |     0 | Cat 7 | #FFFF00 |

Also, instead of using UNION SELECT 0 as id, '' as title, '' as color , you can add a category with id 0 in your TableB 此外,您可以在TableB中添加ID为0的类别,而不是使用UNION SELECT 0 as id, '' as title, '' as color

[UPDATE] Adding both create data SQL and the SQL query below to prove the data: [更新]同时添加创建数据SQL和下面的SQL查询以证明数据:

To Add Test Data run the following SQL commands: 要添加测试数据,请运行以下SQL命令:

DROP TABLE junk_category;

CREATE TABLE junk_category (
    id INT PRIMARY KEY,
    name VARCHAR(32) NOT NULL
);

INSERT INTO junk_category (id,name) VALUES (1,'Cat 1'), (2,'Cat 2'), (3, 'Cat 3'), (4, 'Cat 4');

DROP TABLE junk_data;

CREATE TABLE junk_data (
    id INT PRIMARY KEY,
    name VARCHAR(32) NOT NULL,
    category INT NULL,
    INDEX byCategory (category)
);

INSERT INTO junk_data (id, name, category)
VALUES
(1,'one',1),
(2,'two',1),
(3,'three',1),
(4,'four',2),
(5,'five',2),
(6,'six',3),
(7,'seven',NULL),
(8,'eight',NULL);

To Query Test Data: 要查询测试数据:

SELECT 'Uncategorized' AS category, COUNT(*) AS count
    FROM junk_data A
    WHERE A.category IS NULL
UNION
SELECT B.name AS category, COUNT(DISTINCT A.id) AS count
    FROM junk_category B
    LEFT JOIN junk_data A ON A.category=B.id
    GROUP BY category

The only change needed from the query I had given you before was the DISTINCT A.id. 我之前给您的查询中唯一需要更改的是DISTINCTA.id。 I missed that in the previous paste I had done. 我错过了以前做的粘贴操作。 Without the DISTINCT A.id, the category itself counts as 1. The DISTINCT limits it to the data table. 如果没有DISTINCT A.id,类别本身将计为1。DISTINCT将其限制为数据表。 However, you said you were seeing 3...but the query doesn't "copy" and it wouldn't be 3 where it should be none...so if you are seeing 3 where there should be none, there is some other issue. 但是,您说您看到的是3 ...但是查询不会“复制”,并且应该不是3的查询也不会是3 ...所以如果您看到的3不应有的查询,则有一些其他问题。

[UPDATE 2015-03-03] [更新2015-03-03]

If you are not getting all your categories from this query: 如果您没有从此查询中获取所有类别:

SELECT B.name AS category, COUNT(DISTINCT A.id) AS count
    FROM junk_category B
    LEFT JOIN junk_data A ON A.category=B.id
    GROUP BY category

There is only one reason that this wouldn't return all your categories: if they are not uniquely named . 不会返回所有类别的原因只有一个: 如果它们的名称不是唯一的 The only filter in the above is the GROUP BY . 上面唯一的过滤器是GROUP BY

However, I realize that I may have confused you because I am naming B.name AS category which is the name of one of your columns. 但是,我意识到我可能对您感到困惑,因为我正在命名B.name AS category ,这是您其中一列的名称。 The GROUP BY is really GROUP BY B.name . GROUP BY实际上是GROUP BY B.name Thus, the only way to lose any entries is if they have the same B.name . 因此,丢失任何条目的唯一方法是它们具有相同的B.name So, in any case, your GROUP BY needs to be on your B table, not your A table. 因此,无论如何,您的GROUP BY必须位于B表上,而不是A表上。

There is not much else I can do without seeing your actual query and seeing if your GROUP BY or WHERE are placing additional restrictions. 在没有看到您的实际查询并查看您的GROUP BY或WHERE是否设置了其他限制的情况下,我无能为力 Or utilize my install-junk sql and make sure you can get the same results and then try to figure out the differences between my queries and what your actual queries are doing. 或利用我的install-junk sql并确保获得相同的结果,然后尝试找出我的查询与实际查询在做什么之间的差异。

This answer is not the best variant, but I want to provide it in case nobody here knows how to do what I want with single query and loop. 这个答案不是最好的选择,但是如果没有人知道如何使用单个查询和循环执行我想做的事情,我想提供它。


Right know I "solved" it with while loops (which is exactly what I did not want to use), but it actually looks like what I want is impossible... 知道我用while循环“解决了”(这正是我不想使用的循环),但实际上看起来像我想要的是不可能的...

$get_stats = dbquery("SELECT COUNT(*) AS count, category FROM XXX GROUP BY category");
$get_cats = dbquery("SELECT * FROM YYYYY");
$categories = array();
$stats_arr = array();

while ($cat = dbarray($get_cats)){
    $categories[$cat['id']] = array($cat['title'], $cat['color']);
    $stats_arr[$cat['id']] = array('count' => 0, 'title' => $cat['title'], 'color' => $cat['color']);
}

while ($stats = dbarray($get_stats)){
    if ($stats['category'] === "0"){
        $stats_arr[0] = array('count' => $stats['count'], 'title' => 'Uncategorized', 'color' => '#FFFFFF');
    }else{
        $stats_arr[$stats['category']] = array('count' => $stats['count'], 'title' => $categories[$stats['category']][0], 'color' => $categories[$stats['category']][1]);
    }
}
ksort($stats_arr);

foreach ($stats_arr as $id => $data) {
    // Code here
}

I still want to make it work without need for all of those loops tho. 我仍然想使其工作而无需所有这些循环。

Its OK for now, as its on a page where I already was looping trough categories, but it still added 2 loops and I want to use it on separate page, so I need to solve it with single query + loop. 现在还可以,因为它在我已经在循环槽类别的页面上,但是它仍然添加了2个循环,我想在单独的页面上使用它,因此我需要使用单个查询+循环来解决它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM