SQL - 在通过连接点 table 加入 table 时如何避免重复行?
SQL - How to avoid a repeating row when joining tables via a junction table?
我正在构建一个 Pokemon API,并且在通过连接点 table 加入时遇到重复行的问题。它是一个 SQL 服务器数据库。我的 tables 的简化版本如下所示:
重新创建我的数据库:
CREATE DATABASE PokeApi;
USE PokeApi;
CREATE TABLE Pokemon (
PokemonId INT PRIMARY KEY IDENTITY,
PokemonName VARCHAR(55),
NationalDexNumber INT,
PokemonHeight INT,
PokemonWeight DECIMAL(10,2),
Category VARCHAR(50),
Gender VARCHAR(15),
GenderDifference BIT,
TypeOne VARCHAR(15),
TypeTwo VARCHAR(15),
);
CREATE TABLE Abilities (
AbilityId INT PRIMARY KEY IDENTITY,
AbilityName VARCHAR(20)
);
CREATE TABLE PokemonAbilitiesMapped (
PokemonId INT NOT NULL,
AbilityId INT,
CONSTRAINT PK_PokemonAbilitiesMapped PRIMARY KEY
(
PokemonId,
AbilityId
),
FOREIGN KEY(PokemonId) REFERENCES Pokemon(PokemonId),
FOREIGN KEY(AbilityId) REFERENCES Abilities(AbilityId)
);
INSERT INTO Pokemon
VALUES
('Venusaur', 3, 79, 220.5, 'Seed', 'Male / Female', 1, 'Grass', 'Poison'),
('Mega Venusaur', 3, 94, 342.8, 'Seed', 'Male / Female', 0, 'Grass', 'Poison'),
('Gigantamax Venusaur', 3, 945, NULL, 'Seed', 'Male / Female', 1, 'Grass', 'Poison');
INSERT INTO Abilities
VALUES
('Overgrow'),
('Thick Fat'),
('Test');
INSERT INTO PokemonAbilitiesMapped
VALUES
(1, 1),
(2, 2),
(3, 1),
(3, 3);
我的查询:
SELECT p.PokemonName, p.NationalDexNumber, p.PokemonHeight, p.PokemonWeight,
p.Category, p.Gender, p.GenderDifference, p.TypeOne, p.TypeTwo,
a.AbilityName
FROM Pokemon p
JOIN PokemonAbilitiesMapped pam
ON p.PokemonId = pam.PokemonId
JOIN Abilities a
ON pam.AbilityId = a.AbilityId
输出这个:
PokemonName
NationalDexNumber
PokemonHeight
PokemonWeight
Category
Gender
GenderDifference
TypeOne
TypeTwo
AbilityName
Venusaur
3
79
220.50
Seed
Male / Female
True
Grass
Poison
Overgrow
Mega Venusaur
3
94
342.80
Seed
Male / Female
False
Grass
Poison
Thick Fat
Gigantamax Venusaur
3
945
null
Seed
Male / Female
True
Grass
Poison
Overgrow
Gigantamax Venusaur
3
945
null
Seed
Male / Female
True
Grass
Poison
Test
如您所见,Gigantamax Venusaur 列出了两次,因为它有两个能力。我在想我可以添加另一个名为“AbilityNameTwo”的列,前提是查询的神奇宝贝具有避免重复行的第二种能力。
在这种情况下避免重复数据的最佳方法是什么?如果我应该在加入时添加另一列,我将如何将其写为查询?
连接数据时出现这样的结果是完全正常的。如果你真的想要,你可以拥有“二能力”,但是如果某些神奇宝贝有三能力,或者五能力呢?你如何订购它们?这是一个示例,说明您如何为两种能力执行此操作并按字母顺序排列:
WITH abilitiesMapped AS
(
SELECT pam.PokemonId
, a.AbilityName
, ROW_NUMBER() OVER (PARTITION BY pam.PokemonId
ORDER BY a.AbilityName) AS abilityNo
FROM PokemonAbilitiesMapped pam
JOIN Abilities a
ON a.AbilityId = pam.AbilityId
)
SELECT p.PokemonName, p.NationalDexNumber, p.PokemonHeight, p.PokemonWeight,
p.Category, p.Gender, p.GenderDifference, p.TypeOne, p.TypeTwo
, ability1.abilityName AS ability1
, ability2.abilityName AS ability2
FROM Pokemon p
LEFT OUTER
JOIN abilitiesMapped ability1
ON ability1.PokemonId = p.PokemonId
AND ability1.abilityNo = 1
LEFT OUTER
JOIN abilitiesMapped ability2
ON ability2.PokemonId = p.PokemonId
AND ability1.abilityNo = 2
CTE abilitiesMapped 获取您的映射和能力,并为每个口袋妖怪 (PARTITION BY pam.PokemonId
) 生成一个 abilityNo,其中数字按能力名称 (ORDER BY ...
) 排序。然后这个 CTE 被加入两次 abilityNo 1 和 2。LEFT JOIN
很重要,因为口袋妖怪不一定需要有两个能力,在这种情况下你会在 ability2 中得到一个 NULL(INNER JOIN
您只会获得具有两种能力的能力,因为 abilityNo = 2 需要存在才能满足连接条件)。
感谢您 post 的创建、插入语句。很有帮助。
为避免能力名称重复,您可以将能力名称设为逗号分隔列表。我正在使用 STR_AGG
生成逗号分隔列表。从 SQL Server 2017 开始可用。对于早期版本,您必须使用 FOR XML PATH
来生成逗号分隔列表。
SELECT p.PokemonName, p.NationalDexNumber, p.PokemonHeight, p.PokemonWeight,
p.Category, p.Gender, p.GenderDifference, p.TypeOne, p.TypeTwo,
STRING_AGG(a.AbilityName,',') AS Abilities
FROM Pokemon p
JOIN PokemonAbilitiesMapped pam
ON p.PokemonId = pam.PokemonId
JOIN Abilities a
ON pam.AbilityId = a.AbilityId
GROUP BY p.PokemonName, p.NationalDexNumber, p.PokemonHeight, p.PokemonWeight,
p.Category, p.Gender, p.GenderDifference, p.TypeOne, p.TypeTwo
PokemonName
NationalDexNumber
PokemonHeight
PokemonWeight
Category
Gender
GenderDifference
TypeOne
TypeTwo
Abilities
Gigantamax Venusaur
3
945
NULL
Seed
Male / Female
1
Grass
Poison
Overgrow,Test
Mega Venusaur
3
94
342.80
Seed
Male / Female
0
Grass
Poison
Thick Fat
Venusaur
3
79
220.50
Seed
Male / Female
1
Grass
Poison
Overgrow
我正在构建一个 Pokemon API,并且在通过连接点 table 加入时遇到重复行的问题。它是一个 SQL 服务器数据库。我的 tables 的简化版本如下所示:
重新创建我的数据库:
CREATE DATABASE PokeApi;
USE PokeApi;
CREATE TABLE Pokemon (
PokemonId INT PRIMARY KEY IDENTITY,
PokemonName VARCHAR(55),
NationalDexNumber INT,
PokemonHeight INT,
PokemonWeight DECIMAL(10,2),
Category VARCHAR(50),
Gender VARCHAR(15),
GenderDifference BIT,
TypeOne VARCHAR(15),
TypeTwo VARCHAR(15),
);
CREATE TABLE Abilities (
AbilityId INT PRIMARY KEY IDENTITY,
AbilityName VARCHAR(20)
);
CREATE TABLE PokemonAbilitiesMapped (
PokemonId INT NOT NULL,
AbilityId INT,
CONSTRAINT PK_PokemonAbilitiesMapped PRIMARY KEY
(
PokemonId,
AbilityId
),
FOREIGN KEY(PokemonId) REFERENCES Pokemon(PokemonId),
FOREIGN KEY(AbilityId) REFERENCES Abilities(AbilityId)
);
INSERT INTO Pokemon
VALUES
('Venusaur', 3, 79, 220.5, 'Seed', 'Male / Female', 1, 'Grass', 'Poison'),
('Mega Venusaur', 3, 94, 342.8, 'Seed', 'Male / Female', 0, 'Grass', 'Poison'),
('Gigantamax Venusaur', 3, 945, NULL, 'Seed', 'Male / Female', 1, 'Grass', 'Poison');
INSERT INTO Abilities
VALUES
('Overgrow'),
('Thick Fat'),
('Test');
INSERT INTO PokemonAbilitiesMapped
VALUES
(1, 1),
(2, 2),
(3, 1),
(3, 3);
我的查询:
SELECT p.PokemonName, p.NationalDexNumber, p.PokemonHeight, p.PokemonWeight,
p.Category, p.Gender, p.GenderDifference, p.TypeOne, p.TypeTwo,
a.AbilityName
FROM Pokemon p
JOIN PokemonAbilitiesMapped pam
ON p.PokemonId = pam.PokemonId
JOIN Abilities a
ON pam.AbilityId = a.AbilityId
输出这个:
PokemonName | NationalDexNumber | PokemonHeight | PokemonWeight | Category | Gender | GenderDifference | TypeOne | TypeTwo | AbilityName |
---|---|---|---|---|---|---|---|---|---|
Venusaur | 3 | 79 | 220.50 | Seed | Male / Female | True | Grass | Poison | Overgrow |
Mega Venusaur | 3 | 94 | 342.80 | Seed | Male / Female | False | Grass | Poison | Thick Fat |
Gigantamax Venusaur | 3 | 945 | null | Seed | Male / Female | True | Grass | Poison | Overgrow |
Gigantamax Venusaur | 3 | 945 | null | Seed | Male / Female | True | Grass | Poison | Test |
如您所见,Gigantamax Venusaur 列出了两次,因为它有两个能力。我在想我可以添加另一个名为“AbilityNameTwo”的列,前提是查询的神奇宝贝具有避免重复行的第二种能力。
在这种情况下避免重复数据的最佳方法是什么?如果我应该在加入时添加另一列,我将如何将其写为查询?
连接数据时出现这样的结果是完全正常的。如果你真的想要,你可以拥有“二能力”,但是如果某些神奇宝贝有三能力,或者五能力呢?你如何订购它们?这是一个示例,说明您如何为两种能力执行此操作并按字母顺序排列:
WITH abilitiesMapped AS
(
SELECT pam.PokemonId
, a.AbilityName
, ROW_NUMBER() OVER (PARTITION BY pam.PokemonId
ORDER BY a.AbilityName) AS abilityNo
FROM PokemonAbilitiesMapped pam
JOIN Abilities a
ON a.AbilityId = pam.AbilityId
)
SELECT p.PokemonName, p.NationalDexNumber, p.PokemonHeight, p.PokemonWeight,
p.Category, p.Gender, p.GenderDifference, p.TypeOne, p.TypeTwo
, ability1.abilityName AS ability1
, ability2.abilityName AS ability2
FROM Pokemon p
LEFT OUTER
JOIN abilitiesMapped ability1
ON ability1.PokemonId = p.PokemonId
AND ability1.abilityNo = 1
LEFT OUTER
JOIN abilitiesMapped ability2
ON ability2.PokemonId = p.PokemonId
AND ability1.abilityNo = 2
CTE abilitiesMapped 获取您的映射和能力,并为每个口袋妖怪 (PARTITION BY pam.PokemonId
) 生成一个 abilityNo,其中数字按能力名称 (ORDER BY ...
) 排序。然后这个 CTE 被加入两次 abilityNo 1 和 2。LEFT JOIN
很重要,因为口袋妖怪不一定需要有两个能力,在这种情况下你会在 ability2 中得到一个 NULL(INNER JOIN
您只会获得具有两种能力的能力,因为 abilityNo = 2 需要存在才能满足连接条件)。
感谢您 post 的创建、插入语句。很有帮助。
为避免能力名称重复,您可以将能力名称设为逗号分隔列表。我正在使用 STR_AGG
生成逗号分隔列表。从 SQL Server 2017 开始可用。对于早期版本,您必须使用 FOR XML PATH
来生成逗号分隔列表。
SELECT p.PokemonName, p.NationalDexNumber, p.PokemonHeight, p.PokemonWeight,
p.Category, p.Gender, p.GenderDifference, p.TypeOne, p.TypeTwo,
STRING_AGG(a.AbilityName,',') AS Abilities
FROM Pokemon p
JOIN PokemonAbilitiesMapped pam
ON p.PokemonId = pam.PokemonId
JOIN Abilities a
ON pam.AbilityId = a.AbilityId
GROUP BY p.PokemonName, p.NationalDexNumber, p.PokemonHeight, p.PokemonWeight,
p.Category, p.Gender, p.GenderDifference, p.TypeOne, p.TypeTwo
PokemonName | NationalDexNumber | PokemonHeight | PokemonWeight | Category | Gender | GenderDifference | TypeOne | TypeTwo | Abilities |
---|---|---|---|---|---|---|---|---|---|
Gigantamax Venusaur | 3 | 945 | NULL | Seed | Male / Female | 1 | Grass | Poison | Overgrow,Test |
Mega Venusaur | 3 | 94 | 342.80 | Seed | Male / Female | 0 | Grass | Poison | Thick Fat |
Venusaur | 3 | 79 | 220.50 | Seed | Male / Female | 1 | Grass | Poison | Overgrow |