Altering candidate key in SQL Server 2005 - sql-server-2005

I have a rather interesting task ahead of me and I want to make sure I am thinking it out correct -
I have a table Part that has its part_id being used as part of the candidate keys of several other tables (A, B, C). I need to drop Part and use Product instead. A, B, C need to have their part_id column (which is of type bigint) replaced with a new column of product_id (which is of datatype int). I need to use the part_id column of the tables to determine what product_id I need to use for each row.
Here is what I am thinking is what I need to do (thoughts?):
create the product_id column in each of the tables (A, B, C)
set the product_id of each row for each table to the appropriate value
drop any constraints/fk/pk I have for the part_id column in A, B, C
drop the part_id from those tables completely
recreate the constraints/fk/pk I dropped earlier, only have product_id be part of them instead
drop the Part table completely
Can anyone see any potential issues that I may be neglecting?
Thanks!
Additional Info: Tables A, B, and C each have LOTS of data, so if there is more performant way, I am all ears.

You should be able to create new constraints on product_id before you drop constraints on part_id, and before you drop the column part_id. And you should do it in that way--create the new constraints first.
If things go wrong with the product_id changes, your database is still usable if the part_id constraints are still in place.

Related

How to implement cascading deletes in one -> many *from the many side*

I have a use case where multiple rows in table A are aggregated down to a single row in table B. We represent the origin of rows in table B with a foreign key column in table A, saying "as a row, I contributed to X row in table B".
We want to find the best solution so that once every row from table A which contributed to table B has been deleted, deleted the row in table B as an orphan.
I'm not sure if there's some way to use ON DELETE CASCADE to handle this. But I'm guessing not and that maybe triggers are the best option.
I can't just purge all orphans on a schedule because the changes need to be persisted very soon after occurring.
Using the given schema, what our best option? Alternatively, is there some other schema that better sets us up for the scenario I gave?

Make calculated column from other table

I want to make a calculated columns from different tabel, i want to calculate TotalPrice from table A, which is from Quantity on Table B, and UnitPrice on Table C.
sorry for my bad english
Like #marc_s explain you, you can create computed only with column of the same table. If you want a "table" with a calcul between multiple table you can create simply a view.
Create view on SQL SERVER

Rearrange order of fields in a sql table [duplicate]

I have a table with 50+ columns and I need to swap the order of the first two columns. What is the best way to accomplish this using Oracle? Assume the table name is ORDERDETAILS and as it is, the first two columns are ITEM_ID and ORDER_ID. Once the rename is complete, the table name should still be ORDERDETAILS but the first two columns will be ORDER_ID and ITEM_ID. FWIW, column types and the rest of the columns and their order is irelevent.
Correct me if I'm wrong, but I think the general steps are:
Rename the existing table.
Drop the primary key constraint.
Re-create the table with the correct column order.
List item
Run INSERT INTO .. SELECT to move the data from temp to the table in step #3.
Drop the temp table.
I have little experience with Oracle so perhaps I'm missing a step or two.
Does a primary key imply an index in Oracle? Does dropping the primary key also drop the index?
SQL examples are much appreciated.
EDIT: Un-sincere thanks to those who question why it needs done instead of providing help. To answer your question as to why it needs done: I'm following orders from someone else who says I need to do it this way and the order of the columns DOES matter. My thoughts/opinions on this are irrelevent.
Since the release of Oracle 12c it is now easier to rearrange columns logically.
Oracle 12c added support for making columns invisible and that feature can be used to rearrange columns logically.
Quote from the documentation on invisible columns:
When you make an invisible column visible, the column is included in the table's column order as the last column.
Example
Create a table:
CREATE TABLE t (
a INT,
b INT,
d INT,
e INT
);
Add a column:
ALTER TABLE t ADD (c INT);
Move the column to the middle:
ALTER TABLE t MODIFY (d INVISIBLE, e INVISIBLE);
ALTER TABLE t MODIFY (d VISIBLE, e VISIBLE);
DESCRIBE t;
Name
----
A
B
C
D
E
Credits
I learned about this from an article by Tom Kyte on new features in Oracle 12c.
Look at the package DBMS_Redefinition. It will rebuild the table with the new ordering. It can be done with the table online.
As Phil Brown noted, think carefully before doing this. However there is overhead in scanning the row for columns and moving data on update. Column ordering rules I use (in no particular order):
Group related columns together.
Not NULL columns before null-able columns.
Frequently searched un-indexed columns first.
Rarely filled null-able columns last.
Static columns first.
Updateable varchar columns later.
Indexed columns after other searchable columns.
These rules conflict and have not all been tested for performance on the latest release. Most have been tested in practice, but I didn't document the results. Placement options target one of three conflicting goals: easy to understand column placement; fast data retrieval; and minimal data movement on updates.
I followed the solution above from Jonas and it worked well until I needed to add a second column. What I found is that when making the columns visible again Oracle does not necessarily set them visible in the order listed in the statement.
To demonstrate this follow Jonas' example above. As he showed, once the steps are complete the table is in the order that you'd expect. Things then break down when you add another column as shown below:
Example (continued from Jonas'):
Add another column which is to be inserted before column C.
ALTER TABLE t ADD (b2 INT);
Use the technique demonstrated above to move the newly added B2 column before column C.
ALTER TABLE t MODIFY (c INVISIBLE, d INVISIBLE, e INVISIBLE);
ALTER TABLE t MODIFY (c VISIBLE, d VISIBLE, e VISIBLE);
DESCRIBE t;
Name
----
A
B
B2
D
E
C
As shown above column C has moved to the end. It seems that the ALTER TABLE statement above processed the columns in the order D, E, C rather than in the order specified in the statement (perhaps in physical table order). To ensure that the column is placed where desired it is necessary to make the columns visible one by one in the desired order.
ALTER TABLE t MODIFY (c INVISIBLE, d INVISIBLE, e INVISIBLE);
ALTER TABLE t MODIFY c VISIBLE;
ALTER TABLE t MODIFY d VISIBLE;
ALTER TABLE t MODIFY e VISIBLE;
DESCRIBE t;
Name
----
A
B
B2
C
D
E
It's sad that Oracle doesn't allow this, I get asked to do this by developers all the time..
Here's a slightly dangerous, somewhat quick and dirty method:
Ensure you have enough space to copy the Table
Note any Constraints, Grants, Indexes, Synonyms, Triggers, um.. maybe some other stuff - that belongs to a Table - that I haven't thought about?
CREATE TABLE table_right_columns AS SELECT column1 column3, column2 FROM table_wrong_columns; -- Notice how we correct the position of the columns :)
DROP TABLE table_wrong_columns;
'ALTER TABLE table_right_columns RENAME TO table_wrong_columns;`
Now the yucky part: recreate all those items you noted in step 2 above
Check what code is now invalid, and recompile to check for errors
And next time you create a table, please consider the future requirements! ;)
Use the View for your efforts in altering the position of the column:
CREATE VIEW CORRECTED_POSITION
AS
SELECT co1_1, col_3, col_2
FROM UNORDERDED_POSITION
should help.
This requests are made so some reports get produced where it is using SELECT * FROM [table_name]. Or, some business has a hierarchy approach of placing the information in order for better readability from the back end.
Thanks
Dilip

