SQL Server: how to add new identity column and populate column with ids? - sql

I have a table with huge amount of data. I'd like to add extra column id and use it as a primary key. What is the better way to fill this column with values from one 1 to row count
Currently I'm using cursor and updating rows one by one. It takes hours. Is there a way to do that quicker?
Thank you

Just do it like this:
ALTER TABLE dbo.YourTable
ADD ID INT IDENTITY(1,1)
and the column will be created and automatically populated with the integer values (as Aaron Bertrand points out in his comment - you don't have any control over which row gets what value - SQL Server handles that on its own and you cannot influence it. But all rows will get a valid int value - there won't be any NULL or duplicate values).
Next, set it as primary key:
ALTER TABLE dbo.YourTable
ADD CONSTRAINT PK_YourTable PRIMARY KEY(ID)

If you want to add row numbers in a specific order you can do ROW_NUMBER() into a new table then drop the original one. However, depending on table size and other business constraints, you might not want to do that. This also implies that there is a logic according to which you will want the table sorted.
SELECT ROW_NUMBER() OVER (ORDER BY COL1, COL2, COL3, ETC.) AS ID, *
INTO NEW_TABLE
FROM ORIGINAL_TABLE

Related

How to alter PostgreSQL column with entries to be a nextval id

I have a problem with a really big database with following scheme:
id | date | other columns...
The id column is from type integer. It would be ideal if it where from type integer with a nextval constraint. Many of the id entries have unique id's incremented when they where added.
The problem is all rows added since a specific date have no id and the value is null.
Is it possible to add such constraints to tables with existing values (plus null values) so that the null values are filled with integer id's?
And is this possible without losing the old id's and in the best case with ascending order in relation to the date column?
thanks and greetings
You need to first update the existing rows with a unique, non-null value:
update the_table
set id = new_id
from (
select ctid,
(select max(id) from the_table) + row_number() over (order by date) as new_id
from the_table
where id is null
) t
where t.ctid = the_table.ctid;
I am not sure if the order of the IDs is guaranteed using this approach, but it's likely that it does.
Now, that the column doesn't contain any NULL values, we can either change it automatically assign new values.
The next steps depend on whether you want to make this an identity column or simply a column with a default from a sequence (essentially a (discouraged) serial column)
Staying with a "serial"
We need to create a sequence and sync it with the highest value in the column.
create sequence the_table_id_seq;
select setval('the_table_id_seq', max(id))
from the_table;
Then use this for the default and link the sequence to the column.
alter table the_table
alter id set not null,
alter id set default nextval('the_table_id_seq') ;
alter sequence the_table_id_seq owned by the_table.id;
Using an identity column (recommended)
To make this a proper (recommended) identity column (Postgres 10 and later) you can do it like this:
alter table the_table
alter id set not null,
alter id add generated always as identity;
Now adding the identity attribute created a new sequence which we need to sync with the existing values in the column:
select setval(pg_get_serial_sequence('the_table', 'id'), max(id))
from the_table;
Alternatively, you could have manually looked up the current max value and provide that directly when specifying the identity default:
alter table the_table
alter id set not null,
alter id add generated always as identity (start with 42);

Select row query given table name and primary key in Oracle?

