473,773 Members | 2,334 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Delete all records NOT referenced by Foreign Keys

I'd like to run a clean up command on my tables to
eliminate rows that I'm no longer using in the database.

I want to do something like this:

DELETE FROM tablename
WHERE IS_REFERENCED_B Y_FOREIGN_KEY IS FALSE;

Does anyone know how something like this could be done
in PostgreSQL? I know I can search all the tables that
I know refer to this table and see if my primary key
exists, but I want a solution that does not require me to
rewrite my code every time a new foreign key constraint
is added to the database.

There must be a way to ask PostgreSQL for a reference count
on a given row or something.

Thanks,

Dante

---------
D. Dante Lorenso
da***@lorenso.c om


---------------------------(end of broadcast)---------------------------
TIP 8: explain analyze is your friend

Nov 12 '05 #1
10 17861
On Sat, Dec 13, 2003 at 02:20:15 -0600,
"D. Dante Lorenso" <da***@lorenso. com> wrote:
I'd like to run a clean up command on my tables to
eliminate rows that I'm no longer using in the database.

I want to do something like this:

DELETE FROM tablename
WHERE IS_REFERENCED_B Y_FOREIGN_KEY IS FALSE;

Does anyone know how something like this could be done
in PostgreSQL? I know I can search all the tables that
I know refer to this table and see if my primary key
exists, but I want a solution that does not require me to
rewrite my code every time a new foreign key constraint
is added to the database.

There must be a way to ask PostgreSQL for a reference count
on a given row or something.


If you are more concerned about flexibility than speed you can do something
like the following:

Set all of your foreign key references to the desired table to use an
on delete restrict clause.

Have your application read all of the key values from the desired table
and for each key issue a delete of that key in its own transaction.
This will fail for keys that are referenced (because of the restrict clause).

A more complicated, less future proof, but more efficient approach would
be to have your application find out which tables have references to the
table of interest by looking at the system catalog and then write a
delete query using appropiate where not exist clauses.

---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

Nov 12 '05 #2
Bruno Wolff III wrote:
On Sat, Dec 13, 2003 at 02:20:15 -0600,
"D. Dante Lorenso" <da***@lorenso. com> wrote:

I'd like to run a clean up command on my tables to
eliminate rows that I'm no longer using in the database.

I want to do something like this:

DELETE FROM tablename
WHERE IS_REFERENCED_B Y_FOREIGN_KEY IS FALSE;

Does anyone know how something like this could be done
in PostgreSQL? I know I can search all the tables that
I know refer to this table and see if my primary key
exists, but I want a solution that does not require me to
rewrite my code every time a new foreign key constraint
is added to the database.

There must be a way to ask PostgreSQL for a reference count
on a given row or something.
If you are more concerned about flexibility than speed you can do something
like the following:

Set all of your foreign key references to the desired table to use an
on delete restrict clause.

Have your application read all of the key values from the desired table
and for each key issue a delete of that key in its own transaction.
This will fail for keys that are referenced (because of the restrict clause).

This is something very ugly indeed and is what I'll have to resort to unless
I can find something cleaner. Ideally, I would be able to run this cleanup
on a subset of the table data after an insert into the table. I would like
the query to be fast, though.

Does anyone know if there is any way to say something like:

DELETE FROM tablename
IGNORE ERRORS;

Where a delete that is possible is performed but ones that throw referencial
integrity voilations would silently fail without abandoning the entire
transaction?

I have the 'on delete restrict' clause on my foreign keys already.
A more complicated, less future proof, but more efficient approach would
be to have your application find out which tables have references to the
table of interest by looking at the system catalog and then write a
delete query using appropiate where not exist clauses.

---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings


---------------------------(end of broadcast)---------------------------
TIP 4: Don't 'kill -9' the postmaster

Nov 12 '05 #3
On Sat, Dec 13, 2003 at 09:48:16PM -0600, D. Dante Lorenso wrote:
This is something very ugly indeed and is what I'll have to resort to unless
I can find something cleaner. Ideally, I would be able to run this cleanup
on a subset of the table data after an insert into the table. I would like
the query to be fast, though.
What about just:

delete from a where a.id not in (select id from b);

