A SELECT statement with a WHERE clause that involves 3 sub-selects
returns one row. An UPDATE statement with the same WHERE clause
updates 4 rows. It seems to me this is a clear bug in SQL 2000 (SP
2). It used to work fine in SQL 7.
Can anyone tell me whether the SQL is suspect, otherwise, perhaps an
MVP could pick this up and report it to Microsoft. In the meantime, I
guess I'll have to achieve the same thing with different SQL.
How to reproduce the problem:
1. create a table and its primary key (in any database):
CREATE TABLE [dbo].[test_table] (
[oh_id] [nvarchar] (20) COLLATE Latin1_General_CI_AS NOT NULL ,
[ct_id] [nvarchar] (2) COLLATE Latin1_General_CI_AS NOT NULL ,
[mto_id] [nvarchar] (2) COLLATE Latin1_General_CI_AS NOT NULL ,
[term_id] [nvarchar] (3) COLLATE Latin1_General_CI_AS NULL ,
[oh_orderpos] [smallint] NULL ,
[oh_duedate] [datetime] NULL ,
[st_id] [smallint] NULL ,
[oh_selected] [bit] NULL ,
[oh_uploaded] [bit] NULL ,
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[test_table] ADD
CONSTRAINT [PK_test_table] PRIMARY KEY NONCLUSTERED
(
[oh_id],
[ct_id],
[mto_id]
) ON [PRIMARY]
GO
2. Insert 5 records:
insert test_table values ('10010524', 'CH', 0, NULL, 2, '2003-01-29',
13, 0, 0)
insert test_table values ('10010524', 'FR', 0, NULL, 3, '2003-01-29',
13, 0, 0)
insert test_table values ('10010524', 'AM', 0, NULL, 1, '2003-01-29',
13, 0, 0)
insert test_table values ('10010524', 'MO', 0, NULL, 4, '2003-01-29',
13, 0, 0)
insert test_table values ('10010524', 'MO', 01, NULL, 5, '2003-01-29',
13, 0, 0)
go
3. Run this SELECT query. It will return 1 record as expected:
SELECT * FROM test_table
WHERE oh_id IN
(SELECT TOP 1 O.oh_id
FROM test_table O
WHERE O.oh_selected = 0 AND
O.oh_uploaded = 0 AND
(O.st_id = 13 OR O.st_id = 16) AND
(oh_duedate = '29 Jan 2003' OR oh_duedate = '30 Jan
2003')
ORDER BY O.oh_orderpos ASC)
AND ct_id IN
(SELECT TOP 1 O.ct_id
FROM test_table O
WHERE O.oh_selected = 0 AND
O.oh_uploaded = 0 AND
(O.st_id = 13 OR O.st_id = 16) AND
(oh_duedate = '29 Jan 2003' OR oh_duedate = '30 Jan
2003')
ORDER BY O.oh_orderpos ASC)
AND mto_id IN
(SELECT TOP 1 O.mto_id
FROM test_table O
WHERE O.oh_selected = 0 AND
O.oh_uploaded = 0 AND
(O.st_id = 13 OR O.st_id = 16) AND
(oh_duedate = '29 Jan 2003' OR oh_duedate = '30 Jan
2003')
ORDER BY O.oh_orderpos ASC)
4. Now run this UPDATE statement. Since it uses the same WHERE clause
as the SELECT above, it should update 1 record, but it actually
updates 4 records. Transactions are used to preserve the data allowing
me to run the test more than once.
begin transaction
GO
UPDATE test_table
SET term_id = '001', st_id = 14, oh_selected = -1
WHERE oh_id IN
(SELECT TOP 1 O.oh_id
FROM test_table O
WHERE O.oh_selected = 0 AND
O.oh_uploaded = 0 AND
(O.st_id = 13 OR O.st_id = 16) AND
(oh_duedate = '29 Jan 2003' OR oh_duedate = '30 Jan
2003')
ORDER BY O.oh_orderpos ASC)
AND ct_id IN
(SELECT TOP 1 O.ct_id
FROM test_table O
WHERE O.oh_selected = 0 AND
O.oh_uploaded = 0 AND
(O.st_id = 13 OR O.st_id = 16) AND
(oh_duedate = '29 Jan 2003' OR oh_duedate = '30 Jan
2003')
ORDER BY O.oh_orderpos ASC)
AND mto_id IN
(SELECT TOP 1 O.mto_id
FROM test_table O
WHERE O.oh_selected = 0 AND
O.oh_uploaded = 0 AND
(O.st_id = 13 OR O.st_id = 16) AND
(oh_duedate = '29 Jan 2003' OR oh_duedate = '30 Jan
2003')
ORDER BY O.oh_orderpos ASC)
GO
rollback transaction
GO