I have the following (simplified) structure of a device and log messages which are attached to a device:
CREATE TABLE device (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
serial_number VARCHAR(20) UNIQUE
);
CREATE TABLE error_log (
id SERIAL PRIMARY KEY,
device_id INT NOT NULL REFERENCES device(id),
);
I know want to change the schema to use the serial_number
column of the device as the primary key, and drop the automatic key id
. As part of the process I need to add a new column device_serial_number
to the error_log
table. My question is how to assign the values to this column using only SQL.
If a had an ORM mapper in action my pseudo code would look like this:
for log in error_log.all_objects():
log.device_serial_number = log.device.serial_number
Can I do this in pure SQL? (Postgresql if that matters)
2
Answers
You need to update the rows in the
error_log
table where thedevice.id
=error.log
match todevice.serial_number
.So, first add a column to
error_log
. And then execute an UPDATE statement as following:Afterwards you should add a UNIQUE constraint to the
error_log.serial_number
and then you can remove theerror_log.device_id
column if you don’t need it anymore.This is doable, just not in a single step.
add the new column to the
error_log
table. This must be nullable for now!Populate the new column with the correct values
Now the new column can be set to NOT NULL and we can remove the existing foreign key.
Now drop the ID column, drop the old unique constraint and define a new primary key. Dropping the old unique constraint will remove the underlying unique index which is no longer needed as the primary key will create a new one.
Note that the
drop constraint error_log_device_id_fkey
anddrop constraint device_serial_number_key
assume the default naming convention that Postgres applies for "unnamed" constraints. You need to check if that really is the name of your foreign key.