在 SQL 视图中的列选择中使用左连接别名

Posted

技术标签:

【中文标题】在 SQL 视图中的列选择中使用左连接别名【英文标题】:Use Left Join Alias in Column Select in SQL Views 【发布时间】:2019-03-26 14:41:32 【问题描述】:

我正在 SQL Server 中创建一个视图,其中一个列需要是来自不同表的逗号分隔值。以下表为例 -

CREATE TABLE Persons
(
    Id INT NOT NULL PRIMARY KEY,
    Name VARCHAR (100)
)

CREATE TABLE Skills
(
    Id INT NOT NULL PRIMARY KEY,
    Name VARCHAR (100),
)

CREATE TABLE PersonSkillLinks
(
    Id INT NOT NULL PRIMARY KEY,
    SkillId INT FOREIGN KEY REFERENCES Skills(Id),
    PersonId INT FOREIGN KEY REFERENCES Persons(Id),
)

样本数据

INSERT INTO Persons VALUES
(1, 'Peter'),
(2, 'Sam'),
(3, 'Chris')


INSERT INTO Skills VALUES
(1, 'Poetry'),
(2, 'Cooking'),
(3, 'Movies')

INSERT INTO PersonSkillLinks VALUES
(1, 1, 1),
(2, 2, 1),
(3, 3, 1)

我想要的是如图所示的东西

虽然我已经能够使用下面的脚本获得结果,但我感觉这不是最好的(当然也不是唯一的)就性能而言 -

CREATE VIEW vwPersonsAndTheirSkills
AS
    SELECT p.Name,
    ISNULL(STUFF((SELECT ', ' + s.Name FROM Skills s JOIN PersonSkillLinks psl ON s.Id = psl.SkillId WHERE psl.personId = p.Id FOR XML PATH ('')), 1, 2, ''), '') AS Skill
    FROM Persons p 
GO

我还用下面的脚本试试运气 -

CREATE VIEW vwPersonsAndTheirSkills
AS
 SELECT p.Name,
 ISNULL(STUFF((SELECT ', ' + skill.Name FOR XML PATH ('')), 1, 2, ''), '') AS Skill
 FROM persons p
 LEFT JOIN 
 (
    SELECT s.Name, psl.personid FROM Skills s
    JOIN PersonSkillLinks psl ON s.Id = psl.SkillId
 ) skill ON skill.personId = p.Id

GO

但它没有连接字符串并为每个技能返回单独的行,如下所示 -

那么,我对第一个脚本的假设是否正确?如果是这样,我缺少什么概念以及实现它的最有效方法应该是什么。

【问题讨论】:

您使用的是什么 SQL Server 版本? SQL Server 的哪个版本?从 SQL Server 2017 开始,使用STRING_AGG() 可能会更好? (另外,如果这仅用于显示目的,通常建议此类处理在您的表示层中完成,在 sql 之外。紧密耦合您的数据层和您的表示层会在未来造成严重的破坏。例如后来希望能够从列表中选择一个项目,但发现列表项目本身可以包含逗号。那时你会渴望一个标准化的结构,保持名称分开并有一个带有 id 的列。) 我正在使用 SQL Server 2016...我已经阅读了有关字符串聚合的信息,但不幸的是它从 2017 年开始...... 为什么你认为第一个脚本不是“最好的”?这通常是在 SQL Server 中创建分隔列表的方式(直到 SQL Server 2017)。 @Larnu - 问题从来不在于如何生成列表,而是在哪里......就像 Yogesh 在他的回答中提到的那样,我认为该函数被多次调用,因此会减慢查询速度。 【参考方案1】:

我会尝试APPLY

SELECT p.Name, STUFF(ss.skills, 1, 2, '') AS Skill
FROM Persons p OUTER APPLY
     (SELECT ', ' + s.Name 
      FROM Skills s JOIN 
           PersonSkillLinks psl 
           ON s.Id = psl.SkillId 
      WHERE psl.personId = p.Id 
      FOR XML PATH ('')
     ) ss(skills);

通过这种方式,优化器将不会为外部查询返回的所有行调用一次STUFF()

【讨论】:

以上是关于在 SQL 视图中的列选择中使用左连接别名的主要内容,如果未能解决你的问题,请参考以下文章

如何在laravel eloquent中为左连接表起别名

SQL中的左连接与右连接,内连接有啥区别

左连接 SQL 查询 - MS Access

Hive sql中的 各种join(内连接左外连接右外连接满外连接)

Hive sql中的 各种join(内连接左外连接右外连接满外连接)

Hive sql中的 各种join(内连接左外连接右外连接满外连接)