So after googling this simple question, I could have not find an answer anywhere. I only have very basic database knowledge, and I need a query in Oracle to properly select a row given a table name and a primary key. Most examples I have found all find rows based of a row number or rowID (is that the same as primary key?).
Any help on this would be greatly appreciated.
Do you have the primary key column and the value you want to query? Where or what exactly did you search for? This is a very basic SELECT statement in any relational database:
SELECT *
FROM table_name
WHERE primary_key_column = primary_key_value
Unless, of course, I didn't understand the question.
A primary key is a unique identifier for a row in a table. Each row will have a primary key that is different from all other rows. This key can be one value, such as a rowID, or it can be a composite value (multiple columns used as a primary key because there may not be a need for an extra column only to store a rowID).
#tilley31 above shows a great example of how to search for a specific row in a table. If the primary key was composite;
SELECT *
FROM table_name
WHERE primary_key_column1 = primary_key_value1
AND primary_key_column2 = primary_key_value2
ROWID is a pseudocolumn that returns the address of a row and is usually unique, exception being where more than one table is stored in a same cluster then those tables rows can share the same rowid. ROWID is implicitly given by the oracle to rows.
Primary key uniquely identifies a row at a table level and is created by the user who created the table.
Getting the ROWID of a Row
SELECT ROWID,FIELDNAME FROM ABC;
Getting the PRIMARY Key of a table
SELECT * FROM USER_CONSTRAINTS WHERE TABLE_NAME='YOUR_TABLENAME'
AND CONSTRAINT_TYPE='P';
I guess you are intent to dynamically choose table and where clauses in query (?)
If this is what you want to do then answer is No. Its not possible just through query. You could achieve it through pl/sql. and if you must have this as a query consider using a table function like below -
SELECT * FROM TABLE(func('TABLE_NAME','WHERE_CONDITION'))
Check out this link: https://oracle-base.com/articles/misc/pipelined-table-functions
Again this requires you to have preset output columns (COLUMN1, COLUMN2 etc). You will not be able to select exact column names from table.
Overall this is going to be messy.

SQL Server Constraint (Limit bit field based on a foreign key)