separate columns for separate id fields?

Say we have tables A, B, and C and then we want table Z to contain column TYPE which tells us which table of A, B, and C the record in Z is associated with.
Is it better to have a separate column for each table like columns A_ID, B_ID, and C_ID in order to use indexing?
Or is there some reason why using a generic column TYPE_ID might be better performance-wise?
Using a type_id and then a fk_id won't be good because selectivity on the index is 33%, which is too high to be of any use. You would always be indexing on the fk_id instead (that which links to A,B,C) - which may require tie breaking between 3 values (if the id is used by all 3 types).
Storage wise, an index never stores nulls, so the absolute number of items stored in the indexes, whether a single (fk_id) or multiple (a_id,b_id,c_id) will be similar.
If you are coming in from the exact fk_id (from either A,B,C), then using a unique index on (fk_id,type_id) in that order can quickly identify the record required.
It would seem for simplicity and brevity, two columns are better than 3 here.
This is sometimes a schema code smell.
If you are considering putting this as a single column in Z, does that mean that only one of A, B, C can be applicable to Z?
Before I decide, I'd really say I have to know more about the entity and the usage pattern. Is access coming from known A, B, or C, or is the supplemental info driven from the Z side? If it is driven from the Z side, do you want to get all the A, B and C columns and then use them selectively from the application, or just Zs with As or Zs with Bs - i.e. do you usually know the subtype? Also, do A, B, and C have enough columns to merit the separation out of Zs row if they are each 1-1 (i.e. you could have the columns in Z and just be NULL)
Just for completeness, another possibility which gives you more referential integrity (because with a single column, you can't be an FK to one of three tables) is to have tables Z_A, Z_B, Z_C:
With schemas:
Z_A:
Z_ID REFERENCES (Z.ID)
A_ID REFERENCES (A.ID)
Z_B:
Z_ID REFERENCES (Z.ID)
B_ID REFERENCES (B.ID)
Z_C:
Z_ID REFERENCES (Z.ID)
C_ID REFERENCES (C.ID)
With all IDs unique in each table, this constrains everything pretty nicely, except there is nothing declarative to stop Z lying in multiple tables without a trigger (you cannot make a unique constraint on an indexed view over a UNION ALL in SQL Server).
While it seems to multiply the number of tables, these can usually be wrapped up into views.

Reversing a 1:many relationship between two tables

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.