PostgreSQL: arrays of foreign keys? - postgresql

I have a PostgreSQL table containing a bunch of foreign keys pointing to another table:
create table foo (
hourly00 uuid references hourly(id),
hourly01 uuid references hourly(id),
-- etc.
hourly23 uuid references hourly(id),
-- omit rest
);
Admittedly, this looks silly (and I am lucky to have only 24 of such keys), but I have not found anything better.
In the meantime, I stumbled on PostgreSQL documentation about arrays (I did not know about PostgreSQL arrays before). I got an idea and I tried this:
create table foo (
hourly uuid[24] references hourly(id)
);
which, of course, immediately resulted in an error:
ERROR: foreign key constraint "main_hourly_fkey" cannot be implemented
DETAIL: Key columns "hourly" and "id" are of incompatible types: uuid[] and uuid.
But then I got another idea — to ask about my situation on StackOverflow. So my question is: does PostgreSQL provide means for doing something like this, i.e. for having an array of foreign keys in a table? Is it perhaps doable with some PL/*? Or perhaps with some other database system? I am willing to do my own research, but I have no idea as to where to look.

Related

Errors creating constraint trigger

Let me start by saying that I’m a Linux/Unix admin. That being said my manager has tasked me with moving older PostgreSQL databases to a RedHat server running 8.4.20. I was successful moving a 7.2.1 db but I’m running into issues moving a 7.4.20 db.
I use pg_dump –c filename and psql < filename. For the problematic db everything runs until I get to a CREATE CONSTRAINT TRIGGER statement. If I run it as it is in the file I get :
NOTICE: ignoring incomplete trigger group for constraint "" FOREIGN KEY data(ups) REFERENCES upsinfo(ups)
DETAIL: Found referenced table's DELETE trigger.
CREATE TRIGGER
If I run set schema 'pg_catalog'; I get:
ERROR: relation "upsinfo" does not exist
The tables (I think) involved are:
CREATE TABLE upsinfo (
ups text NOT NULL,
ipaddr inet,
rcomm text,
wcomm text,
reachable boolean,
managed boolean,
comments text,
region text
);
CREATE TABLE data (
date timestamp with time zone,
ups text,
mib text,
value text
);
The trigger problem trigger statement:
CREATE CONSTRAINT TRIGGER "<unnamed>"
AFTER DELETE ON upsinfo
FROM data
NOT DEFERRABLE INITIALLY IMMEDIATE
FOR EACH ROW
EXECUTE PROCEDURE "RI_FKey_cascade_del"('<unnamed>', 'data', 'upsinfo', 'UNSPECIFIED', 'ups', 'ups');
I know that the RI_FKey_cascade_del function is defined differently in the different versions of pg_catalog. Note that search_path is set to ‘public, pg_catalog’ so I’m also confused why I have to set the schema.
Again I’m not a real PostgreSQL DBA so try to be kind.
Oof, those are really old postgres versions, including the version you're upgrading to (8.4 was released in 2009, and support ended in 2014).
The short answer is that, as long as upsinfo and data are being created and populated, you're probably fine, and good to go. But one of your foreign key relationships is broken.
The long answer, well, let me see if I can explain what is going on (or, at least, what I think is going on).
I'm guessing that the original table definition of data included something like FOREIGN KEY (ups) REFERENCES upsinfo (ups) ON DELETE CASCADE. That causes postgres to automatically make some trigger constraints: 1- every time there's a new row for data, make sure that its ups column matches an existing row in upsinfo, and 2- every time you delete a row from upsinfo, delete the corresponding rows in data, based on the matching ups value.
That (not very informative) error message can come up when the foreign key relationship doesn't work. In order for a foreign key to make sense, the referenced value needs to be unique -- there should be only one row in upsinfo for each distinct value of ups. In order for postgres to know that, there needs to be a unique index or primary key on upsinfo.ups.
In this case, one of a couple things could be breaking it:
There's no primary key or unique index on upsinfo.ups (postgres should not have allowed a foreign key, but may have in very old versions)
There used to be a unique index, but it hadn't properly enforced uniqueness, so it didn't get successfully imported (a bug, again likely from a very old version)
In either case, if that foreign key relationship is important, you can try to fix it once the import is complete. Start by trying to make a unique index on upsinfo.ups, and see if you have problems. If you do, resolve the duplicate entries, and try again till it works. Then issue something like:
ALTER TABLE data
ADD FOREIGN KEY (ups) REFERENCES upsinfo (ups) ON DELETE CASCADE;
Of course, if things are working, it's possible you don't need to fix the foreign key, in which case you're probably able to ignore those errors and just move forward.
Hope that helps, and good luck!
This seems to be a part of ON DELETE CONSTRAINT. If I were you I would delete all such statements and replace them with a proper constraint definition on the target table.
Table definition should then look like this:
CREATE TABLE bookings (
boo_id serial NOT NULL,
boo_hotelid character varying NOT NULL,
boo_roomid integer NOT NULL,
CONSTRAINT pk_bookings
PRIMARY KEY (boo_id),
CONSTRAINT fk_bookings_boo_roomid
FOREIGN KEY (boo_roomid)
REFERENCES rooms (roo_id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
) WITHOUT OIDS;
And this part is what will internally create the trigger:
CONSTRAINT fk_bookings_boo_roomid
FOREIGN KEY (boo_roomid)
REFERENCES rooms (roo_id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
But, to be honest, I do not have an understanding for an upgrade to an unsupported version. You know the Postgres is version 9.5 now, right?

Foreign key constraint with no from column

In our database we happen to have a foreign key constraint that has an empty from column
It looks something like this
fk_1049376c154c25f8 FOREIGN KEY () REFERENCES table2 (id)
What does this denote and where is a documentation in the Postgres documentation for this
I see three possible meanings
use the same column name as referenced in the second table so meaning (id) references table2 (id) implicitly
use the primary key which would be id in this table so it might also be (id) references table (id)
or monitor all columns (*) references table2 (id) which actually seems to be the way this behaves but does not make any sense to me in using it
Can anyone point me to a correct explanation or some read that confirms any of my theories or gives me the real truth?
Trying to use this throws a syntax error in PostgreSQL 9.3 at least.
postgres=# alter table test add foreign key () references test(id);
ERROR: syntax error at or near ")"
LINE 1: alter table test add foreign key() references test(id);
I am guessing this comes from psql \d or something so it sounds like something wrong in your database, perhaps some sort of catalog corruption.
At any rate it is not a valid syntax and you should look into where this is coming from and fixing it.

Postgresql and primary key, foreign key indexing

On https://stackoverflow.com/questions/10356484/how-to-add-on-delete-cascade-constraints#= a user, kgrittn, commented saying that
But I notice that you have not created indexes on referencing columns... Deletes on the referenced table will take a long time without those, if you get many rows in those tables. Some databases automatically create an index on the referencing column(s); PostgreSQL leaves that up to you, since there are some cases where it isn't worthwhile.
I'm having difficulty understanding this completely. Is he saying that primary keys are not created automatically with an index or is he saying that foreign keys should be indexed (in particular cases that is). I've looked at the PostgreSQL documentation and it appears from there that an index is created for primary keys automatically. Is there a command I can use to list all indexes?
Thanks
A primary key is behind the scenes a special kind of a unique index. The quote referencing, that it might be a good idea to create an index also on columns, where the primary key is used as an foreign key.

Unique Constraint error creating tables in PostgreSQL (migrated from MySQL)

I read with great enthusiasm the question entitled Migrate from MySQL to PostgreSQL on Linux (Kubuntu). The Star Wars theme made it that much more entertaining. But I've run into an issue regarding Unique Constraints in PostgreSQL.
I followed the above post closely to create a PostgreSQL DDL using sqlt. The thought process was to create the schema/tables first and then import the data. However 57 of my 72 tables use CONSTRAINT "userid" UNIQUE ("user_id", "key")
Here is an example of one of the tables:
CREATE TABLE "account_otherserviceinfo" (
"id" serial NOT NULL,
"user_id" bigint NOT NULL,
"key" character varying(50) NOT NULL,
"value" text NOT NULL,
PRIMARY KEY ("id"),
CONSTRAINT "user_id" UNIQUE ("user_id", "key")
);
When I copy these tables into my PostgreSQL DB using the Query tool in pgadmin3, I get the following error:
ERROR: relation "user_id" already exists
SQL state: 42P07
I did not design this database schema. I am only helping with the migration process. When reading the documentation on Unique Constraints, it appears that it is Ok to use the same name as long as it's in a different table. http://www.postgresql.org/docs/8.3/static/ddl-constraints.html. Am I misinterpreting this?
Any suggestions or pointers would be greatly appreciated.
Thank you!
PS: Thanks https://stackoverflow.com/users/59087/dave-jarvis and https://stackoverflow.com/users/26534/michael-trausch for getting me this far ;-)
When reading the documentation on
Unique Constraints, it appears that it
is Ok to use the same name as long as
it's in a different table.
I'm not sure what part of the documentation you're reading, but you're misinterpreting it. Constraint names have to be globally unique. So you can have as many of these UNIQUE ("user_id", "key") as you like, but you can't name every one of them "user_id".
You can get around this type of issue by giving your constraints more detailed names.
You will need to come up with a naming standard for you database objects to avoid this type of issue. Maybe something like type_schema_tablename_columnname. So for example uidx_public_account_otherserviceinfor_user_id_key. That type of name will make sure you don't have issues and makes it easy to figure out what object an error message is referring to. You can debate the clearest way to implement what I said, but the key point is come up with a standard to use for all objects that works for your enviroment.
You should not use user_id as constraint name because it is already used as column name.

django: manually adding a foreign key column (newcolumn_id_refs_id_4bfb2ece ?)

I need to add a foreign key field to an existing django model/postgres table. As per the django documentation, I ran the 'sqlall myapp' command to 'work out the difference'.
The obvious difference is that the table in question now has an extra column with a new contraint, which looks like this:
ALTER TABLE "myapp_mytable" ADD CONSTRAINT newcolumn_id_refs_id_4bfb2ece
FOREIGN KEY ("newcolumn_id") REFERENCES "myapp_theothertable" ("id")
DEFERRABLE INITIALLY DEFERRED;
Before messing with my database, I'd like to understand that statement, in particular, what does the last part of newcolumn_id_refs_id_4bfb2ece refer to?
Thanks,
Martin
It will make PostgreSQL understand and enforce your foreign key to the other table and guarantee there won't be anything in myapp_table.newcolumn that can't be found in myapp_theothertable.id
Actually, your django app will work just fine even without that constraint. However, it's a good idea to have one in place, and if you do afterwards a dumpdata - loaddata -cycle, it will be created.