列前缀'%s'与查询中使用的表名或别名不匹配

时间:2013-04-17 20:57:09

标签: sql-server sql-server-2008-r2 sql-server-2000 correlated-subquery

我正在尝试对远程2000服务器运行查询;但本地服务器生成的查询不正确,导致远程服务器返回错误:

  

列前缀'Tbl1002'与查询中使用的表名或别名不匹配。

当您跟踪远程服务器时,您可以看到sp_cursorprepexec批处理实际上是无效的SQL;它引用了一个不存在的衍生表Tbl1002

我在本地服务器上运行的查询是:

SELECT
    P.Code, P.Name AS PositionName, P.CompCommitteeMember,
    (    SELECT COUNT(*) 
         FROM Employees E 
         WHERE E.PositionID = P.PositionID
    ) AS EmployeeCount
FROM Positions P
WHERE P.PositionID = '{D1B0912D-B1A5-11D4-BBDD-0004ACC5B8A7}' 

其中EmployeesPositions是仅从链接服务器中选择的视图。为了消除这种混淆,我们将消除视图 - 并直接使用四部分命名:

SELECT
    P.Code, P.Name AS PositionName, P.CompCommitteeMember,
    (    SELECT COUNT(*) 
         FROM WCLHR.CasinoHR.dbo.Employees E 
         WHERE E.PositionID = P.PositionID
    ) AS EmployeeCount
FROM WCLHR.CasinoHR.dbo.Positions P
WHERE P.PositionID = '{D1B0912D-B1A5-11D4-BBDD-0004ACC5B8A7}' 

查询仍然失败:

  

列前缀'Tbl1002'与查询中使用的表名或别名不匹配。

为了消除WHERE子句中guid的任何混淆,我们将删除WHERE子句:

SELECT
    P.Code, P.Name AS PositionName, P.CompCommitteeMember,
    (    SELECT COUNT(*) 
         FROM WCLHR.CasinoHR.dbo.Employees E 
         WHERE E.PositionID = P.PositionID
    ) AS EmployeeCount
FROM WCLHR.CasinoHR.dbo.Positions P

它仍然失败:

  

列前缀'Tbl1002'与查询中使用的表名或别名不匹配。

为了消除*中使用COUNT的任何混淆,我们将消除它,而只计算一个常数:

SELECT
    P.Code, P.Name AS PositionName, P.CompCommitteeMember,
    (    SELECT COUNT(1) 
         FROM WCLHR.CasinoHR.dbo.Employees E 
         WHERE E.PositionID = P.PositionID
    ) AS EmployeeCount
FROM WCLHR.CasinoHR.dbo.Positions P

它仍然失败:

  

列前缀'Tbl1002'与查询中使用的表名或别名不匹配。

进一步向下,我们甚至会消除链接的服务器,并在2000机器上本地运行查询。

如果在远程服务器上运行该怎么办?

如果我针对远程服务器本身运行此查询:

SELECT
    P.Code, P.Name AS PositionName, P.CompCommitteeMember,
    (    SELECT COUNT(*) 
         FROM Employees E 
         WHERE E.PositionID = P.PositionID
    ) AS EmployeeCount
FROM Positions P

工作正常。

生成的查询是什么,你怎么知道它不好?

使用Profiler,我们可以看到进入远程服务器的查询。这是一个巨大的可怕混乱,但它肯定是无效的。它尝试引用不在范围内的派生表。任何在SQL Server中使用远程服务器的人都熟悉整个批处理:

declare @P1 int
set @P1=NULL
declare @P2 int
set @P2=NULL
declare @P3 int
set @P3=557064
declare @P4 int
set @P4=98305
declare @P5 int
set @P5=0
exec sp_cursorprepexec @P1 output, @P2 output, NULL, N'SELECT "Tbl1002"."PositionID", .....
select @P1, @P2, @P3, @P4, @P5

真正的问题是另一个SQL Server要求服务器准备服务器的SQL语句。调整下来,它说:

