另一个表中的 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 列在视图中具有静态值的主要内容,如果未能解决你的问题,请参考以下文章