I have two MySQL tables A and B. Table A has a member ref which is a ForeignKey reference to B.id. This makes for a 1:many association between B and A.
This has been in production for a few weeks, but I'm now adding more features to my code and have realized I got my original mapping wrong. I needed a many:1 relationship between B and A. That is, B.ref should point to A.id, not the other way around. It wasn't a problem until now because it was all 1:1 mapping so far. How do I migrate my data to the new schema?
I'd guess:
ALTER TABLE B ADD COLUMN ref INTEGER CONSTRAINT FOREIGN KEY (A.id) -- add the column first
Run the SQL equivalent of "for row in A: row.ref.ref = row"
ALTER TABLE A DROP COLUMN ref
Attempting to do this in SQLAlchemy fails with a circular reference error. I need to do it in SQL, but am not familiar with the necessary SELECT+UPDATE syntax. Help?
For step 2:
update b, a
set b.ref = a.id
where a.ref = b.id
Just add the foreign key constraint as fourth step, you won't need it when creating the column.
Related
There are two tables A and B. As they have a many-to-many relation, there's also table C.
A
------
id PK
B
------
id PK
C
------
id_A PK
id_B PK
Now, a row B only exists only exists when at least one row of A has a relation to it, and one B may contain a relation to two or more different rows of A.
My question is, how do i automatically delete a row from B if there isn't any foreign to it in C? My initial though was to set a trigger, but i'm not to sure about this and i'd want a second opinion in how to proceed. Thank you.
First, one assumes that the data is initially set up correctly. That is, the only b records are the ones that meet your condition.
Then, the solution involves triggers on table c. When a row is deleted, it would check:
Does id_b have any other rows in the table?
If not, then delete the row.
This can actually be a bit tricky. In general, you don't want to query the table being triggered. So, I might suggest an alternative approach:
Add a counter on b.
Add insert/update/delete triggers on c that increments or decrements the count in b.
If the counter is 0 (or 1 before decrementing), then delete the row.
Gosh, you might find that the counter itself is sufficient, and there is no need to actually delete the row. You can get that effect if you use a view:
create view v_b as
select b.*
from b
where ab_counter > 0;
You could also create a view on b and not have to deal with triggers at all:
create view v_b as
select b.*
from b
where exists (select 1 from c where c.b_id = b.id);
#Gordon's solution above is great, However a slight modification might help.
First, one assumes that the data is initially set up correctly. That is, the only b records are the ones that meet your condition.
Then, the solution involves triggers on table c. When a row is deleted, it would check:
Does id_b have any other rows in the table?
If not, then delete the
row.
This is a bit tricky because you have to check if other rows exist. This check can be automated by using,
FOREIGN KEY(id) REFERENCES B(id) ON DELETE RESTRICT
on table C. Now you only need to delete row from B in the trigger without any checks, since the restrict constraint will automatically check if row exists in table C and restrict the delete of a referenced row in table B else delete is successful.
Suppose, I have a SQL database with table like A,B,C and Z. all three table A,B and C has a one-many relationship with table Z. I think of solution mentioned below but need suggestion or better solution for this problem if any.
Solution-
Create one more table named 'LinkZ' which have one-many relationship with table 'Z'
Add foreign key field to table A,B and C of table 'LinkZ'
So that way in future if more tables add to database which need relationship with table 'Z' we just need to add foreign key to newly added table of 'LinkZ' as it has already one-many relationship.
Please suggest solution if exist which satisfy my needs.
Edit -
#Gordon, "If all the tables have a "1-many" relationship with Z, then you don't need a link table at all. You need a link table when your relationships are many-to-many". I need this kind relationship which you have quoted from your answer. but if follow traditional way then i need to add AID, BID, CID in Z to achieve 1-Many with Z then 'Z' table contains many columns which represent foreign key with other table (In future might be other table also included to have same relationship, so in that case i want to avoid many columns from Z of only foreign keys only) that's why I have created dummy table 'LinkZ' which provide illusion to other table A,B and C that this all tables have 1-Many relationship with Z directly.
This is too long for a comment.
If all the tables have a "1-many" relationship with Z, then you don't need a link table at all. You need a link table when your relationships are many-to-many.
It is unclear which way the linkage is going, but you either want ZID in each of A, B, and C, or you want AID, BID, CID in Z.
I have problem with SQL .
I am trying to create tables from other tables with foreign keys. The table is created normally without problem but when I'm trying to see the data inside the table there is none of the data inside! Anyone who knows?
-- Here is my table with the foreign keys
CREATE TABLE StaffXCustomersXMeals(
--MealID int FOREIGN KEY REFERENCES Meals(MealID),
--CustomersID int FOREIGN KEY REFERENCES Customers(CustomersID),
--StaffID int FOREIGN KEY REFERENCES Staff(StaffID)
)
You might want to consider reading up on the concept of a SQL View - think of it as a "virtual table based on the result-set of an SQL statement." When you create a view based on the JOIN between multiple tables, it saves your query and you can then select from it like you would a table.
For example, you might have the following:
CREATE VIEW StaffCustomerMeals
AS
SELECT
m.MealID,
c.CustomersID,
s.StaffID
FROM
Meals m
LEFT JOIN
Customers c ON
m.SomeIDThatMeansThisCustomer = c.CustomersID
LEFT JOIN
Staff s ON
m.SomeIDThatMeansAStaffMember = s.StaffID
You need to define these relationships in accordance with your own schema - it's your homework assignment, so do your best to figure it out. A couple more questions to consider:
Does a meal always have both a customer and a staff member, or are they customers who might happen to be staff members?
Should you include other information besides the IDs (e.g., CustomerName, StaffMemberDepartment, MealPrice, PurchaseDate)
You didn't enter any data. You only said that whatever data entered must reference the other tables. So you cannot enter invalid meals for instance.
You need INSERT statments to fill the table with whatever data you need.
I need to update one field for a few rows in one table (say, Table_A). However, I'm getting an error message saying conflict with the Foreign Key Constraint in Table_B.
So, I tried to update Table_B as well, turns out Table_B has Foreign Key Constraint with Table_C and Table_D; again, I tried to update Table_C and D, turns out they are conflicting with table_E, F, G, H, I, J, K etc. etc. and on and on.
I was told that such "chain" can go up to 20+ tables.
Additionally, I do not have access to the database schema, thus it is extremely difficult for me to determine which field in which table is the foreign key for the other table.
Currently, all I can do is manually checking each table, all the way from A-Z by using select * statement from the table that is showing in the error message. I'm wondering if there is any alternative to update these specific fields all across tables A till (whichever the last table) directly?
I'm using SQL Server 2005.
This will give you the names of the tables and columns in your foreign keys
SELECT
OBJECT_NAME(fk.[constraint_object_id]) AS [foreign_key_name]
,OBJECT_SCHEMA_NAME(fk.[parent_object_id]) AS [parent_schema_name]
,OBJECT_NAME(fk.[parent_object_id]) AS [parent_table_name]
,pc.[name] AS [parent_column_name]
,OBJECT_SCHEMA_NAME(fk.[parent_object_id]) AS [referenced_schema_name]
,OBJECT_NAME(fk.[referenced_object_id]) AS [referenced_table_name]
,rc.[name] AS [referenced_column_name]
FROM [sys].[foreign_key_columns] fk
INNER JOIN [sys].[columns] pc ON
pc.[object_id] = fk.[parent_object_id] AND
pc.[column_id] = fk.[parent_column_id]
INNER JOIN [sys].[columns] rc ON
rc.[object_id] = fk.[referenced_object_id] AND
rc.[column_id] = fk.[referenced_column_id]
How to best display and analyze the connection graph is a more subjective matter and will depend on the complexity of your schema.
I have 2 tables one is an extension of the other so it is currently a simple one-to-one relationship (this is likely to become one-to-many in the future). I need to join from one table to another to pull a value out of another column in the extension.
so table A contains basic details including an id and table B uses a FK reference to the Id column in table A. I need to pull out column X from table B.
To add complexity sometimes there won't be a matching entry in table B but in that case it needs to return null. Also the value of X could be null.
I know I can use a left outer join but is there a more efficient way to perform the join?
Left outer join is the way. In order to make it most efficient, make sure you index the FK column in table B. It will be super-fast with the index.
You don't need to index the primary key in table A for this query (and most databases already index primary keys anyway).
The MySQL syntax for creating the index:
CREATE INDEX `fast_lookups` ON `table_b` (`col_name`);
You can name it whatever, I picked "fast_lookups."