SELECT 
   "Tbl1002"."PositionID" "Col1010", ...
   (   SELECT "Expr1007" 
       FROM (
          SELECT "Expr1006","Expr1006" "Expr1007" 
          FROM (
             SELECT COUNT(*) "Expr1006" 
             FROM (
                SELECT 
                   "Tbl1005"."EmployeeID" "Col1043", ...
                FROM "CasinoHR"."dbo"."Employees" "Tbl1005" 
                WHERE "Tbl1005"."PositionID"="Tbl1002"."PositionID"
             ) Qry1103
          ) Qry1104
       ) "Subquery_Source_Tbl" 
    ) "Expr1008" 
FROM "CasinoHR"."dbo"."Positions" "Tbl1002" 
WHERE "Tbl1002"."PositionID"={guid'D1B0912D-B1A5-11D4-BBDD-0004ACC5B8A7'}'

这是一个混乱的读取,但你可以看到问题,它在一些嵌套的派生表中引用Tbl1002

WHERE "Tbl1005"."PositionID"="Tbl1002"."PositionID"

但只在外面宣布;最后:

FROM "CasinoHR"."dbo"."Positions" "Tbl1002"  

我们在这里讨论哪些版本的SQL Server?

我们尝试查询的“remote”服务器(“wclhr”)是带有SP4的SQL Server 2000:

  

Microsoft SQL Server 2000 - 8.00.2066(Intel X86)2012年5月11日18:41:14

发出查询时,我们尝试过SQL Server 2005和SQL Server 2008 R2。它曾经在两台服务器都是SQL Server 2000时工作。

从SQL Server 2005开始,继续到2008 R2,它正在生成无效 SQL!

我们尝试过的其他事情

令人惊讶的是,一个可怕的黑客攻击:

SELECT TOP 99.999999 PERCENT
    P.Code, P.Name AS PositionName, P.CompCommitteeMember,
    (    SELECT COUNT(1) 
         FROM WCLHR.CasinoHR.dbo.Employees E 
         WHERE E.PositionID = P.PositionID
    ) AS EmployeeCount
FROM WCLHR.CasinoHR.dbo.Positions P

这会阻止本地SQL Server 2008 R2为2000计算机生成无效的sql。

本地服务器不是64位,而是upgraded the catalogs on SQL Server 2000 anyway。它没有解决它。

您的原始查询不正确吗?

@Damien,Unbeliever并不认为范围可能是问题所在。请放心,确实如此。我的原始查询针对SQL Sever 2000正确运行:

SELECT
    P.Code, P.Name AS PositionName, P.CompCommitteeMember,
    (    SELECT COUNT(*) 
         FROM Employees E 
         WHERE E.PositionID = P.PositionID
    ) AS EmployeeCount
FROM Positions P
WHERE P.PositionID = '{D1B0912D-B1A5-11D4-BBDD-0004ACC5B8A7}' 

不幸的是,SQL Server 2005/2008 / 2008R2优化器将该查询转换为等效查询 - 但遗憾的是SQL Server 2000无法执行:

SELECT 
   Tbl1002.PositionID, 
   Tbl1002.Name AS PositionName, 
   Tbl1002.CompCommitteeMember,
   (    SELECT RecordCount
        FROM (
            SELECT COUNT(*) AS RecordCount
            FROM (
                SELECT 
                    Employees.EmployeeID
                FROM Employees
                WHERE Employees.PositionID=Tbl1002.PositionID
            ) Qry1103
        ) Qry1104
    ) AS EmployeeCount
FROM Positions Tbl1002
WHERE Tbl1002.PositionID= 'D1B0912D-B1A5-11D4-BBDD-0004ACC5B8A7'

在SQL Server 2000上,它给出了:

Msg 107, Level 16, State 2, Line 12
The column prefix 'Tbl1002' does not match with a table name or alias name used in the query.

SQL Server 2000似乎存在相关子查询的范围问题;在SQL Server 2005中“改进”

奖金阅读

1 个答案:

答案 0 :(得分:2)

基于您附带的阅读,看起来试图真正解决此问题需要您重新构建查询,以避免链接服务器上的相关子查询。

一种可能性是将您的链接表作为分组选择中的联接包含在内,并评估该语句中的聚合计数。

SELECT
    P.Code, P.Name AS PositionName, P.CompCommitteeMember, Count(*)
FROM Positions P
Left Join Employees E on E.PositionID = P.PositionID
WHERE P.PositionID = '{D1B0912D-B1A5-11D4-BBDD-0004ACC5B8A7}' 
group by P.Code, P.Name, P.CompCommitteeMember