Recently I had to do some data manipulation against a Sybase linked server running on a Unix box. When you have a linked server you can use OPENQUERY do perform DML statements like delete, update and inserts but the syntax is a little different

So let’s look at some code, first create a linked server on your machine that is linked to your machine. You can add a linked server through the wizard or through the sp_addlinkedserver stored proc

EXEC master.dbo.sp_addlinkedserver @server = N'localhost', @srvproduct=N'SQL Server'

Test that the linked server was created and that you can execute queries against it

select * from openquery(localhost,'select * from sysobjects')

Now that this is done we need to create a table and insert one row of data

use tempdb
go


create table test(id int primary key, col1 varchar(20))
go

insert test values(1,'test1')

Select from the table

select * from test

Output

—————-

id	col1
1	test1

SELECT

A select statement with openquery looks like this

select * from openquery(localhost,'select * from tempdb.dbo.test')

As you can see that was pretty standard

INSERT

an insert statement is a little odd looking because you still have the select in the openquery but the values that you want to insert look like a select statement that come after the openquery. It looks like this

INSERT  OPENQUERY(localhost,'SELECT id,col1 from tempdb.dbo.test ')
SELECT 2,'Test2'

Verify that the data is correct

select * from test

Output

—————-

id	col1
1	test1
2	Test2

UPDATE

The update has a select with a where clause inside the openquery statement and the set statement comes after that. Here is what this looks like

UPDATE OPENQUERY(localhost, 'select id,col1 from tempdb.dbo.test where id = 1 ')
SET id = 3,col1 = 'Test3'

Verify that the data is correct

select * from test

Output

—————-

id	col1
2	Test2
3	Test3

DELETE

Finally a delete will have the where clause inside openquery

DELETE OPENQUERY(localhost, 'select id,col1 from tempdb.dbo.test where id = 2 ')

Verify that the data is correct

select * from test

Output

————–

id	col1
3	Test3

When it doesn’t work

I showed you what worked, now let’s look at some stuff that doesn’t

Create another table that looks like the table we had before but without a primary key

create table test2(id int, col1 varchar(20))
go

insert test2 values(1,'test1')

The select statement works without a problem

select * from openquery(localhost,'select * from tempdb.dbo.test2')

Output

—————-

id	col1
1	test1

The insert statement also works

INSERT  OPENQUERY(localhost,'SELECT id,col1 from tempdb.dbo.test2 ')
SELECT 2,'test2'

Verify that the data is correct

select * from test2
1	test1
2	test2

If you run the following update query

UPDATE OPENQUERY(localhost, 'select id,col1 from tempdb.dbo.test2 where id = 1 ')
SET id = 3,col1 = 'test2'

you will be greeted with this message

_Server: Msg 7320, Level 16, State 2, Line 1

Could not execute query against OLE DB provider ‘SQLOLEDB’. The provider could not support a required row lookup interface. The provider indicates that conflicts occurred with other properties or requirements.

[OLE/DB provider returned message: Multiple-step OLE DB operation generated errors. Check each OLE DB status value, if available. No work was done.]

OLE DB error trace [OLE/DB Provider ‘SQLOLEDB’ ICommandText::Execute returned 0x80040e21: select id,col1 from tempdb.dbo.test2 where id = 1 [PROPID=DBPROP_IRowsetLocate VALUE=True STATUS=DBPROPSTATUS_CONFLICTING], [PROPID=DBPROP_BOOKMARKS VALUE=True STATUS=DBPROPSTATUS_CONFLICTING]]._

The delete has the same issue as the update statement, running the following

DELETE OPENQUERY(localhost, 'select id,col1 from tempdb.dbo.test2 where id = 2 ')

will produce this error message

_Server: Msg 7320, Level 16, State 2, Line 1

Could not execute query against OLE DB provider ‘SQLOLEDB’. The provider could not support a required row lookup interface. The provider indicates that conflicts occurred with other properties or requirements.

[OLE/DB provider returned message: Multiple-step OLE DB operation generated errors. Check each OLE DB status value, if available. No work was done.]

OLE DB error trace [OLE/DB Provider ‘SQLOLEDB’ ICommandText::Execute returned 0x80040e21: select id,col1 from tempdb.dbo.test2 where id = 2 [PROPID=DBPROP_IRowsetLocate VALUE=True STATUS=DBPROPSTATUS_CONFLICTING], [PROPID=DBPROP_BOOKMARKS VALUE=True STATUS=DBPROPSTATUS_CONFLICTING]]._

So what those errors are telling us is that a row lookup could not be performed, this is of course because we don’t have a key on this table. So just be aware of that!

Now that we are done we can drop the linked server, you can use sp_dropserver to do that

sp_dropserver 'localhost'

*** If you have a SQL related question try our Microsoft SQL Server Programming forum or our Microsoft SQL Server Admin forum