or the equivalent exists query.
--
Martijn van Oosterhout <kl*****@svana. org> http://svana.org/kleptog/ (... have gone from d-i being barely usable even by its developers
anywhere, to being about 20% done. Sweet. And the last 80% usually takes
20% of the time, too, right?) -- Anthony Towns, debian-devel-announce


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQE/3AB0Y5Twig3Ge+Y RAtAlAJ9u8mCreN Ipr/Tk69PINKTbHdE+a wCfVuoC
r9kWIkzslXKFGiI kBeuj0iA=
=7P25
-----END PGP SIGNATURE-----

Nov 12 '05 #4
Martijn van Oosterhout wrote:
On Sat, Dec 13, 2003 at 09:48:16PM -0600, D. Dante Lorenso wrote:

This is something very ugly indeed and is what I'll have to resort to unless
I can find something cleaner. Ideally, I would be able to run this cleanup
on a subset of the table data after an insert into the table. I would like
the query to be fast, though.


What about just:

delete from a where a.id not in (select id from b);

or the equivalent exists query.

You missed the previous part of the thread. I have N tables that
have a foreign key to the table in question. Tomorrow there may be
more or fewer foreign key references. Without having to know which
tables have foreign keys on my table, I want to delete all rows
that are not used by any any other table.

PG already can block a delete when it knows that foreign key exists, so
why can't I perform a query that says...

DELETE FROM tablename
WHERE FOREIGN_KEY_EXI STS(oid) IS FALSE;

You see? Something like what I seek never requires ME the developer or
DBA to know about foreign key relationships because I know that PostgreSQL
already does.

To NOT have this functionality does not cause problems, but it does cause
me to waste disk space on rows that are no longer in use. I just want to
do some automated cleanup on tables and just leave that process running
in a crontab nightly or something. I don't want to have to re-write the
cleanup process every time a new dependency is introduced or removed.

I think Bruno had a good idea about using the system tables to determine
relationships, but how to do that is beyond my PostgreSQL expertise at
the moment. I just think there's gotta be an easier way, though...someth ing
like what I describe above.

Dante

----------
D. Dante Lorenso
da***@lorenso.c om

---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to ma*******@postg resql.org

Nov 12 '05 #5

On Sun, 14 Dec 2003, D. Dante Lorenso wrote:
PG already can block a delete when it knows that foreign key exists, so
why can't I perform a query that says...

DELETE FROM tablename
WHERE FOREIGN_KEY_EXI STS(oid) IS FALSE;


That's fairly different from the checks that are performed for the foreign
keys which happen after the action has happened and errors to prevent the
action from being visible. The where clause happens long before that. If
the above has to check each referencing table for matching rows for each
row in tablename, I'd also expect it to perform poorly.

---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to ma*******@postg resql.org

Nov 12 '05 #6

"D. Dante Lorenso" <da***@lorenso. com> writes:
To NOT have this functionality does not cause problems, but it does cause
me to waste disk space on rows that are no longer in use. I just want to
do some automated cleanup on tables and just leave that process running
in a crontab nightly or something. I don't want to have to re-write the
cleanup process every time a new dependency is introduced or removed.


You could just try to delete every record in the desired tables and see if you
get a foreign key violation. You would have to do each delete in a separate
transaction and just ignore any errors.

so you would have to do something like

foreach table in <list of "auto-cleanup" tables>
select id from table
delete from table where id = xx

This would mean your auto-cleanup crontab script doesn't even have to look in
the system catalog to find out the dependencies. It just depends on postgres
knowing all the dependencies and checking them all.

Inevitably though there will be some tables that have some implicit
depenencies that cannot be represented as foreign key references. Or are just
the master records and don't need anything else in the database to depend on
them. So you'll need a list somewhere of tables that are purely subservient to
other tables and can be summarily cleaned up this way.
--
greg
---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to ma*******@postg resql.org so that your
message can get through to the mailing list cleanly

Nov 12 '05 #7
Stephan Szabo wrote:
On Sun, 14 Dec 2003, D. Dante Lorenso wrote:
PG already can block a delete when it knows that foreign key exists, so
why can't I perform a query that says...

DELETE FROM tablename
WHERE FOREIGN_KEY_EXI STS(oid) IS FALSE;


That's fairly different from the checks that are performed for the foreign
keys which happen after the action has happened and errors to prevent the
action from being visible. The where clause happens long before that. If
the above has to check each referencing table for matching rows for each
row in tablename, I'd also expect it to perform poorly.

My hope was that there was some sort of (semaphore? / counter?) associated
with each row that indicated whether a dependency existed at all. Although
that would most likely not be an indexed column, I could apply additional
WHERE constraints to avoid a full table scan.

