Mensajes de error al realizar una instrucción UPDATE, INSERT o DELETE de Transact-SQL en una tabla remota mediante la función OpenQuery: "7357" y "7320"


Síntomas


Consultas distribuidas que usan la función OPENQUERY para actualizar, eliminar o insertar datos de la siguiente manera
exec sp_dropserver 'linked1', 'droplogins'exec sp_addlinkedserver 'linked1', 'SQL Server'exec sp_setnetname  'linked1', '<servername>'exec sp_addlinkedsrvlogin 'linked1', 'false', null, '<login name>', '<password>'SET ANSI_NULLS ONgoSET ANSI_WARNINGS ONgoselect * from openquery (linked1, 'update testlinked set ssn=ssn+1')select * from openquery (linked1, 'insert into  testlinked  (ssn) values (1000)')select * from openquery (linked1, 'delete from  testlinked  where ssn=1')
puede generar los siguientes mensajes de error:
Servidor: msj 7357, nivel 16, estado 2, línea 1 no se pudo procesar el objeto ' Update testlinked Set SSN = SSN '. El proveedor OLE DB ' SQLOLEDB ' indica que el objeto no tiene columnas. Servidor: msg 7357, nivel 16, estado 2, línea 1 [Microsoft] [controlador ODBC SQL Server] [SQL Server] no se pudo procesar el objeto ' Update testlinked Set SSN = SSN '. El proveedor OLE DB ' MSDASQL ' indica que el objeto no tiene columnas.
El mensaje de texto real del error puede variar según el proveedor de OLE DB y la operación (actualizar, insertar o eliminar) que se realicen, pero el número de error siempre es 7357. Si está usando Microsoft SQL Server 2005, recibirá el siguiente mensaje de error:
Servidor: msj 7357, nivel 16, estado 2, línea 1 no se puede procesar el objeto "Update testlinked Set SSN = SSN". El proveedor OLE DB "SQLOLEDB" del servidor vinculado "nombreservidor" indica que el objeto no tiene columnas o que el usuario actual no tiene permisos sobre ese objeto.

Causa


OPENQUERY requiere que se devuelva un conjunto de resultados, pero las instrucciones Update, Delete e Insert que se usan con OPENQUERY no devuelven un conjunto de resultados.

Solución alternativa


Puede solucionar este problema de las siguientes maneras:
  1. Use nombres de cuatro partes (linked_server_name. Catalog. Schema. object_name) para realizar operaciones de inserción, actualización o eliminación.
  2. Como se describe en los libros en línea de SQL Server, haga referencia a la función OPENQUERY como la tabla de destino de una instrucción INSERT, Update o DELETE, sujeta a las funciones del proveedor OLE DB. Las siguientes consultas demuestran el uso adecuado con el proveedor OLE DB de SQL Server:
    update openquery(linked1, 'select ssn from testlinked where ssn=2')set ssn=ssn + 1insert openquery(linked1, 'select ssn from testlinked where 1=0') values (1000)delete openquery(linked1, 'select ssn from testlinked where ssn>100')
    Nota En la instrucción INSERT, se usa un predicado WHERE 1 = 0 para evitar la recuperación de datos desde el servidor remoto, lo que puede dar lugar a un menor rendimiento. Además, las operaciones de actualización y eliminación tienen requisitos de índice especiales; para obtener más información, consulta la sección "más información".

Más información


Requisito de índice único

El proveedor OLE DB de SQL Server requiere que exista un índice único en la tabla subyacente para las operaciones de actualización o eliminación. Si no existe un índice único en una tabla remota, se produce el error siguiente cuando se intenta una actualización o una eliminación:
Servidor: msj 7320, nivel 16, estado 2, línea 1 no se pudo ejecutar la consulta con el proveedor OLE DB ' SQLOLEDB '. El proveedor no es compatible con la interfaz de búsqueda de filas requerida. El proveedor indica que se han producido conflictos con otras propiedades o requisitos. [Proveedor OLE/DB devolvió el mensaje: la operación OLE DB de varios pasos generó errores. Compruebe el valor de estado de la BD de OLE, si está disponible. No se ha realizado ningún trabajo.
Esto se aplica a las operaciones de actualización y eliminación de cuatro partes y con nombre. El problema se resuelve agregando un índice único en la tabla remota.

Ejecución dinámica con OpenQuery

A veces puede ser deseable usar una consulta dinámica para lograr el mismo efecto mediante OPENQUERY, como se muestra en el siguiente ejemplo:
begin tranSET QUOTED_IDENTIFIER OFFSET XACT_ABORT ONdeclare @cmd varchar(2500) declare @cmd1 varchar(2500) declare @var varchar(20) set @var = 'White' declare @var1 varchar(20) set @var1 = 'White1' declare @var2 varchar(20) set @var2 = 'Johnson1'select @cmd = "Update openquery(linked1,'select au_lname, au_fname from pubs.dbo.authorswhere au_lname = ''" + @var + "''' )set au_lname = '" + @var1 + "',au_fname = '" + @var2 + "'"exec ( @cmd )commit transelect * from <servername>.pubs.dbo.authors