Integer as SQL Alias 不会出错,但会给出不正确的结果

Integer as SQL Alias doesn’t error but gives incorrect result

我今天正在编写一些 SQL 代码,其中发起者弄错了 table 的别名,即字母 l,但他们输入的是数字 1。

即使这个错误已经发生,代码仍然 运行。

这是代码示例

SELECT l.[Name]
       ,l.Address
       ,1.Postcode
FROM List l

错误是代码 1.Postcode 而不是 l.Postcode

结果出来了,邮政编码栏全1,如下

如果错误是使用t.Postcode那么它会报错

The multi-part identifier " t.Postcode " could not be bound.

但不是错误 1.Postcode 而是被视为 1 AS Postcode

将行更正为l.Postcode即可得到正确的数据,如下

所以我的问题是为什么行 1.Postcode 没有错误?

您的语法 1.Postcode 被 sql-server 视为 +1.0 AS Postcode

有一个误解,它没有抛出错误,因为没有错误可以抛出,它给出了正确的结果...对于这个语法..

这里的主要问题是列值和列别名之间的space不是强制性的,在某些情况下可以省略。

SELECT 来自 Microsoft 文档:

SELECT [ ALL | DISTINCT ]  
[ TOP ( expression ) [ PERCENT ] [ WITH TIES ] ]   
<select_list>   
<select_list> ::=   
    {   
      *   
      | { table_name | view_name | table_alias }.*   
      | {  
          [ { table_name | view_name | table_alias }. ]  
               { column_name | $IDENTITY | $ROWGUID }   
          | udt_column_name [ { . | :: } { { property_name | field_name }   
            | method_name ( argument [ ,...n] ) } ]  
          | expression  
          [ [ AS ] column_alias ]   
         }  
      | column_alias = expression   
    } [ ,...n ]   

如您所见,考虑到 1Postcode 之间的点作为分隔符,1 不是 table_name, view_name, table_alias, nor a udt_column_name,因此它只保留 method_nameexpression.
但是 1.Postcode 不能是 method_name (cannot start with a number),所以你的情况是 expression [ [ AS ] column_alias ]

其中:

expression
Is a constant, function, any combination of column names, constants, and functions connected by an operator or operators, or a subquery.

嗯..同样,1 不能是函数也不能是列名 (cannot start with a number),所以它 必须常量.

第一个字符 1 是一个不同于 0 的数字.. 所以它只能是 bit, integer, decimal or float constant,但是第二个字符 . 仅限于小数和浮点数常数。

. 之后我们有 P,它不是数字.. 也不是 Ee(表示浮点常量)所以我们找到了一个十进制常数。

以下不是AS(请注意AS后的空格)所以它可能是列别名,而Postcode是一个有效的列别名..所以我们有我们的新列,它的值是 1(准确地说是 1.0),它的名字是 Postcode

看看这些例子并享受:

select 
    1.Postcode_decimal, -- 1.0 AS Postcode_decimal
    1.ePostcode_float, -- 1.0E0 AS Postcode_float
    1.asPostcode_decimal, -- 1.0 AS asPostcode_decimal
    1.as PostcodeAS_decimal, -- 1.0 AS PostcodeAS_decimal
    1Postcode_int, -- 1 AS Postcode_int
    1.+1.Postcode_expression, -- (1.0 + 1.0) AS Postcode_expression
    1.%1.+1+0.-.0/.1e-1Postcode_more_complex_expr, -- (1.0 % 1.0) + 1 + (0.0 / 0.1E-1) AS Postcode_more_complex_expr
    0xPostcode_varbin, -- 0x00 as Postcode_varbin
    3.5[3.5], -- 3.5 AS [3.5]
    'Hello'Postcode_varchar, 
    '1.0'[1.0], -- value is varchar, name is '1.0'  
    -- you can single quote an alias 
    22'Postcode_int2', 
    22'2.2',
    -- but beware of two single quotes are treated as one literal single quote.. 
    'Hello''Postcode_varchar'_  -- yes, the underscore can be an identifier..
into 
    #test_alias

SELECT * FROM #test_alias

select column_ordinal, name, is_nullable, system_type_name, max_length, precision, source_column
from sys.dm_exec_describe_first_result_set(N'SELECT * FROM #test_alias',null,1) 

drop table #test_alias

输出:

Postcode_decimal    Postcode_float  asPostcode_decimal  PostcodeAS_decimal  Postcode_int    Postcode_expression Postcode_more_complex_expr  Postcode_varbin Postcode_varchar    1.0 Postcode_int2   2.2 _                       3.5
1                   1               1                   1                   1               2                   1                           0x              Hello               1.0 22              22  Hello'Postcode_varchar  3.5

column_ordinal  name                        is_nullable system_type_name    max_length  precision   
1               Postcode_decimal            0           numeric(1,0)        5           1           
2               Postcode_float              0           float               8           53          
3               asPostcode_decimal          0           numeric(1,0)        5           1           
4               PostcodeAS_decimal          0           numeric(1,0)        5           1           
5               Postcode_int                0           int                 4           10          
6               Postcode_expression         1           numeric(2,0)        5           2           
7               Postcode_more_complex_expr  1           float               8           53          
8               Postcode_varbin             0           varbinary(1)        1           0           
9               Postcode_varchar            0           varchar(5)          5           0           
10              1.0                         0           varchar(3)          3           0           
11              Postcode_int2               0           int                 4           10          
12              2.2                         0           int                 4           10          
13              _                           0           varchar(22)         22          0           
14              3.5                         0           numeric(2,1)        5           2