Creating one-many relationship between street sections and car scans? - postgresql

I have two tables and need to create a one to many relationship between them. tlbsection represents a series of street sections as lines in a city. Each street section has its own id.
tlbscans represents a on street scan of a street section counting cars on it. I need to relate tlbscans to tlbsection as a street section and can have more than one scan. What is a good way to do this with with the example data below?
tlbsections
ID(PK) | geom | section |
1 | xy | 5713 |
2 | xy | 5717 |
tlbscans
section | a | b |
5713 | 30 | 19 |
5717 | 2 | 1 |

The overwhelming question: Is the column section unique in tlbsections. If it is then create a unique constraint on it. Then create a FK on column section in table `tblscans' referencing. Assuming the tables already exist:
alter table tlbsections
add constraint section_uk
unique section;
alter table tblscans
add constraint scans_section_fk
foreign key (section)
references tlbsections(section);
If column section unique in tlbsections is not unique then you cannot build a relationship as currently defined. Without much more detail, I suggest you add a column to contain tlbsections.id, create a FK on the new column then drop column section tblscans.
alter table tblscans
add tlbsections_id <data type>;
alter table tblscans
add constraint sections_fk
foreign key (tlbsections_id)
references tlbsections(id);
alter table tblscans
drop column section;
There may be other options, but not apparent what is provided.

Related

Delete duplicate entries in Postgresql

I have users table which has multiple same user entries and I need to delete duplicate
entries.How to skip foreign key related entries and delete remaining entries. For example below the entries I have in table.I need to delete duplicate entries which is not related to foreign keys.Could any one please guide how to proceed with this in Postgresql?
id name email role_id
2512 |Raja (Contractor) | raja_test#test.com|5 |
6 |Raja (Contractor) | raja_test#test.com|5 |
5 |Raja (Contractor) | raja_test#test.com|5 |
I have tried below query
delete from users a using users b where a.email=b.email ;
ERROR: update or delete on table "users" violates foreign key constraint "fk_rails_c5e2af0763" on table "devices"
DETAIL: Key (id)=(14) is still referenced from table "devices".
Devices table
id | mac_address | model | user_id
14 | 14:5E:BE:26 |Arris | 6
You can use:
ALTER TABLE users disable TRIGGER ALL;
-- your delete query
ALTER TABLE users enable TRIGGER ALL;
When we use disable trigger all in PostgreSQL, hidden triggers, foreign-key controls, and other constraints for the selected table are also disabled

Creating a 2-way relationship in PostgreSQL table

I have 3 tables representing UUIDs, Name, Location, and Info of a house, room and drawers (this is an example as my work is sensitive).
So, for example 1 house will have many rooms (one to many) and the many rooms will contain many drawers (many to many).
The idea is that an associations table will be created where each UUID of the rows in the table will be associated with the corresponding UUID of the other table.
For example, if I query the house which is represent by ID1 it will return the following:
SELECT * FROM house where 'ID_1='1';
| ID_1|ID_2 |
| ----| -----|
| 1 | 201 |
| 1 | 254 |
| 1 | 268 |
So far, I have created a temporary version of the associations table of how I need it to be represented in the real table. However, now I need a function to automatically fill in the IDs properly for all rows from the temporary associations table to the real associations table. For example:
INSERT INTO associations (id_1, id_2) VALUES
('1','201'),
('201','1')
I need it to be directionless so that when I query id_1 I'm also getting it's linked id_2 in the result
Let's say your query to get a one-way relationship looks like this:
SELECT room_uuid AS left_uuid, house_the_room_is_in_uuid AS right_uuid
FROM rooms
WHERE house_the_room_is_in_uuid IS NOT NULL
AND is_active
All you need to get the reverse relationship is to put the list in the other order; the rest of the query doesn't need to change, however complex it is:
SELECT house_the_room_is_in_uuid AS left_uuid, room_uuid AS right_uuid
FROM rooms
WHERE house_the_room_is_in_uuid IS NOT NULL
AND is_active
Both of those will be valid as queries to insert into a table with two UUID columns:
CREATE TABLE my_lookup_table (left_uuid UUID, right_uuid UUID);
INSERT INTO my_lookup_table (left_uuid, right_uuid)
SELECT ... -- either of the above
To combine them, either insert each into the same table in turn, or use a UNION to create one result set with both sets of rows:
SELECT room_uuid AS left_uuid, house_the_room_is_in_uuid AS right_uuid
FROM rooms
WHERE is_in_house_uuid IS NOT NULL
AND is_active
UNION
SELECT house_the_room_is_in_uuid AS left_uuid, room_uuid AS right_uuid
FROM rooms
WHERE is_in_house_uuid IS NOT NULL
AND is_active
All that's required for a union is that the queries have the same number and type of columns. The names (if relevant at all) come from the first query, but I find it more readable if you include the aliases on both.
Since the result of that UNION is itself just a two-column result set, it can be used with the same INSERT statement as before. That would allow you to insert into the table even if it had a self-referencing foreign key constraint as discussed here:
ALTER TABLE my_lookup_table ADD CONSTRAINT
my_lookup_table_combinations_must_be_unique
UNIQUE (left_uuid, right_uuid);
ALTER TABLE my_lookup_table ADD CONSTRAINT
my_lookup_table_must_have_rows_both_ways_around
FOREIGN KEY (right_uuid, left_uuid)
REFERENCES my_lookup_table (left_uuid, right_uuid);
If you tried to insert just one set of rows, this would fail, but with the UNION, by the end of the statement/transaction, each row is in the table both ways around, so the constraint is met.

How can I update or insert a where by looking to see the data already exists in 2 of the columns?

My table is look like below:
id | u_id | server_id | user_id | pts | level | count | timestamp
I want to check when inserting new data or updating data if the values from data to be inserted already exist in both the server_id or user_id column. In other words, no two rows can have the same server_id or user_id.
Add an unique constraint to the table
alter table tablename add constraint ids_unique unique (server_id, user_id);
and then handle possible exceptions.

Cause of PostgreSQL foreign key violation?

My PostgreSQL (9.2) database contains two tables registrations and attributes with a foreign key constraint:
postgres=# \d+ registrations;
Table "public.registrations"
Column | Type | Modifiers | Storage | Stats target | Description
---------+-------+-----------+----------+--------------+-------------
name | text | not null | extended | |
parent | text | | extended | |
storage | bytea | | extended | |
Indexes:
"registrations_pkey" PRIMARY KEY, btree (name)
Referenced by:
TABLE "attributes" CONSTRAINT "attributes_cname_fkey" FOREIGN KEY (cname) REFERENCES registrations(name) ON DELETE CASCADE
Has OIDs: no
postgres=# \d+ attributes;
Table "public.attributes"
Column | Type | Modifiers | Storage | Stats target | Description
--------+-------+-----------+----------+--------------+-------------
cname | text | not null | extended | |
aname | text | not null | extended | |
tags | text | | extended | |
value | bytea | | extended | |
Indexes:
"attributes_pkey" PRIMARY KEY, btree (cname, aname)
Foreign-key constraints:
"attributes_cname_fkey" FOREIGN KEY (cname) REFERENCES registrations(name) ON DELETE CASCADE
Has OIDs: no
At some point I realised that some rows violated the foreign key constraint:
postgres=# SELECT COUNT(*) FROM attributes LEFT JOIN registrations ON attributes.cname=registrations.name WHERE registrations.name IS NULL;
count
-------
71
(1 row)
Could you help me understand how this corruption could happen?
A constraint marked as NOT VALID is the one case you might expect to see violations, but the NOT VALID clause would show up in the psql \d+ output. (I believe it's possible to manually update this flag in the catalog, but I hope for your sake that this isn't the issue...)
As far as I know, the only supported way of bypassing a foreign key check is to SET session_replication_role TO replica before modifying the data. This is there for the benefit of replication processes, operating under the assumption that the constraint has already been validated on the master - though this can certainly go wrong if your replicator is buggy or misconfigured.
It's also possible for a superuser to manually disable the constraint's underlying triggers (and it's often tempting for someone trying to speed up a bulk import). The following will tell you if the triggers are currently active (tgenabled should be 'O'):
SELECT *
FROM pg_trigger
WHERE tgname ~ '^RI_ConstraintTrigger'
AND tgrelid IN ('registrations'::regclass, 'attributes'::regclass)
I don't think there's any way of knowing whether this was temporarily changed in the past, though if you have statement logging enabled, you might find an ALTER TABLE ... DISABLE TRIGGER statement in there somewhere.
There is also at least one loophole in the foreign key enforcement, and of course, it's always possible that you've found a bug...
This can happen if the FK contraint was created with a NOT VALID clause (don't do this):
CREATE TABLE one
( one_id INTEGER NOT NULL PRIMARY KEY
);
CREATE TABLE two
( two_id INTEGER NOT NULL PRIMARY KEY
, one_id INTEGER NOT NULL
);
INSERT INTO one(one_id)
SELECT gs FROM generate_series(0,12,2) gs;
INSERT INTO two(two_id,one_id)
SELECT gs, gs FROM generate_series(0,12,3) gs;
ALTER TABLE two
ADD CONSTRAINT omg FOREIGN KEY (one_id) references one(one_id)
-- DEFERRABLE INITIALLY DEFERRED
NOT VALID
;

Split table with duplicates into 2 normalized tables?

I have a table with some duplicate rows that I want to normalize into 2 tables.
user | url | keyword
-----|-----|--------
fred | foo | kw1
fred | bar | kw1
sam | blah| kw2
I'd like to start by normalizing this into two tables (user, and url_keyword). Is there a query I can run to normalize this, or do I need to loop through the table with a script to build the tables?
You can do it with a few queries, but I'm not familiar with postgreSQL. Create a table users first, with an identity column. Also add a column userID to the existing table:
Then something along these lines:
INSERT INTO users (userName)
SELECT DISTINCT user FROM url_keyword
UPDATE url_keyword
SET userID=(SELECT ID FROM users WHERE userName=user)
Then you can drop the old user column, create the foreign key constraint, etc.