Le préfixe de colonne '% s' ne correspond pas à un nom de table ou un nom d'alias utilisé dans la requête

j'essaye d'exécuter une requête contre un server 2000 distant; mais la requête que le server local génère est incorrecte et provoque le server distant pour renvoyer l'erreur:

Le préfixe de colonne 'Tbl1002' ne correspond pas à un nom de table ou un nom d'alias utilisé dans la requête.

Lorsque vous tracez le server distant , vous pouvez voir que le lot sp_cursorprepexec est, en fait, SQL non valide; il a une reference à une table Tbl1002 qui n'existe pas.

La requête que je cours sur mon server local est:

 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}' 

Employees et Positions sont des vues qui sont simplement sélectionnées à partir du server lié. Afin d'éliminer cette confusion, nous allons éliminer les vues – et utiliser quatre noms de partie directement:

 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}' 

Et la requête échoue toujours avec:

Le préfixe de colonne 'Tbl1002' ne correspond pas à un nom de table ou un nom d'alias utilisé dans la requête.

Afin d'éliminer toute confusion autour du guid dans la clause WHERE , nous allons éliminer la clause 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 

Et il échoue toujours avec:

Le préfixe de colonne 'Tbl1002' ne correspond pas à un nom de table ou un nom d'alias utilisé dans la requête.

Afin d'éliminer toute confusion autour de l'utilisation de * dans COUNT , nous allons l'éliminer, et au lieu de countr seulement une constante:

 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 

Et il échoue toujours avec:

Le préfixe de colonne 'Tbl1002' ne correspond pas à un nom de table ou un nom d'alias utilisé dans la requête.

Plus bas, nous allons même éliminer les servers liés, et exécuter la requête localement sur la machine 2000.

Que faire si vous l'exécutez sur le server distant lui-même?

Si j'exécute cette requête sur le server distant lui-même:

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

Ça fonctionne bien.

Quelle est la requête générée, comment savez-vous que c'est mauvais?

En utilisant Profiler, nous pouvons voir la requête arriver sur le server distant. C'est un énorme gâchis horrible, mais c'est définitivement invalide. Il essaie de referencer une table dérivée qui n'est pas dans la scope. Le lot entier sera familier à tous ceux qui ont travaillé avec des servers distants dans 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 

Le vrai problème est l'instruction SQL qu'un autre server SQL a demandé au server de préparer. Trimmed, il dit:

 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'}' 

C'est une lecture compliquée, mais vous pouvez voir le problème, c'est referencer Tbl1002 dans certaines tables dérivées nestedes:

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

Mais seulement le déclarer dehors; à la fin:

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

De quelles versions de SQL Server parlons-nous ici?

Le server "distant" que nous essayons d'interroger ("wclhr") est SQL Server 2000 avec SP4:

Microsoft SQL Server 2000 – 8.00.2066 (Intel X86) 11 mai 2012 18:41:14

Lors de l'émission de la requête, nous avons essayé à partir de SQL Server 2005 et de SQL Server 2008 R2. Il fonctionnait lorsque les deux servers étaient SQL Server 2000.

À partir de SQL Server 2005 et continuant vers 2008 R2, il génère un SQL non valide !

D'autres choses que nous avons essayées

Surprenant, un horrible hack est de courir:

 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 

Cela empêche le SQL Server 2008 R2 local de générer un SQL non valide pour la machine 2000.

Les servers locaux ne sont pas 64 bits, mais nous avons mis à jour les catalogues sur SQL Server 2000 de toute façon . Ça n'a pas arrangé ça.

Votre requête initiale n'est-elle pas aussi fausse?

@Damien l'Incroyable ne croit pas que la scope peut être le problème. Rassurez-vous, ça l'est. Ma requête d'origine s'exécute correctement sur SQL Server 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}' 

Malheureusement, l'optimiseur SQL Server 2005/2008 / 2008R2 transforme cette requête en une requête équivalente, mais malheureusement, SQL Server 2000 ne peut pas l'exécuter:

 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' 

Qui, sur SQL Server 2000, donne:

 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 semble avoir des problèmes de scope avec des sous-requêtes corrélées; qui ont été "améliorés" dans SQL Server 2005.

Lecture bonus

  • Microsoft Connect: sql2005 sp2 – problème avec le server lié (sql2000) et sous-requête corrélée dans la clause where
  • La sous-requête corrélée échoue lors de l'utilisation d'une table sur un server lié
  • KB825019: CORRECTIF: une requête de server lié échoue avec le message d'erreur "Statement (s) n'a pas pu être préparé" dans SQL Server 2000

    En fonction de la lecture que vous avez jointe, il semble que si vous essayez de vraiment contourner ce problème, vous devrez restructurer votre requête afin d'éviter la sous-requête corrélée sur le server lié.

    Une possibilité pourrait être d'inclure votre table liée en tant que jointure dans une sélection groupée et d'évaluer le nombre agrégé dans cette déclaration.

     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