Ian*_*oyd 5 sql-server sql-server-2000 sql-server-2008-r2 correlated-subquery
我正在尝试对远程2000服务器运行查询; 但是本地服务器生成的查询不正确,导致远程服务器返回错误:
列前缀"Tbl1002"与查询中使用的表名或别名不匹配.
跟踪远程服务器时,您可以看到该sp_cursorprepexec批处理实际上是无效的SQL; 它引用了一个Tbl1002不存在的dervied表.
我在本地服务器上运行的查询是:
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}'
Run Code Online (Sandbox Code Playgroud)
其中Employees和Positions是仅从链接服务器中选择的视图.为了消除这种混淆,我们将消除视图 - 并直接使用四部分命名:
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}'
Run Code Online (Sandbox Code Playgroud)
并且查询仍然失败:
列前缀"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
Run Code Online (Sandbox Code Playgroud)
它仍然失败:
列前缀"Tbl1002"与查询中使用的表名或别名不匹配.
为了eliminte各地使用任何混乱*中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
Run Code Online (Sandbox Code Playgroud)
它仍然失败:
列前缀"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
Run Code Online (Sandbox Code Playgroud)
它工作正常.
使用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
Run Code Online (Sandbox Code Playgroud)
真正的问题是另一个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'}'
Run Code Online (Sandbox Code Playgroud)
这是一个混乱的读取,但你可以看到问题,它Tbl1002在一些嵌套的派生表中引用:
WHERE "Tbl1005"."PositionID"="Tbl1002"."PositionID"
Run Code Online (Sandbox Code Playgroud)
但只能在外面宣布它; 在末尾:
FROM "CasinoHR"."dbo"."Positions" "Tbl1002"
Run Code Online (Sandbox Code Playgroud)
我们尝试查询的"远程"服务器("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
Run Code Online (Sandbox Code Playgroud)
这会阻止本地SQL Server 2008 R2为2000计算机生成无效的sql.
本地服务器不是64位,但无论如何我们升级了SQL Server 2000上的目录.它没有解决它.
@Damien the 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}'
Run Code Online (Sandbox Code Playgroud)
不幸的是,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'
Run Code Online (Sandbox Code Playgroud)
在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.
Run Code Online (Sandbox Code Playgroud)
SQL Server 2000似乎存在相关子查询的范围问题; 在SQL Server 2005 中被"改进"了.
根据您附加的阅读内容,尝试真正解决此问题似乎需要您重新构造查询,以避免链接服务器上的相关子查询。
一种可能性是将链接表作为联接包含在分组选择中,并评估该语句中的聚合计数。
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5359 次 |
| 最近记录: |