If such a counter existed, it would certainly speed up deletes when no
foreign
key checks were necessary. But I suppose it would also slow down
deletes when
it becomes necessary to decrement a counter for the dependencies created
by the
row being deleted.

So...internally , how does a row KNOW that it can not be deleted because of
a foreign key constraint? Whatever that mechanism is, isn't there a way for
me to make use of that as I try my query?

And... if not...how about something like this in PL/SQL:

-- Find all the address records which might need to be removed...
FOR my_rec IN
SELECT addr_id
FROM address
WHERE acct_id = in_acct_id
AND addr_is_active IS FALSE
LOOP

-- try to delete this record...
DELETE FROM address
WHERE addr_id = my_rec.addr_id;

END LOOP;

This will loop through the records one at a time and try to delete them.
However, I don't want to have any exceptions thrown if the DELETE action
can not be performed. Is there a TRY/CATCH type of code that I can
surround the DELETE with to prevent the entire operation from being
aborted on the first error found?

Dante

----------
D. Dante Lorenso
da***@lorenso.c om

---------------------------(end of broadcast)---------------------------
TIP 3: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to ma*******@postg resql.org so that your
message can get through to the mailing list cleanly

Nov 12 '05 #8
On Sun, Dec 14, 2003 at 03:02:49AM -0600, D. Dante Lorenso wrote:
My hope was that there was some sort of (semaphore? / counter?) associated
with each row that indicated whether a dependency existed at all. Although
that would most likely not be an indexed column, I could apply additional
WHERE constraints to avoid a full table scan.
Ah, I see. There is no counter. When you delete a row, it does a check on
the referencing table to see if it would break any foreign keys. The system
has a defined trigger for that purpose. If you don't want to have the
trigger error out, you do the same test. That's what my query did.

In fact, you'll be able to do it more efficiently, since you know you'll be
deleting many rows, you can arrange to only scan the referencing table once.

The table with the foreign keys in it would be pg_constraint I think. You
can use -E on psql to see you \d gets the info.
This will loop through the records one at a time and try to delete them.
However, I don't want to have any exceptions thrown if the DELETE action
can not be performed. Is there a TRY/CATCH type of code that I can
surround the DELETE with to prevent the entire operation from being
aborted on the first error found?
That would be subtransactions , and they're not done yet.
--
Martijn van Oosterhout <kl*****@svana. org> http://svana.org/kleptog/ (... have gone from d-i being barely usable even by its developers
anywhere, to being about 20% done. Sweet. And the last 80% usually takes
20% of the time, too, right?) -- Anthony Towns, debian-devel-announce


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQE/3C6aY5Twig3Ge+Y RAq1LAKCGEBx300 VIoBJ5vLNxBMGj/HYBWACgiiJo
hrxdaBPPLNwM9Kp ZnEs3P1o=
=K5PU
-----END PGP SIGNATURE-----

Nov 12 '05 #9

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Does anyone know how something like this could be done
in PostgreSQL? I know I can search all the tables that
I know refer to this table and see if my primary key
exists, but I want a solution that does not require me to
rewrite my code every time a new foreign key constraint
is added to the database.


Here is a function that removes all non-referenced rows from
a table. Make a backup before using of course. :)

CREATE OR REPLACE FUNCTION delete_nonrefs( TEXT) RETURNS TEXT AS '
DECLARE
mytable ALIAS FOR $1;
mytext TEXT;
myrec RECORD;
deltext TEXT;
myrows INTEGER;
BEGIN

