Creating a sequence on an existing table - sql

How can I create a sequence on a table so that it goes from 0 -> Max value?
I've tried using the following SQL code, but it does not insert any values into the table that I am using:
CREATE SEQUENCE rid_seq;
ALTER TABLE test ADD COLUMN rid INTEGER;
ALTER TABLE test ALTER COLUMN rid SET DEFAULT nextval('rid_seq');
The table I am trying to insert the sequence in is the output from another query. I can't figure out if it makes more sense to add the sequence during this initial query, or to add the sequence to the table after the query is performed.

Set the default value when you add the new column:
create sequence rid_seq;
alter table test add column rid integer default nextval('rid_seq');
Altering the default value for existing columns does not change existing data because the database has no way of knowing which values should be changed; there is no "this column has the default value" flag on column values, there's just the default value (originally NULL since you didn't specify anything else) and the current value (also NULL) but way to tell the difference between "NULL because it is the default" and "NULL because it was explicitly set to NULL". So, when you do it in two steps:
Add column.
Change default value.
PostgreSQL won't apply the default value to the column you just added. However, if you add the column and supply the default value at the same time then PostgreSQL does know which rows have the default value (all of them) so it can supply values as the column is added.
By the way, you probably want a NOT NULL on that column too:
create sequence rid_seq;
alter table test add column rid integer not null default nextval('rid_seq');
And, as a_horse_with_no_name notes, if you only intend to use rid_seq for your test.rid column then you might want to set its owner column to test.rid so that the sequence will be dropped if the column is removed:
alter sequence rid_seq owned by test.rid;

In PostgreSQL:
UPDATE your_table SET your_column = nextval('your_sequence')
WHERE your_column IS NULL;

I'm not fluent in postgresql so I'm not familiar with the "CREATE SEQUENCE" statement. I would think, though, that you're adding the column definition correctly. However, adding the column doesn't automatically insert data for existing rows. A DEFAULT constraint is for new rows. Try adding something like this afterwards to populate data on the existing rows.
DECLARE #i Int
SET #i = 0
SET ROWCOUNT 1
WHILE EXISTS (SELECT 1 FROM test WHERE rid IS NULL) BEGIN
UPDATE test SET rid = #i WHERE rid IS NULL
END
SET ROWCOUNT 0

Related

Snowflake: Trying to make a column to use as default the value from a sequence

