Rearrange order of fields in a sql table [duplicate] - sql

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

Related

Swapping columns in a table to match formatting of another table prior to row insertion

I want to swap columns within Visual Fox Pro 9 in table_1 before inserting its rows into table_2 so as to avoid data losses caused by datatype variations. I tried these two options based on other solutions on stackoverflow, but I get syntax error messages for both command inputs. The name field is of datatype = character(5)and it needs to be after the subdir field.
ALTER table "f:\csp" modify COLUMN name character(5) after subdir
ALTER table "f:\csp" change COLUMN name name character(5) after subdir
I attempted these commands based on solutions here:
How to move columns in a MySQL table?
You never need to change the column order, and you never should rely on column order to do something.
For inserting into another table from this one you could simply select the columns in the order you desired (and their column names do not even need to be the same in the case of "insert ... select ... "). ie:
insert into table_2 (subdir, name) ;
select subdir, name from table_1
Another way is to use the xBase commands like:
select table_2
append from table_1
In the case of latter, VFP would do the match on column names.
All in all, relying on column ordering is dangerous. If you really want to do that, then you can still do, in a number of ways. One of them is to select all data into a temp table, recreate the table in the order you want and fill back from temp (might not be as easy as it sounds if there are existing dependencies such as referential integrity - also you need to recreate the indexes).

Column Copy and Update vs. Column Create and Insert

I have a table with 32 Million rows and 31 columns in PostgreSQL 9.2.10. I am altering the table by adding columns with updated values.
For example, if the initial table is:
id initial_color
-- -------------
1 blue
2 red
3 yellow
I am modifying the table so that the result is:
id initial_color modified_color
-- ------------- --------------
1 blue blue_green
2 red red_orange
3 yellow yellow_brown
I have code that will read the initial_color column and update the value.
Given that my table has 32 million rows and that I have to apply this procedure on five of the 31 columns, what is the most efficient way to do this? My present choices are:
Copy the column and update the rows in the new column
Create an empty column and insert new values
I could do either option with one column at a time or with all five at once. The columns types are either character varying or character.
The columns types are either character varying or character.
Don't use character, that's a misunderstanding. varchar is ok, but I would suggest just text for arbitrary character data.
Any downsides of using data type "text" for storing strings?
Given that my table has 32 million rows and that I have to apply this
procedure on five of the 31 columns, what is the most efficient way to do this?
If you don't have objects (views, foreign keys, functions) depending on the existing table, the most efficient way is create a new table. Something like this ( details depend on the details of your installation):
BEGIN;
LOCK TABLE tbl_org IN SHARE MODE; -- to prevent concurrent writes
CREATE TABLE tbl_new (LIKE tbl_org INCLUDING STORAGE INCLUDING COMMENTS);
ALTER tbl_new ADD COLUMN modified_color text
, ADD COLUMN modified_something text;
-- , etc
INSERT INTO tbl_new (<all columns in order here>)
SELECT <all columns in order here>
, myfunction(initial_color) AS modified_color -- etc
FROM tbl_org;
-- ORDER BY tbl_id; -- optionally order rows while being at it.
-- Add constraints and indexes like in the original table here
DROP tbl_org;
ALTER tbl_new RENAME TO tbl_org;
COMMIT;
If you have depending objects, you need to do more.
Either was, be sure to add all five at once. If you update each in a separate query you write another row version each time due to the MVCC model of Postgres.
Related cases with more details, links and explanation:
Updating database rows without locking the table in PostgreSQL 9.2
Best way to populate a new column in a large table?
Optimizing bulk update performance in PostgreSQL
While creating a new table you might also order columns in an optimized fashion:
Calculating and saving space in PostgreSQL
Maybe I'm misreading the question, but as far as I know, you have 2 possibilities for creating a table with the extra columns:
CREATE TABLE
This would create a new table and filling could be done using
CREATE TABLE .. AS SELECT.. for filling with creation or
using a separate INSERT...SELECT... later on
Both variants are not what you seem to want to do, as you stated solution without listing all the fields.
Also this would require all data (plus the new fields) to be copied.
ALTER TABLE...ADD ...
This creates the new columns. As I'm not aware of any possibility to reference existing column values, you will need an additional UPDATE ..SET... for filling in values.
So, I' not seeing any way to realize a procedure that follows your choice 1.
Nevertheless, copying the (column) data just to overwrite them in a second step would be suboptimal in any case. Altering a table adding new columns is doing minimal I/O. From this, even if there would be a possibility to execute your choice 1, following choice 2 promises better performance by factors.
Thus, do 2 statements one ALTER TABLE adding all your new columns in on go and then an UPDATE providing the new values for these columns will achieve what you want.
create new column (modified colour), it will have a value of NULL or blank on all records,
run an update statement, assuming your table name is 'Table'.
update table
set modified_color = 'blue_green'
where initial_color = 'blue'
if I am correct this can also work like this
update table set modified_color = 'blue_green' where initial_color = 'blue';
update table set modified_color = 'red_orange' where initial_color = 'red';
update table set modified_color = 'yellow_brown' where initial_color = 'yellow';
once you have done this you can do another update (assuming you have another column that I will call modified_color1)
update table set 'modified_color1'= 'modified_color'

