Sql Server On Update Cascade With Multiple Constraints On Multiple Tables - sql-server-2005

I've seen questions similar to mine, but none exactly the same.
Suppose, I have the following (simplified) tables:
Table A
aID int PRIMARY KEY
10
11
Table B
bID int PRIMARY KEY, aID int FOREIGN KEY referencing A.aID
100, 10
101, 11
Table C
cID int PRIMARY KEY, bID int FOREIGN KEY referencing B.bID
1001, 101
Table D
aID int, bID int, cID int
11, 101, 1001
I want Table D to be constrained so that:
aID, bID, cID are all valid ID values
aID and bID are a valid pair from Table B
bID and cID are a valid pair from Table C
Number 1. is easy to take care of with Foreign key constraints.
But suppose I update table C to instead be
1001, 100
How can I make sure table D is automatically updated to be
10, 100, 1001
Notice that 2 fields have to change here in order to satisfy 2. and 3. above. Is there a way to do this with Foreign keys, or is an AFTER UPDATE trigger the only way?

According to my point in this type of case don't create other table D with select all the data based on inner join of table (A-B)-C in your case y create table D by sql select statement but define one extra trigger for update on B,C so they can truncate the table D so D is reconstruct again

I ended up changing Table D to be a VIEW that is a JOIN of Tables B and C.
CREATE VIEW D AS
SELECT BB.aID, BB.bID, CC.cID FROM B BB
JOIN C CC
ON CC.bID = BB.bID
Once I realized doing this gave me what I wanted, it became much, much simpler to manage.

Related

postgres sql returns no row