So, I have something like this:
CREATE OR REPLACE TABLE TABLE_NAME (
ID NUMBER(38, 0) NOT NULL,
/* OTher elements */
)
With some values already (manually) inserted. I need to update this table so, for future inserts, the value of ID is taken from a sequence I just created:
CREATE OR REPLACE SEQUENCE S_TABLE_NAME_ID
START WITH 451;
For what I've seen in the documentation and in several forums, the syntax should be like this:
ALTER TABLE TABLE_NAME ALTER ID SET DEFAULT S_TABLE_NAME_ID.NEXTVAL;
But when I try to execute it, I get the following error message:
SQL Error [2] [0A000]: Unsupported feature 'Alter Column Set Default'.
Am I missing here something?
from Snowflake Doc (https://docs.snowflake.com/en/sql-reference/sql/alter-table-column.html):
"To change the default sequence for a column, the column must already
have a default sequence. You cannot use the command ALTER TABLE ...
SET DEFAULT <seq_name> to add a sequence to a column that does not
already have a sequence."
So I guess you have to set the sequence as column default when creating the table.

update and concatenate columns in PostgreSQL

I want to update and concatenate 3 columns in a new a attribute I've already created in my table. However when I execute my code, it puts attributes that before had values in null.
My code example:
update saber2012_1
set estu_fecha_nacimiento = Concat(estu_nacimiento_dia,'/',estu_nacimiento_mes,'/',estu_nacimiento_anno);
In this picture all values that is in null before these had values.
when I make this update
ALTER TABLE saber2012_uno ADD COLUMN punt_c_naturales int;
update saber2012_uno set punt_c_naturales = round((PUNT_BIOLOGIA::numeric + PUNT_FISICA::numeric + PUNT_QUIMICA::numeric) / 3,0);
alter table saber2012_uno DROP COLUMN PUNT_BIOLOGIA;
alter table saber2012_uno DROP COLUMN PUNT_FISICA;
alter table saber2012_uno DROP COLUMN PUNT_QUIMICA;
all is well. but I do not know because previous update is incorrect.
Perhaps you want concat_ws():
update saber2012_1
set estu_fecha_nacimiento = concat_ws('/', estu_nacimiento_dia, estu_nacimiento_mes, estu_nacimiento_anno);
This will ignore any of the arguments that are NULL.
However, your update will not change any other columns in the table. Perhaps the results are just coming back in a different order, when you query after the update.

SQL Trigger to add values of Two columns and store it in Third column

i have a table with three columns say pqty,prqty and balqty.
what i want to do is, have to add values of pqty and prqty. and then it should be stored in balqty. while inserting or updating this table, each row must be affect.
i used this trigger, and it worked sometimes and most of times it wont. i dont know why.
CREATE TRIGGER tsl on stockledger
FOR update
AS declare #pqty int, #prqty int;
select #pqty=i.pqty from inserted i;
select #prqty=i.prqty from inserted i;
update Stockledger set balqty = (#pqty - #prqty)
PRINT 'AFTER Update trigger fired.'
I don't think this is a good use of a trigger. Instead, if you have the capacity, consider using a computed column (with PERSISTED to enhance performance):
ALTER TABLE StockLedger DROP COLUMN balqty;
ALTER TABLE StockLedger ADD COLUMN balqty AS pqty - prqty PERSISTED;

timestamp, rowversion and datetime - I need a mark when a row is inserted or updated

I have the following requirement:
I have a table with 1 unique auto-incremental Int ID and data columns.
I need the following:
Every time a row is inserted into that table, a column at the right end of the table must hold the full datetime of that insert.
Also, if a row is updated I need that column that holds the full datetime of the insert of that row into the table, to be updated to hold the update time for that row.
Now the obvious and very straightforward way to do this is:
you create your table:
create table My_Test_Table
(my_id int identity not null,
my_data nvarchar(max));
you alter your table adding the datetime column and a Default constraint on it:
ALTER TABLE My_Test_Table
ADD [timestamp] datetime;
ALTER TABLE My_Test_Table
ADD CONSTRAINT DF_My_Test_Table_timestamp DEFAULT GETDATE() FOR [timestamp];
then you make a nice trigger for update, like so:
CREATE TRIGGER DML_Trigger_update_My_Test_Table
ON My_Test_Table
FOR UPDATE
AS
IF ##ROWCOUNT <> 0
BEGIN
IF EXISTS (SELECT * FROM INSERTED) AND EXISTS (SELECT * FROM DELETED)
BEGIN
UPDATE My_Test_Table
SET [timestamp] = GETDATE()
FROM INSERTED
WHERE My_Test_Table.my_id = INSERTED.my_id;
END
END
Now the tricky part is:
I want, for reasons that are beyond scope here, to implement this exact thing as above but without a Trigger!
Is it possible?
I do not want to use the SQL type timestamp or rowversion, this won't work for me, I need the date, time down to the milliseconds to be clearly stored in that column.
Any ideas would be much appreciated.
You don't need a trigger
You can use the DEFAULT keyword as the source value in the UPDATE statement to use, well, the DEFAULT constraint defined on that column
UPDATE
MyTable
SET
foo = ...,
bar = ...,
ChangedDateTime = DEFAULT
WHERE
...;
I wouldn't use a column called timestamp because this has meaning on SQL Server, as a synonym for rowversion. For SQL Server 2008+ use datetime2(3) to accurately record milliseconds. The "old" datetime is accurate to a rounded 3.33 milliseconds only

How can you make a new, non-nullable column whose initial data will just clone over from that of another column?

Let's say there's a table in SQL Server 2008 with two columns: id and name. Now let's say you want to add a non-nullable column to the table called "description", and in the process of adding this column, you want to use the data in name as the original batch of data in description. Is there not a way to do this directly, i.e., without dropping the table and re-creating it or filling in the values manually post-addition or something? If there is a way, how? Thanks!
You could what you're asking as a computed column, but then you wouldn't be able to later modify the description independently.
What you can do to minimize the impact on the log etc. is to add it as nullable, then update the values in batches, then change it to not nullable.
ALTER TABLE dbo.foo ADD description VARCHAR(whatever) NULL;
SELECT 1;
BEGIN TRANSACTION;
WHILE ##ROWCOUNT > 0
BEGIN
COMMIT TRANSACTION;
BEGIN TRANSACTION;
UPDATE TOP (1000) dbo.foo
SET description = name
WHERE description IS NULL;
END
ALTER TABLE dbo.foo ALTER COLUMN description VARCHAR(whatever) NOT NULL;
COMMIT TRANSACTION;
Or as Dems suggested, add it as not nullable with a default value, then later remove the default constraint.