Correct spelling mistakes in a column based on another table in postgresql

My postgresql table has a (cityname) column. the values in the (cityname) column has some spelling mistakes. Each and every record of column (cityname) needs to be corrected. Another table has a column that contains all correct city names. Based on this table the spelling mistakes of the first table are needed to be corrected.
You need a column which can relate rows in table A (with the mistakes) to table B with the correct data. Lets assume you have the city_id column which does this job.
update table_A
set add1 = table_b.correct_add1
from table_A as j_table_A
join table_B on table_B.city_id = table_A.city_id
where j_table_A.primary_key_column = table_A.primary_key_column
you basically reference table_A twice. there is no good reason to do this, but I have found that if you need to pull data from joins, then during an update this is the easiest way.
Edited after comment:
Since you have no good way of associating the correct data to the data that needs fixing (like a city_id), then you need to work on your join condition and perhaps introduce a regex. there is a link here which may be of some use

Moving columns in Teradata

I´ve created one new column in Teradata, and then I have moved the data from another colum into this new colmn. After that, I've deleted the old column.
What I would like to do now is to move the new column n the same place in the table where the old column was.
I would like to ask you - is that possible or not?
Unless the business requirement enforces the ordinal positioning of a column in a table definition (e.g. timestamp is the last column in the table definition), it doesn't really matter. If you have a V1 layer that maps views column for column (1:1) with proper ROW ACCESS locking, your view definition can always expose the preferred ordinal positioning of your columns to your end users and BI applications.
If you must re-order your columns perform the following:
Submit a CREATE TABLE MyDB.MyTable_ with your preferred ordinal position, column defaults, and any value list compression.
COLLECT STATISTICS ON MyDB.MyTable_ FROM MyDB.MyTable; -- Migrate collected statistics
INSERT INTO MyDB.MyTable_ SELECT /* Columns */ FROM MyDB.MyTable;
RENAME MyDB.MyTable AS MyDB.MyTable1; RENAME TABLE MyDB.MyTable_ AS MyDB.MyTable;
After validating everything is in order, DROP TABLE MyDB.MyTable1;
You could also do the following instead of Step 1 and 3:
CREATE TABLE MyDB.MyTable_
(/* Column Definitions in new Order */ ) AS
(SELECT /* New Column Ordering */
FROM MyDB.MyTable)
WITH DATA AND STATISTICS
{UNIQUE} PRIMARY INDEX (/* Primary Index Columns */);
Stats may or may not come over populated using this approach. You will want to verify this after the new table is created.
Since this is related to your previous question, I'll try to answer in the same context.
No, you cannot change the order of columns after the fact. When you "add" a new column to an existing table, it will be defined at the end of the table description. If you really need the columns to appear in a specific order in the physical table, you must recreate the table completely.
However, you can create a VIEW that displays the columns in whatever order you want. In fact, if you are going to use this table for some sort of application, you should create a VIEW in any case (so you can establish the proper access lock). For example, suppose you have a table named MYTABLE with three columns COL_A, COL_B, and COL_C and you want them "displayed" in reverse order:
replace view MYDB.MYTABLE_V as
locking MYDB.MYTABLE for access
select COL_C, COL_B, COL_A
from MYDB.MYTABLE
Using "replace view" will create the view if it does not already exist or replace it if it does. Of course, this means that if you ever alter the table, you must recreate the view again. I keep view definitons in a comment block in my table creation programs just to be safe.

Change the order of database columns

I want to change the order of column e.g. name is first column of my table and there are 10 other columns in table I want to insert a new column in 2nd position after name column.
How is this possible?
1 - It's not possible without rebuilding the table, as Martin rightly points out.
2 - It's a good practice anyways to specify what fields you want and in what order in your SELECT statements as n8wrl points out.
3 - If you really really need a fixed order on your fields, could create a view that selects the fields you want in the order you want.
Like the rows in the table, there is no meaning to the order of the columns. In fact, it is best to specify the order you want the columns in your select statements rather than using select *, so you can 'insert' new columns wherever you want just by writing your SELECT statements accordingly.
Its possible to change the order. In some instances it really matters. have a personal experience.
Anyway..this query works fine.
ALTER TABLE user MODIFY Name VARCHAR(150) AFTER address;
You can achieve this by following these steps:
remove all foreign keys and primary key of the original table.
rename the original table.
using CTAS, create the original table in the order you want.
drop the old table.
apply all constraints back to the original table.