mytext := ''
SELECT
c2.relname AS tname,
SUBSTRING((SELE CT pg_get_constrai ntdef(r.oid)) FROM \'\'\\\\\\\\)[^(]+.([^)]+)\'\') AS fkcol,
SUBSTRING((SELE CT pg_get_constrai ntdef(r.oid)) FROM \'\'\\\\\\\\(([^)]+)\'\') AS mycol
FROM pg_class c, pg_class c2, pg_constraint r
WHERE c.relname = \' || quote_literal(m ytable) || \'
AND r.confrelid = c.oid
AND r.contype = \'\'f\'\'
AND c2.oid = r.conrelid'';

FOR myrec IN EXECUTE mytext LOOP
IF deltext IS NULL THEN deltext := \' \\nWHERE \';
ELSE deltext := deltext || \'\\nAND \';
END IF;
deltext := deltext || \'NOT EXISTS \' ||
\'(SELECT 1 FROM \' || quote_ident(myr ec.tname) || \' t WHERE \' ||
quote_ident(myt able) || \'.\' || myrec.fkcol || \' = t.\' || myrec.mycol || \')\';
END LOOP;

IF deltext IS NULL THEN
RETURN \'Table \' || quote_ident(myt able) || \' is not referenced by any other tables\';
END IF;

deltext := \'DELETE FROM \' || quote_ident(myt able) || deltext;
EXECUTE deltext;
GET DIAGNOSTICS myrows := ROW_COUNT;
RETURN \'Rows deleted from table \' || quote_ident(myt able) || \': \' || myrows;

END;
' LANGUAGE plpgsql STABLE STRICT;

- --
Greg Sabino Mullane gr**@turnstep.c om
PGP Key: 0x14964AC8 200312141306

-----BEGIN PGP SIGNATURE-----

iD8DBQE/3KeCvJuQZxSWSsg RAnNwAJ4v0bh/ATZtTaPqqid43qZ uaFB/0ACdG+GL
m6AtGBa3tNKsoZm y1ir6/KY=
=S39B
-----END PGP SIGNATURE-----

---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

Nov 12 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
3006
by: Vinodh Kumar P | last post by:
I understand the number of foreign keys allowed is restricted by the DBMS I use. In a general relational schema design perspective how many foreign keys a table shall have? If I have large number of foreign keys what anamolies it will lead to? Is this crucial to identify all the foriegn key relationships for a table? Vinodh
26
14145
by: pb648174 | last post by:
I have a table called BidItem which has another table called BidAddendum related to it by foreign key. I have another table called BidFolder which is related to both BidItem and BidAddendum, based on a column called RefId and one called Type, i.e. type 1 is a relationship to BidItem and type 2 is a relationship to BidAddendum. Is there any way to specify a foreign key that will allow for the different types indicating which table the...
6
2812
by: Brendan Jurd | last post by:
Hi all, I read on the manual page for Inheritance that: "A limitation of the inheritance feature is that indexes (including unique constraints) and foreign key constraints only apply to single tables, not to their inheritance children. Thus, in the above example, specifying that another table's column REFERENCES cities(name) would allow the other table to contain city names but not capital names. This deficiency will probably be fixed...
5
3344
by: Ross A. Finlayson | last post by:
Hi, I'm scratching together an Access database. The development box is Office 95, the deployment box Office 2003. So anyways I am griping about forms and global variables. Say for example I'm adding a customer. The Customer fields are mostly foreign keys that refer to primary keys in other tables, left join instead of junction tables at this point. So, when I want to add a customer record, I also need to add records to the other...
1
2097
by: Thomas T. Thai | last post by:
I'm looking for a better way to make use of foreign keys. Here is a sample setup: -- TESTING Foreign Keys create table mod ( mod_id int not null primary key, name varchar(32) not null default '' );
9
3910
by: sonal | last post by:
Hi all, I hv started with python just recently... and have been assigned to make an utility which would be used for data validations... In short we take up various comma separated data files for eg: area.txt, school.txt, students.txt.... and so on (ok?!?) now, 1. area code used in the school.txt must be defined in the area.txt (Primary key in area => area_code defined in area.txt & Foreign key on school => area_code defined in...
6
9770
by: Ivan | last post by:
Hello to all and thanks for answer to my topics. I made one stored procedure that delete one table, but when call/execute the procedure this show SQL0532N A parent row cannot be deleted because the relationship "TXN_TRANSACTION.FK_SCLI " restricts the deletion. Then in the procedure it adds one delete of the foreign keys. This it
6
14302
by: ravichoudhari | last post by:
i came accross requirement of multiple foreign keys in a table referencing the same primary key another table. i created the table relations using the relations editor in access. even though i could have multiple foreign keys to a table access did allow the referential integrity. my database structure is table1 - students table table 2 - subjects table
1
11011
by: apax999 | last post by:
Kinda new to SQL, using SQL Server 2005. I have some foreign keys in a couple of tables. I need to drop these tables, but can't since I'll get the error: Msg 3726, Level 16, State 1, Line 1 Could not drop object 'Client' because it is referenced by a FOREIGN KEY constraint.
0
9454
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10264
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10106
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10039
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8937
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7463
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6717
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
1
4012
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
2852
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.