Bug in WITH clause (subquery factoring clause) in Oracle 11?
I'm using WITH to perform a set comparison in order to qualify a given query as correct or incorrect regarding an existing solution. However, the query does not give the expected result - an empty set - when comparing the solution to itself in Oracle 11 whereas it does in Oracle 10. A minimal example os posted below as script. There are also some observations about changes to the tables or the query that make Oracle 11 returning correct results but in my opinion these changes must not change the semantics of the queries.
Is this a bug or am I getting something wrong? The Oracle versions are mentioned in the script.
------------------------------------------------------
-- Bug in WITH clause (subquery factoring clause)
-- in Oracle Database 11g Enterprise Edition 11.2.0.1.0?
DROP TABLE B PURGE;
DROP TABLE K PURGE;
DROP TABLE S PURGE;
CREATE TABLE S (
m number NOT NULL,
x varchar2(30) NOT NULL
);
CREATE TABLE K (
k char(2) NOT NULL,
x varchar2(50) NOT NULL
);
CREATE TABLE B (
m number NOT NULL ,
k char(2) NOT NULL ,
n number
);
INSERT INTO S VALUES(1, 'h');
INSERT INTO S VALUES(2, 'l');
INSERT INTO S VALUES(3, 'm');
INSERT INTO K VALUES('k1', 'd');
INSERT INTO K VALUES('k2', 'i');
INSERT INTO K VALUES('k3', 'm');
INSERT INTO K VALUES('k4', 't');
INSERT INTO K VALUES('k5', 't');
INSERT INTO K VALUES('k6', 's');
INSERT INTO B VALUES(1, 'k1', 40);
INSERT INTO B VALUES(1, 'k2', 30);
INSERT INTO B VALUES(1, 'k4', 50);
INSERT INTO B VALUES(3, 'k1', 10);
INSERT INTO B VALUES(3, 'k2', 20);
INSERT INTO B VALUES(3, 'k1', 30);
INSERT INTO B VALUES(3, 'k6', 90);
COMMIT;
ALTER TABLE S ADD CONSTRAINT S_pk PRIMARY KEY (m);
ALTER TABLE K ADD CONSTRAINT K_pk PRIMARY KEY (k);
ALTER TABLE B ADD CONSTRAINT B_S_fk
FOREIGN KEY (m) REFERENCES S(m) ON DELETE CASCADE;
CREATE OR REPLACE VIEW v AS
SELECT S.m, B.n
FROM S JOIN B ON S.m=B.m JOIN K ON B.k=K.k
WHERE K.x='d'
ORDER BY B.n DESC;
-- Query 1: Result should be 0
WITH q AS
(
SELECT S.m, B.n
FROM S JOIN B ON S.m=B.m JOIN K ON B.k=K.k
WHERE K.x='d'
ORDER BY B.n DESC
)
SELECT COUNT(*)
FROM
(
(
SELECT * FROM q
MINUS
SELECT * FROM v
)
UNION ALL
(
SELECT * FROM v
MINUS
SELECT * FROM q
)
);
-- COUNT(*)
-- --
-- 6
--
-- 1 rows selected
-- Query 2: Result set should be empty (Query 1 without counting)
WITH q AS
(
SELECT S.m, B.n
FROM S JOIN B ON S.m=B.m JOIN K ON B.k=K.k
WHERE K.x='d'
ORDER BY B.n DESC
)
SELECT *
FROM
(
(
SELECT * FROM q
MINUS
SELECT * FROM v
)
UNION ALL
(
SELECT * FROM v
MINUS
SELECT * FROM q
)
);
-- M N
-- --- ---
-- null 10
-- null 30
-- null 40
-- 1 40
-- 3 10
-- 3 30
--
-- 6 rows selected
-- Observations:
-- Incorrect results in Oracle Database 11g Enterprise Edition 11.2.0.1.0:
-- Query 1 returns 6, Query 2 returns six rows.
-- Correct in Oracle Database 10g Enterprise Edition 10.2.0.1.0.
-- Correct without the foreign key.
-- Correct if attribute x is renamed in S or K.
-- Correct if attribute x is left out in S.
-- Correct without the ORDER BY clause in the definition of q.
-- Only two results if the primary key on K is left out.
-- Correct without any change if not using WITH but subqueries (see below).
-- Fixed queries
-- Query 1b: Result should be 0
SELECT COUNT(*)
FROM
(
(
SELECT * FROM
(
SELECT S.m, B.n
FROM S JOIN B ON S.m=B.m JOIN K ON B.k=K.k
WHERE K.x='d'
ORDER BY B.n DESC
)
MINUS
SELECT * FROM v
)
UNION ALL
(
SELECT * FROM v
MINUS
SELECT * FROM
(
SELECT S.m, B.n
FROM S JOIN B ON S.m=B.m JOIN K ON B.k=K.k
WHERE K.x='d'
ORDER BY B.n DESC
)
)
);
-- COUNT(*)
-- --
-- 0
--
-- 1 rows selected
-- Query 2b: Result set shoud be empty (Query 1b without counting)
SELECT *
FROM
(
(
SELECT * FROM
(
SELECT S.m, B.n
FROM S JOIN B ON S.m=B.m JOIN K ON B.k=K.k
WHERE K.x='d'
ORDER BY B.n DESC
)
MINUS
SELECT * FROM v
)
UNION ALL
(
SELECT * FROM v
MINUS
SELECT * FROM
(
SELECT S.m, B.n
FROM S JOIN B ON S.m=B.m JOIN K ON B.k=K.k
WHERE K.x='d'
ORDER BY B.n DESC
)
)
);
-- M N
-- -- --
--
-- 0 rows selected