Foreign key "code tables" are ubiquitous in good database design; another
example is zip/postal codes and cities.  Statuses are another standard
usage.  Thus, what you're doing is absolutely bog-standard.  (In your case,
I would add "taxonomy_edition" to the species table.  You get more
information, and don't have to update the species table; just add more to
it.  New sightings can use the new taxonomy.)

As to whether it would work... I absolutely _would not_ go mucking around
in the catalog.  Bite the bullet and ALTER the twenty-odd columns to TEXT.

(Why TEXT and not a DOMAIN?  Simplicity.)

On Wed, May 28, 2025 at 8:33 AM Richard Zetterberg <
richard.zetterb...@googlemail.com> wrote:

> Thanks for the reply, Adrian!
>
> I must have explained my problem poorly, sorry for that.
>
> Let me present an imaginary scenario and hopefully that clears things up.
>
> It's 2015 and you want to start a birdwatching club and want to keep track
> of sightings in a postgres database.
>
> To make sure that users in your birdwatching club all enter the specie of
> the observed bird correctly, you decide to create a table that will contain
> all distinct bird species. Since there are over >10 000 bird species you
> decide to download an existing taxonomy of bird species. On
> birdtaxonomies.com you download edition 5 of the bird species taxonomy as
> a CSV-file. Each row of this file represents a bird specie and it has two
> columns: unique ID and name.
>
> You observe that the IDs in the downloaded file have at most 6 characters.
> To make room for additional bird species in coming editions of the
> taxonomy, you decide to use `varchar(7)` as the type of the ID column. To
> improve readability, you create a type alias:
>
> ```
> CREATE DOMAIN species_id AS varchar(7);
> ```
>
> Then you create the table that contains the bird species taxonomy:
>
> ```
> CREATE TABLE species (
>   id   species_id PRIMARY KEY,
>   name text       NOT NULL
> );
> ```
>
> Once all the bird species are imported from the taxonomy file into the
> `species` table, nothing is changed in this file.
>
> To guarantee that people enter the specie correctly, you now add a foreign
> key to all of your observation tables referencing the `species` table.
> Here's an example of what one of those tables look like:
>
> ```
> CREATE TABLE sightings (
>   id          serial                 PRIMARY KEY,
>   specie_id   species_id             NOT NULL REFERENCES species (id),
>   coordinates geography(POINT, 4326) NOT NULL,
>   date        timestamptz            NOT NULL
> );
> ```
>
> Each year, birdtaxonomies.com release a new edition of the bird species
> taxonomy, that you update your species table with. But this year,
> birdtaxonomies.com comes decides they want a more fine grained way of
> classifying bird species, which results in latest edition of bird species
> taxonomy to have more than 1 million species and IDs that are as long as 9
> characters.
>
> After these 10 years your club has more than 1 million members worldwide,
> more than 20 different kinds of observations tables, procedures and views,
> billions of rows of different kinds of observations and a total size of
> over 100 GB.
>
> In order to import the latest taxonomy, you need to change the type of the
> domain `species_id` from `varchar(7)` to `text`. But postgres doesn't allow
> you to change the type of a domain with a single command. Instead what you
> need to do is:
>
> 1. Rename current domain: `ALTER DOMAIN species_id RENAME TO
> species_id_depricated;`
> 2. Create a new domain: `CREATE DOMAIN species_id AS text;`
> 3. Change all >20 tables, procedures and views to use the new domain
> 4. Drop the old domain
>
> You had done a similar but smaller change a couple of years ago, and that
> meant days of downtime. Also, you are a lazy person and it's tedious to
> write the SQL code to change all tables, procedures and views. So, you
> decide to manipulate `pg_type` directly, since you read somewhere online
> that `varchar` and `text` are basically the same under the hood.
>
> End of story.
>
> Basically, I was hoping that my shortcut would save time and that this
> small `pg_type` manipulation can be done without any side effects. I don't
> have any knowledge of postgres internals, so I don't know if postgres would
> accept this change and carry on like nothing happened. Or, if it will break
> my indices or how queries are executed.
>
> In my head, this change would be instant and postgres would carry on like
> nothing happened and that the domain always had the type `text`. Is this a
> fools errand? Or could it actually make sense in this situation?
>
> Thanks
> Richard
>
> On Tue, May 27, 2025 at 8:10 PM Adrian Klaver <adrian.kla...@aklaver.com>
> wrote:
>
>>
>>
>> On 5/27/25 7:27 AM, Richard Zetterberg wrote:
>> > Hello,
>> >
>> > I have a read-only table that contains a set of never changing
>> > categories. Each category has a unique alpha numerical ID and a
>> > description. The purpose of this table is so that other tables can
>> > reference the ID of this table, to make sure that they don't contain
>> > invalid/unknown categories and so that users can lookup the description
>> > of each category.
>> Define 'read-only'. In other words can you temporarily make it not
>> read-only and change the type to text(or just varchar (no length
>> specifier)?
>> This would be the easiest fix.
>>
>> >
>> > This category table has the following type on the ID column:
>> > "varchar(7)" (yes, I should have used text). In order to avoid having
>> to
>> > type "varchar(7)" in all the tables that references the category table,
>> > I created this domain that I used as type for all referencing columns:
>> > "CREATE DOMAIN cat.id <http://cat.id> AS varchar(7);".
>> >
>> > During some data archeology, I found a bunch of new categories that
>> > haven't been imported into the database yet, and they have IDs longer
>> > than 7.
>>
>> If the read-only table field has a maximum length of 7 and you have
>> incoming data that is coming in longer then 7 characters, how are they
>> going to reference the read-only table?
>>
>> >
>> > I've seen claims that varchar and text have the same representation on
>> > disk and that they are treated the same way "under the hood", except
>> for
>> > the extra constraint checks on varchar. So, I thought that maybe I
>> could
>> > just change the type of my domain to text, directly in pg_type and that
>> > should solve my problems
>>
>> Per my comment above, how?
>>
>>
>> > Thanks for any insight,
>> > Richard Zetterberg
>>
>> --
>> Adrian Klaver
>> adrian.kla...@aklaver.com
>>
>

-- 
Death to <Redacted>, and butter sauce.
Don't boil me, I'm still alive.
<Redacted> lobster!

Reply via email to