MySQL JOIN->;即使并没有匹配项,也要从正确的表中获取所有数据


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

我有两个表,一个表包含数据(A),另一个表具有类别(B)

我需要的是,即使A中没有匹配项,我也希望在图上显示B中的所有类别(计数为0,但我需要显示它们)。

因此,如果没有具有该类别id的项目,它根本不会显示该类别,但我需要显示它,即使它有0个项目。

我尝试了LEFT JOIN,RIGHT JOIN,它们都有UNION,但都不起作用。

表A

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

表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

有了这些数据,我希望获得以下内容:

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 ) 

但这就是我实际上得到的:

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 )

这是调用

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

PS.:再一次,我也修正了RIGHT联接和RIGHT和LEFT联接的并集。此外,表的名称非常长,不能在调用中用作A.category等。

在不使用两个SQL调用和两个循环的情况下,有什么方法可以做到这一点吗?我真的不想那样做。

谢谢。

这个呢:

SQL Fiddle

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')
;

查询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

结果

| 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 |

此外,您可以在TableB 中添加id为0的类别,而不是使用UNION SELECT 0 as id, '' as title, '' as color

这个答案不是最好的变体,但我想提供它以备不时之需这里没有人知道如何使用单个查询和循环来完成我想要的操作。


我知道我用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
}

我仍然想让它在不需要所有这些循环的情况下工作。

现在还可以,因为它在一个页面上,我已经通过类别进行了循环,但它仍然添加了2个循环,我想在单独的页面上使用它,所以我需要用单查询+循环来解决它。

[UPDATE]添加创建数据SQL和下面的SQL查询来证明数据:

要添加测试数据,请运行以下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);

查询测试数据:

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

我之前给你的查询只需要更改DISTINCT A.id。我在之前的粘贴中错过了它。如果没有DISTINCT A.id,则类别本身计数为1。DISTINCT将其限制在数据表中。然而,你说你看到了3……但查询没有"复制",也不会是3,因为它应该是零。。。因此,如果你看到的是应该没有的3,那么还有其他问题。

[更新2015-03-03]

如果您没有从这个查询中获得所有类别:

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

这不会返回所有类别的原因只有一个:如果它们不是唯一命名的。上述中唯一的过滤器是GROUP BY

然而,我意识到我可能混淆了您,因为我正在命名B.name AS category,这是您的一个列的名称。GROUP BY实际上是GROUP BY B.name。因此,丢失任何条目的唯一方法是如果它们具有相同的B.name。所以,无论如何,你的GROUP BY需要在你的B表上,而不是在你的A表上。

如果不查看您的实际查询并查看您的GROUP BY或WHERE是否设置了额外的限制,我将无能为力。或者利用我的安装垃圾sql,确保你能得到相同的结果,然后试着找出我的查询和你的实际查询之间的区别。