另一个表中的 SQL Server 列在视图中具有静态值

Posted

技术标签:

【中文标题】另一个表中的 SQL Server 列在视图中具有静态值【英文标题】:SQL Server Column From Another Table With Static Value In View 【发布时间】:2014-10-22 08:23:55 【问题描述】:

有没有办法让另一个表中的列在视图中的值始终相同> 示例:

SELECT *, 
   (SELECT value FROM tblStudentPrefixes WHERE PrefixName = 'SeniorPrefix')
   AS StudentPrefix
FROM tblStudents

上面的嵌套查询会针对每一行执行吗?有没有办法执行一次并用于所有行。

请注意,我说的是视图,而不是存储过程。我知道这可以在存储过程中完成。

【问题讨论】:

如果您的 PrefixName 是唯一的,您可以将其重写为外连接 【参考方案1】:

这实际上取决于您的餐桌设置。除非prefixName 被限制为唯一,否则您可能会遇到错误,其中子查询返回不止一行。如果它不限于唯一,但恰好对于 SeniorPrefix 是唯一的,那么您的查询将被执行 1000 次。为了证明我使用了以下 DDL:

CREATE TABLE #tblStudents (ID INT IDENTITY(1, 1), Filler CHAR(100));
INSERT #tblStudents (Filler)
SELECT TOP 10000 NULL
FROM sys.all_objects a, sys.all_objects b;

CREATE TABLE #tblStudentPrefixes (Value VARCHAR(10), PrefixName VARCHAR(20));
INSERT #tblStudentPrefixes (Value, PrefixName) VALUES ('A Value', 'SeniorPrefix');

运行查询会提供以下 IO 输出:

表“#tblStudentPrefixes”。扫描计数 10000,逻辑读取 10000

表“#tblStudents”。扫描计数 1,逻辑读取 142

关键是 tblStudentPrefixes 上的 1000 次逻辑读取。它不被限制为唯一的另一个问题是,如果您有重复,您的查询将失败并出现错误:

子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。

如果您不能将PrefixName 限制为唯一,那么您可以停止它对每一行的执行并使用TOP 避免错误:

SELECT *, 
   (SELECT TOP 1 value FROM #tblStudentPrefixes WHERE PrefixName = 'SeniorPrefix' ORDER BY Value)
   AS StudentPrefix
FROM #tblStudents

IO 现在变成:

表“#tblStudentPrefixes”。扫描计数 1,逻辑读取 1

表“#tblStudents”。扫描计数 1,逻辑读取 142

但是,我仍然建议在此处切换到 CROSS JOIN:

SELECT  s.*, p.Value AS StudentPrefix
FROM    #tblStudents AS s
        CROSS JOIN 
        (   SELECT TOP 1 value 
            FROM #tblStudentPrefixes 
            WHERE PrefixName = 'SeniorPrefix'
            ORDER BY Value
        ) AS p;

对执行计划的检查表明,使用表假脱机的子选择对于单个值来说是非常不必要的:

因此,总而言之,它是否会为每一行执行取决于您的表设置,但无论您是否给优化器一个更好的机会,如果您切换到交叉连接。


编辑

鉴于当tblStudentPrefixes 中的SeniorPrefix 不匹配时,您需要从tblstudent 返回行,并且PrefixName 当前不被限制为唯一,那么最好的解决方案是:

SELECT *, 
   (SELECT MAX(value) FROM #tblStudentPrefixes WHERE PrefixName = 'SeniorPrefix')
   AS StudentPrefix
FROM #tblStudents;

如果您确实将其限制为唯一,那么以下 3 个查询会产生(基本上)相同的计划和相同的结果,这只是个人喜好:

SELECT *, 
   (SELECT value FROM #tblStudentPrefixes WHERE PrefixName = 'SeniorPrefix')
   AS StudentPrefix
FROM #tblStudents;

SELECT  s.*, p.Value AS StudentPrefix
FROM    #tblStudents AS s
        LEFT JOIN #tblStudentPrefixes AS p
            ON p.PrefixName = 'SeniorPrefix';

SELECT  s.*, p.Value AS StudentPrefix
FROM    #tblStudents AS s
        OUTER APPLY 
        (   SELECT Value
            FROM #tblStudentPrefixes 
            WHERE PrefixName = 'SeniorPrefix'
        ) AS p;

【讨论】:

谢谢。在检查 SO 的答案之前,我尝试了以下方法,这给了我想要的结果。你认为你的查询会有更好的性能吗? SELECT s.*, p.Value AS StudentPrefix FROM tblStudents s LEFT JOIN tblStudentPrefixes ON p.PrefixName = 'SeniorPrefix' 视情况而定,但我对此表示怀疑。使用LEFT JOIN,如果它被限制为唯一,则与子选择具有上述相同的惰性假脱机问题,如果它不被限制为唯一,则嵌套循环连接和获得 1,000 次 tblStudentPrefixes 读取有相同的问题. 我想关键问题是,在 tblStudentPrefixes 中是否总是有 SeniorPrefix 的值?如果没有,你想返回结果吗? 是的,如果SeniorPrefix 没有值,我想返回结果 PrefixName 在您的表中是否被限制为唯一?如果没有,并且有多个值,您要返回多行吗?【参考方案2】:

我希望我能正确理解你的问题,但试试这个

SELECT *  
FROM tblStudents
 Outer Apply 
  (
    SELECT value 
    FROM tblStudentPrefixes 
    WHERE PrefixName = 'SeniorPrefix'
   ) as tble

【讨论】:

【参考方案3】:

没关系。将为每一行上的每一行执行子查询(这可能会提供糟糕的性能)。 你也可以试试:

SELECT tblStudents.*,StudentPrefix.value 
  FROM tblStudents,
      (SELECT value 
         FROM tblStudentPrefixes 
        WHERE PrefixName = 'SeniorPrefix')StudentPrefix

【讨论】:

以上是关于另一个表中的 SQL Server 列在视图中具有静态值的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server:使用来自另一个表或视图的参数连接一个表中的平均数据

SQL Server 4

SQL Server中的标识列

使用表中的列在 PostgreSQL 中创建视图

JOIN列在两个表中具有相同名称时的T-SQL语法缩写?

表中的更改列在 postgres 中具有枚举类型