Ah, the idiocies of Oracle's database language, PL/SQL.
Let's say you're trying to fix things for a few thousand customers who have managed to create duplicate accounts. You want to delete the duplicate accounts, which are listed in a driver table called DUPLICATE_ACCOUNTS. Knowing that committing a few rows at a time is a good thing on a running database, you might try something like the following:
DECLARE
CUSTOMER_ID NUMBER;
CURSOR CDEL_CUR IS SELECT CUSTOMER_ID
FROM ADMIN.DUPLICATE_CUSTOMERS;
BEGIN
OPEN CDEL_CUR;
LOOP
FETCH CDEL_CUR INTO CUSTOMER_ID;
EXIT WHEN CDEL_CUR%NOTFOUND;
DELETE FROM CUSTOMERS
WHERE CUSTOMERS.CUSTOMER_ID = CUSTOMER_ID;
COMMIT;
END LOOP;
CLOSE CDEL_CUR;
END;
Note the boldfaced delete clause. One might expect this to find the row where the CUSTOMER_ID is the same as the CUSTOMER_ID we just fetched from the driver table. But no! Oracle interprets this the same as:
DELETE FROM CUSTOMERS
WHERE CUSTOMERS.CUSTOMER_ID = CUSTOMERS.CUSTOMER_ID;
In other words, those rows whose CUSTOMER_ID is equal to itself -- which (since there are no null CUSTOMER_IDs) is every single freaking row in the database!
Yes, I did this (well, something similarly disasterous) at work today. Yes, it was a production database. No, thankfully nothing crashed -- our databases are so busy that this immediately got hung up waiting for locks that we were able to kill it once we realized what was happening.
I'm not a DBA. I just play one on TV.
Thursday, January 17, 2008
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment