在mysql中为外部联接使用别名的正确方法是什么,这样我就不会收到“非唯一表/别名”错误?

时间:2019-04-30 02:31:39

标签: mysql

当试图从玩家表和包括报表和玩家(reports_players表)的联接表中获取玩家的名字及其伤害时,我收到错误1066(42000):不是唯一的表/别名:'rp'

我还想将item_level包含在此查询中,但想让此部分首先工作。

我尝试使用此查询来获取我想要的两个值:

SELECT p.name
FROM players p
LEFT JOIN rp ON p.player_id=rp.player_id
UNION
SELECT rp.damage_done
FROM reports_players rp
RIGHT JOIN rp ON p.player_id=rp.player_id
GROUP BY p.name;
直接从How to do a FULL OUTER JOIN in MySQL?引用的

我仍然不清楚为什么会出错。我已经使用了多个完整联接的示例,但除了空集或永久挂断的查询之外,我仍然无法获得其他任何信息。

这是我的数据库结构:

CREATE TABLE reports(
report_id INT UNSIGNED auto_increment PRIMARY KEY,
zone INT UNSIGNED,
report_url VARCHAR(20),
title VARCHAR(50)
)engine=InnoDB CHARSET utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE reports_players(
id INT UNSIGNED auto_increment PRIMARY KEY,
report_id INT UNSIGNED UNIQUE KEY,
player_id INT UNSIGNED UNIQUE KEY,
damage_done INT UNSIGNED,
item_level INT UNSIGNED
)engine=InnoDB CHARSET utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE players(
player_id INT UNSIGNED auto_increment PRIMARY KEY,
name VARCHAR(20)
)engine=InnoDB CHARSET utf8mb4 COLLATE = utf8mb4_unicode_ci;

预期:玩家和report_players的外部联接,以显示玩家的名称及其造成的伤害。 实际:错误1066(42000):不是唯一的表/别名:“ rp”

1 个答案:

答案 0 :(得分:0)

如果您还没有设置内联显示值的方法,那么下面的内容应该为您提供有关不同玩家名称及其所造成的损害的报告。

SELECT p.name, sum(rp.damage_done) damage_done
FROM players p 
JOIN reports_players rp
    ON p.player_id=rp.player_id
Group By p.name

如果您需要所有玩家,即使他们没有造成伤害:

SELECT p.name, sum(ifnull(rp.damage_done,0)) damage_done
FROM players p 
LEFT JOIN reports_players rp
    ON p.player_id=rp.player_id
Group By p.name

要将查询固定为完全外部联接,您需要执行以下操作:

SELECT p.name, sum(rp.damage_done)
FROM players p
LEFT JOIN reports_players rp ON p.player_id=rp.player_id
GROUP BY p.name
UNION
SELECT p.name, sum(rp.damage_done)
FROM reports_players rp
RIGHT JOIN players p ON p.player_id=rp.player_id
GROUP BY p.name;

但是,如果左联接对您不起作用,我真的认为这不会解决您的问题。 我认为上述选择对您不起作用的原因是您表中的数据不匹配。为了向您展示我所做的选择确实起作用,我给出以下示例。

-- make the tables. 
CREATE TABLE reports(
report_id INT UNSIGNED auto_increment PRIMARY KEY,
zone INT UNSIGNED,
report_url VARCHAR(20),
title VARCHAR(50)
)engine=InnoDB CHARSET utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- note that I removed the unique keys from this table on report_id and player_id.  
CREATE TABLE reports_players(
id INT UNSIGNED auto_increment PRIMARY KEY,
report_id INT UNSIGNED ,
player_id INT UNSIGNED ,
damage_done INT UNSIGNED,
item_level INT UNSIGNED
)engine=InnoDB CHARSET utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE players(
player_id INT UNSIGNED auto_increment PRIMARY KEY,
name VARCHAR(20)
)engine=InnoDB CHARSET utf8mb4 COLLATE = utf8mb4_unicode_ci;

create index reports_players_player_id on reports_players (player_id);
create index reports_players_report_id on reports_players (report_id);

insert into players (name) 
values 
('last one'),
('Jack'),
('Jaragoth'),
('Jim'),
('Joe'),
('Jill');

insert into reports (zone, report_url, title) VALUES
(1,'www.place.com','The Place'),
(2,'www.theother.com','The Other Place');


drop PROCEDURE if EXISTS makeData;
-- make a procedure to build a data set. 
CREATE PROCEDURE makeData() 
BEGIN
    DECLARE i INT DEFAULT 0;

    TRUNCATE TABLE reports_players;

    start transaction;
    WHILE i < 10000 DO
    insert into reports_players (report_id, player_id, damage_done, item_level)    
    select floor(rand() *2) + 1 report_id, floor(rand() * 5) + 1 player_id, floor(rand() *20) +1 damage_done, floor(rand() * 5) + 1 item_level;
    set i = (i + 1);
    END WHILE;
    commit;
END ;

-- make the data
call makeData();

-- we will want an index
create index reports_players_player_id on reports_players (player_id);
create index reports_players_report_id on reports_players (report_id);

-- prove we made the data
select count(1) from reports_players;

---- some reporting examples. 
-- Inner join
SELECT p.name, sum(ifnull(rp.damage_done,0)) damage_done
FROM players p 
JOIN reports_players rp
    ON p.player_id=rp.player_id
Group By p.name

-- Left outer join (all players regarless of if they have damaged)
SELECT p.name, sum(ifnull(rp.damage_done,0)) damage_done
FROM players p 
LEFT JOIN reports_players rp
    ON p.player_id=rp.player_id
Group By p.name

-- Left outer join grouped by player, and item
SELECT p.name, rp.item_level, sum(ifnull(rp.damage_done,0)) damage_done
FROM players p 
LEFT JOIN reports_players rp
    ON p.player_id=rp.player_id
Group By p.name, rp.item_level