I need help with constraints in SQL Server. The situation is for each OrderID=1 (foreign key not primary key so there are multiple rows with the same ID) on the table, the bit field can only be 1 for one of those rows, and for each row with OrderID=2, the bit field can only be 1 for one row, etc etc. It should be 0 for all other rows with the same OrderID. Any new records coming in with 1 in the bit field should reject if there is already a row with that OrderID which has the bit field set to 1. Any ideas?
CREATE UNIQUE INDEX ON UnnamedTable (OrderID) WHERE UnnamedBitField=1
It's called a Filtered Index. If you're on a pre-2008 version of SQL Server, you can implement a poor-mans equivalent of a filtered index using an indexed view:
CREATE VIEW UnnamedView
WITH SCHEMABINDING
AS
SELECT OrderID From UnnamedSchema.UnnamedTable WHERE UnnamedBitField=1
GO
CREATE UNIQUE CLUSTERED INDEX ON UnnamedView (OrderID)
You can't really do it as a constraint, since SQL Server only supports column constraints and row constraints. There's no (non-fudging) way to write a constraint that deals with all values in the table.
You could more fully normalize the schema which will help you not have to hunt for the already set bit but use a join. You need to remove the bit field and crate a new table say X containing OrderID and the primary key of your table, with the primary key of X being all those fields.
This means that when you insert you need to insert into your original table and into X f and only if you would have set the bit to 1 on your table. The insert will fail if there is already a row in X which is as if there was already an original row with bit set to 1.
The downside is that this takes up more space than your schema but is easier to maintain as you can't get to the equivalent of having two rows with the bit set to 1.
The only way to do that is to subclass the parent table. You didn't mention it but a common reason for this pattern is to represent one unique active row from the set of all rows with the same common key value. Let's Assume your bit field represents the active Orders....
Then I would create a separate table called ActiveOrders, which will only contain the one row with the bit field set to 1
Create Table ActiveOrders(int Orderid Primary Key Null)
and the other table with all the rows in it, with it's own unique Primary Key OrderId
Create Table AllOrders
(OrderId Integer Primary Key Not Null, ActiveOrderId Integer Not Null,
[All other data fields]
Constraint FK_AllOrders2ActiveOrder
Foreign Key(ActiveOrderId) references ActiveOrders(OrderId))
You now no longer even need the bit field, as the presence of the row in the ActiveOrders table identifies it as the Active Order... To get only the active Orders (the ones that in your scheme would have bit field set to 1), just join the two tables.
I aggree with the other answers and if you can change the schema then do that but if not then I think something like this will do.
CREATE FUNCTION fnMyCheck
(#id INT)
RETURNS INT
AS
BEGIN
DECLARE #i INT
SELECT #i = COUNT(*)
FROM MyTable
WHERE FkCol = #id
AND BitCol = 1
RETURN #i
END
ALTER TABLE YourTable
ADD CONSTRAINT ckMyCheck CHECK (fnMyCheck(FkCol)<=1)
but there are problems that can come from doing using a udf in a check constraint, such as this
Edit to add comment regarding problems with this 'solution':
There are more straightforward issues than what you've linked to.
INSERT INTO YourTable(FkCol,BitCol) VALUES (1,1),(1,0)
followed by
UPDATE YourTable SET BitCol=1
succeeds and leaves two rows with FkCol=1 and BitCol=1

Unique index in already existing database table

I am trying to add a new unique index on one of my database tables in SQL Server 2008. This is an existing table and the column where I want the unique index already has some duplicate values.
Can I set up a unique index for that column? If so, how?
You can't set this column up with a UNIQUE index if the table already has duplicate values, unless you remove the records containing the duplicate values for that column. This goes to the definition of UNIQUE.
First you are gonna need to delete the duplicate values on your column and then you can create a unique index on it. So lets assume your table has 2 columns, id and column1. To delete duplicate values you need to choose one, it can be random or with some order. So it would be like this:
WITH CTE AS
(
SELECT *, ROW_NUMBER() OVER(PARTITION BY column1 ORDER BY Id) Corr
FROM YourTable
)
DELETE FROM CTE
WHERE Corr > 1
CREATE UNIQUE INDEX I_Unique ON YourTable(Column1)
No as the name suggest, Unique Index which says key has to be unique. So you cant
See this
If the column already has duplicate values then I would recommend you create a unique composite key instead.
e.g.
So, to handle that issue with this table design, you need to create a unique constraint on the table CustomerID/ProductID columns:
create unique index cust_products_unique on CustomerProducts (CustomerID, ProductID)
So that in essence a combination of fields ensures that the index is unique.
Regards
May not have been true in SQL Server 2008, however you can use Management Studio to do this in later versions such as 2014.
Right click your table
Choose Design
Expand "Identity Specification" and set (is Identity) to Yes
Save

How to insert duplicate rows in SQLite with a unique ID?

This seems simple enough: I want to duplicate a row in a SQLite table:
INSERT INTO table SELECT * FROM table WHERE rowId=5;
If there were no explicit unique column declarations, the statement would work, but the table's first column is declared rowID INTEGER NOT NULL PRIMARY KEY. Is there any way to create a simple statement like the one above that works without knowing the schema of the table (aside from the first column)?
This can be done using * syntax without having to know the schema of the table (other than the name of the primary key). The trick is to create a temporary table using the "CREATE TABLE AS" syntax.
In this example I assume that there is an existing, populated, table called "src" with an INTEGER PRIMARY KEY called "id", as well as several other columns. To duplicate the rows of "src", use the following SQL in SQLite3:
CREATE TEMPORARY TABLE tmp AS SELECT * FROM src;
UPDATE tmp SET id = NULL;
INSERT INTO src SELECT * FROM tmp;
DROP TABLE tmp;
The above example duplicates all rows of the table "src". To only duplicate a desired row, simply add a WHERE clause to the first line. This example works because the table "tmp" has no primary key constraint, but "src" does. Inserting NULL primary keys into src causes them to be given auto-generated values.
From the sqlite documentation: http://www.sqlite.org/lang_createtable.html
A "CREATE TABLE ... AS SELECT" statement creates and populates a database table based on the results of a SELECT statement. A table created using CREATE TABLE AS has no PRIMARY KEY and no constraints of any kind.
If you want to get really fancy, you can add a trigger that updates a third table which maps old primary keys to newly generated primary keys.
No. You need to know the schema of the table to write the insert statement properly.
You need to be able to write the statement in the form of:
insert into Table (column1, column2, column3)
select column1, column2, column3
from OtherTable
where rowId = 5
Well, since I was unable to do this the way I wanted, I resorted to using the implicit row id, which handily enough has the same name as the rowId column I defined explicitly, so now I can use the query I had in the question, and it will insert all the data with a new rowId. To keep the rest of the program working, I just changed SELECT * FROM table to SELECT rowId,* FROM table and everything's fine.
Absolutely no way to do this. Primary Key declaration implies this field is unique. You can't have a non unique PK. There is no way to create a row with existing PK in the same table.