I have 3 followings tables:
CREATE TABLE public.a
(
id bigint NOT NULL DEFAULT nextval('a_id_seq'::regclass),
CONSTRAINT a_pkey PRIMARY KEY (id)
)
CREATE TABLE public.b
(
id bigint NOT NULL DEFAULT nextval('b_id_seq'::regclass),
fkid bigint,
CONSTRAINT b_pkey PRIMARY KEY (id),
CONSTRAINT b_fkid_fkey FOREIGN KEY (fkid)
REFERENCES public.a (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
CREATE TABLE public.history
(
id bigint NOT NULL DEFAULT nextval('history_id_seq'::regclass),
CONSTRAINT history_pkey PRIMARY KEY (id)
)
As you can see, the table A has 1 to many relationship with table B. The history table keeps track of logical time inside the app. The following query:
WITH main_q AS (
SELECT
a.id
FROM a
LEFT JOIN b ON a.id = b.fkid
)
SELECT main_q.id,
max(history.id) as as_of
FROM main_q,history
GROUP BY
main_q.id
Returns no rows, even if tables A contains rows, because History table is empty. However, as soon as I add at least 1 row in history table, the query works.
Could someone please explain how I should modify my query so that it returns rows even if history is empty (as long as table A contains rows) ? I would expect to receive a NULL value in as_of column or 0. I tried COALESCE(max(history.id,0)) but this doesn't work either, well, because no rows in history
EDIT Example:
Table A content:
id
1
2
Table B content:
id, fkid
1, 2
2, 2
Table History content:
<empty>
The issue is the query below
SELECT main_q.id,
max(history.id) as as_of
FROM main_q,history
GROUP BY
main_q.id
Why not try a left join, you may have nothing to join, you can try something below
SELECT main_q.id,
max(history.id) as as_of
FROM main_q left join history on 1=1
GROUP BY
main_q.id
If I am not wrong, you are performing a cartesian product between main_q and history, because you haven't a predicate to join these 2 tables.
Likely, when you are performing this cartesian product, if the second table (history) is empty, the cartesian product returns nothing. As soon as you have 1 record in history, you will get data from Main_q. However, if you have more than 1 record in history, you will start to get duplicate data because of the cartesian product.

How to create SQL constraint on primary key to make sure it could only be referenced once?

How do I add constraint to guard that a primary key could only be referenced once?(It could be referenced in two tables)
Each reference should have a unique value out of the primary key.
Table A
----------------------
id
1
2
3
4
Table B
----------------------
id a_id (foreign key to table A.id)
1 2
2 3
Table C
----------------------
id a_id (foreign key to table A.id)
1 1
I want something to happen to give error when try to insert a_id = 2 into table C as its used in table B already.
You can use an INSERT, UPDATE trigger on each of the child tables to ensure that the PK of the parent table that is about to be inserted or updated does not already exist in the other child table.
What you are trying to do requires another table D, that will help unify the references to A.
Table D will contain its own primary key ( Id ), a reference to table A with a UNIQUE constraint on it (call it AId ), and a third column (called "RowType") to indicate to which of the child tables (B or C) the row corresponds. You can make this column to be of type int, and assign value "0" for B and "1" for C, for example.
Then in table B you add a foreign key to D.Id, AND another column "BRowType" as foreign key to D.RowType; then you define a constraint on this column, so it can only have the value '0' ( or whatever value you have decided to correspond to this table).
For table C your constraint will limit the values to '1'.
Or course, in order to insert a record into B or C you first need to create a record in D. But once you have a record in B that references a record in D, which in turn links to a record in A, you will no longer be able to create a record in C for the same line in A - because of the UNIQUE constraint on D.AId AND the constraint on C.BRowType.
If I understand the question correctly, it sounds like you need to add a unique constraint on the column of each table that references your primary key.
For example:
Table A
----------------------
id (primary key)
1
2
3
Table B
----------------------
id a_id (foreign key to table A.id)
1 2
2 3
Set the a_id column to be UNIQUE and that way you can ensure that the primary key from Table A is not used twice. You would do that in each table which references A.id
If you want to avoid using triggers, you could create a table X with id and a unique constraint on it.
In each transaction in which you insert a record into B or C you have to insert into X as well. Both insertions will only be possible if not yet in the other table.

Query for column key when foreign key is absent in another table postgresql

We have a PostgreSQL database which has a table with a foreign key reference to the primary key of another table like below
Table A
a_key
b_key
when_
Table B
b_key
There was a bug in our code where we removed rows from Table B but did not remove the entries in Table A that were associated with those rows. I am trying to right a query to find all of the primary keys from Table A which have a "b_key" value that does not exist in Table B, I also added a time restriction to the query. My query is below but it is not returning any results. Can anyone see an issue with the query? Is it not done correctly?
select a_key
from A left join B b on a.b_key = b.b_key
where b.b_key is null and A.when_ < '2017-03-13 00:00:00.0'::timestamp
try this first
SELECT
a_key
FROM A
where not exists (
select b_key from B where B.b_key = A.b_key)

Refactor many-to-many relationship to many-to-one in Oracle

Given the following table arrangement:
A - B - C
where B is a join table between A and C. It turns out the domain relationship between A and C is truly one to many (many on the A side), and I would like to refactor our schema to reflect this fact.
Is it possible to write a SQL UPDATE statement to insert all the correct id's of C into the proper rows of A (each row of A will have exactly one C id)? Or is a procedure necessary?
Note: I will accept an Oracle-only answer, as that is the only place this migration will be necessary.
update tableA
set foreignKeyColumn = (
select columnC
from tableB
where columnA = tableA.columnA
);
Actually seeing the full table structure would make it easier, but this should work.
-- assuming you have tableA (id_a), tableB (id_a,id_c), tableC (id_c)
alter table tableA add id_c int;
alter table tableA add constraint foreign key (id_c) references tableC(id_c);
merge into tableA a
using tableB b
on (a.id_a = b.id_a)
when matched then update set
a.id_c = b.id_c;
commit;
Sure
Alter Table C Add FK2A int Null
Update C Set c.FK2A =
(Select FK2A From B
Where FK2C = C.PK)
Alter Table C Alter Column FK2A int Not Null
Alter Table C Add Constraint FKTableCToA
Foreign Key (FK2A)
References A (PK)

SQL query to combine existence check and condition check

I have 2 tables, call A and B. A has a foreign key on B. call them A_ID and B_ID respectively. But the constraint not enforced in the design. I am not supposed to change the schema. I need to delete entries from table A based on 2 conditions.
1)If table B doesn't contain A_ID
2)If some condition on B is met.
I have formed a query something like this. But I dont think its optimal. Is there a better way of doing this?
delete from A where A_ID not in (select B_ID from B where status='x' )
or A_ID not in (select B_ID from B)
You could use not exists to delete rows without a matching entry in table B. This one treats status = 'x' as if no match was found, i.e. it will delete those rows:
delete A
where not exists
(
select *
from B
where B.B_ID = A.A_ID
and status <> 'x'
)
JustABitOfCode and UltraCommit told about omitting one part
furthermore, if it's a foreign key, you can say to keep deleting unwanted A in definition:
CREATE TABLE A
(
uniqeidentifire A_ID
, FOREIGN KEY (A_ID) REFERENCES B(B_ID) ON DELETE CASCADE
);
This will Automatically delete each A that does not have a B match
and this is more efficient
As just explained from JustABitOfCode, please remove the condition:
(select B_ID from B where status='x')
because it is redundant: the result set of the previous select, is a SUBSET of the result set of the following select:
(select B_ID from B)