SQL Server 中的 T-SQL - 错误还是功能?

fcm*_*fcm -4 t-sql sql-server

我有以下选择:

SELECT DISTINCT pl 
FROM [dbo].[VendorPriceList] h
WHERE PartNumber IN (SELECT DISTINCT PartNumber 
                     FROM [dbo].InvoiceData 
                     WHERE amount > 10 
                       AND invoiceDate > DATEADD(yyyy, -1, CURRENT_TIMESTAMP)

                     UNION

                     SELECT DISTINCT PartNumber 
                     FROM [dbo].VendorDeals)
Run Code Online (Sandbox Code Playgroud)

这里的问题是表[dbo].VendorDeals没有列PartNumber,但是没有检测到错误并且查询适用于联合的第一部分。

更重要的是,IntelliSense 还允许并识别PartNumber. 仅当位于复杂语句内时,此操作才会失败。

很明显,如果您限定列名,错误就会很明显。

use*_*983 5

这不是 SQL Server/T-SQL 方言解析中的错误,不,这完全按照预期工作。问题或错误出在您的T-SQL 中;特别是因为您还没有限定您的专栏。由于我没有您的表的定义,我将首先提供示例 DDL:

CREATE TABLE dbo.Table1 (MyColumn varchar(10), OtherColumn int);
CREATE TABLE dbo.Table2 (YourColumn varchar(10) OtherColumn int);
Run Code Online (Sandbox Code Playgroud)

然后是一个与您的查询类似的示例:

SELECT MyColumn
FROM dbo.Table1
WHERE MyColumn IN (SELECT MyColumn FROM dbo.Table2);
Run Code Online (Sandbox Code Playgroud)

首先,这将解析;这是一个有效的查询。其次,如果dbo.Table2包含至少一行,则表中的每一dbo.Table1行都将返回MyColumn具有非NULL值的行。为什么?好吧,让我们用表名来限定列,因为 SQL Server 会解析它们:

SELECT Table1.MyColumn
FROM dbo.Table1
WHERE Table1.MyColumn IN (SELECT Table1.MyColumn FROM dbo.Table2);
Run Code Online (Sandbox Code Playgroud)

请注意,内的列也IN引用Table1而不是 Table2。默认情况下,如果子查询中省略了列的别名,则将假定列引用该子查询中定义的表。但是,如果子查询中的任何表都没有具有该名称的列,则将假定引用该列确实存在的表;在这种情况下Table1

相反,让我们使用表中的另一列来举一个不同的示例:

SELECT OtherColumn
FROM dbo.Table1
WHERE OtherColumn IN (SELECT OtherColumn FROM dbo.Table2);
Run Code Online (Sandbox Code Playgroud)

这将被解析如下:

SELECT Table1.OtherColumn
FROM dbo.Table1
WHERE Table1.OtherColumn IN (SELECT Table2.OtherColumn FROM dbo.Table2);
Run Code Online (Sandbox Code Playgroud)

这是因为两个OtherColumn表中都存在。由于在子查询中没有限定,因此假定所需的列是在同一范围 中定义的表中的列。OtherColumnTable2

那么解决办法是什么呢?别名和限定您的列:

SELECT T1.MyColumn
FROM dbo.Table1 T1
WHERE T1.MyColumn IN (SELECT T2.MyColumn FROM dbo.Table2 T2);
Run Code Online (Sandbox Code Playgroud)

毫不奇怪,这将出现错误,因为Table2has no column MyColumn

就我个人而言,我建议除非您在查询中只引用一个表,否则您可以对所有列进行别名和限定。这不仅确保不能引用错误的列(例如在子查询中),而且意味着其他读者确切地知道正在引用哪些列。它还可以阻止未来的失败。老实说,我已经记不清多年来有多少次由于“不明确的列”错误而导致进程失败,因为表的定义被更改,并且引用该表的查询没有被开发人员正确限定......