Symptomy
Zapytania rozproszone korzystające z funkcji OPENQUERY w celu aktualizowania, usuwania lub wstawiania danych w następujący sposób
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')
może generować następujące komunikaty o błędach:
Serwer: MSG 7357, Level 16, State 2, wiersz 1 nie można przetworzyć obiektu "Update testlinked Set SSN = SSN". Dostawca OLE DB "SQLOLEDB" wskazuje, że obiekt nie zawiera kolumn. Serwer: MSG 7357, Level 16, State 2, Line 1 [Microsoft] [ODBC SQL Server Driver] [SQL Server] nie można przetworzyć obiektu "Update testlinked Set SSN = SSN". Dostawca OLE DB "MSDASQL" wskazuje, że obiekt nie ma kolumn.
Rzeczywisty komunikat tekstowy błędu może być różny w zależności od dostawcy OLE DB oraz operacji (UPDATE, INSERT lub DELETE), ale numer błędu jest zawsze 7357. Jeśli korzystasz z programu Microsoft SQL Server 2005, zostanie wyświetlony następujący komunikat o błędzie:
Serwer: MSG 7357, poziom 16, stan 2, linia 1 nie może przetworzyć obiektu "Update testlinked Set SSN = SSN". Dostawca OLE DB "SQLOLEDB" dla połączonego serwera "nazwa_serwera" wskazuje, że obiekt nie ma kolumn lub bieżący użytkownik nie ma uprawnień do tego obiektu.
Przyczyna
OPENQUERY wymaga zwrócenia zestawu wyników, ale instrukcje Update, DELETE i Insert używane z opcją OPENQUERY nie zwracają zestawu wyników.
Obejście
Ten problem można obejść na następujące sposoby:
-
Aby wykonać operacje INSERT, Update lub DELETE, użyj nazw czterech części (linked_server_name. Catalog. Schema. object_name).
-
Jak opisano w dokumentacji książki online programu SQL Server, należy odwołać się do funkcji OPENQUERY jako tabeli docelowej instrukcji INSERT, Update lub DELETE, pod warunkiem możliwości dostawcy OLE DB. Poniższe zapytania demonstrują właściwe użycie u dostawcy OLE DB programu 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')
Uwaga W instrukcji INSERT użyto predykatu WHERE 1 = 0, aby uniknąć pobierania danych z serwera zdalnego, co może powodować wolniejszą wydajność. Ponadto operacje aktualizowania i usuwania mają specjalne wymagania dotyczące indeksu; Aby uzyskać szczegółowe informacje, zobacz sekcję "więcej informacji".
Więcej informacji
Wymaganie dotyczące indeksu unikatowego
Dostawca OLE DB programu SQL Server wymaga, aby w tabeli źródłowej istniał indeks unikatowy dla operacji UPDATE lub DELETE. Jeśli w tabeli zdalnej nie istnieje indeks unikatowy, podczas próby aktualizacji lub usunięcia jest wyświetlany następujący błąd:
Serwer: MSG 7320, poziom 16, stan 2, wiersz 1 nie można wykonać zapytania dotyczącego dostawcy OLE DB "SQLOLEDB". Dostawca nie obsługuje wymaganego interfejsu wyszukiwania wierszy. Dostawca wskazuje, że wystąpiły konflikty z innymi właściwościami lub wymaganiami. [Dostawca OLE/DB zwrócił komunikat: Błędy generowane przez Wieloetapową bazę danych OLE. Zaznacz poszczególne wartości statusu OLE DB (jeśli są dostępne). Nie wykonano żadnej pracy.
Dotyczy to zarówno poleceń OPENQUERY , jak i czterech-części o nazwanych operacjach Update i DELETE. Problem został rozwiązany przez dodanie indeksu unikatowego do zdalnej tabeli.
Dynamiczne wykonywanie z OpenQuery
Czasami może być wskazane użycie zapytania dynamicznego w celu osiągnięcia tego samego skutku przy użyciu funkcji OPENQUERY, jak pokazano w poniższym przykładzie:
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