I have a Postgres table with certain data, let's say I have 3 columns at the beginning:
name
age
gender
Name1
31
F
Name2
18
M
Name3
22
F
Later on I want to add a new field created_date to record when a user is created and meet 2 sceanrios:
For the existing users, leave the fields empty
For the new users, the field created_date is required and can't be NULL.
Now I can't find a way to how to define "empty" since it can't be null if I add created_date NOT NULL like below query, but the same time I don't want to add DEFAULT xxx since the time is inaccurate.
ALTER TABLE `users`
ADD `created_Date` DATETIME NOT NULL
DEFAULT '2023-02-03 00:00:00'
Can anyone help to define the "empty" in this case?
There are only three options:
Make the new column not nullable
Make the column nullable and use a default date for all existing entries like 01.01.2000. You can set a default value on the column or do an update after adding the column. In the second case the not null needs to be added (with alter table statement) to the column after the update statement.
Create a complete new Table and use it to insert new entries. To read all values together (old entries without date column and new columns with date column) you can make a View which combines the two tables with a union all. This case requires adjustments in your Application and a good thinking about to not have duplicate entries in both tables. And of course the sequences needs to be adjusted aswell. I would not go this way.
Unfortunately there is no other option if the column needs to be not null.
I'd recommend instead:
ALTER TABLE users
ADD COLUMN created TIMESTAMP WITH TIME ZONE NOT NULL
DEFAULT '1970-01-01 00:00:00 UTC';
ALTER TABLE users
ALTER COLUMN created SET DEFAULT now();
That's because:
The column name "current_date" is misleading. This is a timestamp, not just a date.
You should always use "timestamp with time zone" for timestamps, or you'll otherwise have various bugs, like values going backwards, being duplicated, jumping forward, being interpreted differently depending on the client's time zone etc.
This will fill currently existing rows with the timestamp '1970-01-01 00:00:00 UTC', which is immediately recognized as a timestamp "0", so called "epoch time", making it obviously fake, but still older than any newly created.
After that, changing the default to now() will make new rows fill the timestamp automatically and correctly, when the client will either skip the column or will use DEFAULT as value.
Related
Adding a column to one of my tables like this :
ALTER TABLE MY_TABLE
ADD S_CHANGED TIMESTAMP NOT NULL GENERATED ALWAYS FOR EACH ROW ON UPDATE AS ROW CHANGE TIMESTAMP
leads to an initial S_CHANGED value of zero (year zero) for existing rows.
Is there a way to specify a default value (e.g. CURRENT_TIMESTAMP) within the same SQL query, or is an UPDATE query required for that? Adding DEFAULT CURRENT_TIMESTAMP causes an error.
I would like to append two timestamp columns to an existing table.
CREATED_TSTMP would be populated with the current timestamp when a record is inserted and LAST_UPD_TSTMP would be updated automatically when a record in the table gets updated.
I would like to do this without having to modify existing queries.
I have the following DDL statements:
ALTER TABLE XXX ADD CREATED_TSTMP TIMESTAMP NOT NULL WITH DEFAULT CURRENT TIMESTAMP ;
alter table XXX add column LAST_UPD_TSTMP timestamp not null generated by default for each row on update as row change timestamp ;
However once the columns are appended, this will cause an existing query with the following syntax:
INSERT INTO XXX VALUES(?,?,?,?,?,?,?,?,?,?)
to fail with
The number of values assigned is not the same as the number of
specified or implied columns or variables..
Is there any way around this problem without having to inspect all of the existing queries (there are hundreds of them...)
If you add the IMPLICITLY HIDDEN option when creating the columns, they will be ignored by the SQL statements unless you explicitly mention these columns.
PS. I'm assuming you are on a sufficiently recent version of DB2, because of your using row change timestamp. To avoid ambiguity, you should indicate the DB2 version and platform in question.
I have the following table:
Study id
Pepsi 1
Coke 2
Sprite 3
I need to add a new column timestamp in the above table. i.e, study creation time and date will be stored in this column. What value should I have set for existing rows? Or should the "Timestamp" column have a value only for newly created rows?
I have used the following query to add the new column:
alter table Study add Timestamp datetime
There is no way to tell you what value you should set for existing rows - that is up to you to decide. If you can somehow retrieve the creation time by piecing together other information, then perhaps you can do this one by one, or you could just leave the existing rows to NULL.
Setting a default like GETDATE() for the column, and setting it to NOT NULL, forces all of the existing rows to inherit the current date and time - and you won't be able to set those back to NULL. I'm quite opposed to using garbage token values like 1900-01-01 to represent unknown, and I also don't believe in modifying the code to say something like "if the date is October 8, 2013 then that's because we just didn't know." So I would suggest adding a NULLable column with a default:
ALTER TABLE dbo.Study ADD CreationTime DATETIME NULL DEFAULT CURRENT_TIMESTAMP;
GO
Note that if you leave the column nullable, then the DEFAULT constraint is only useful if DML never sets it to NULL. If an INSERT statement, for example, explicitly places NULL there, the default is ignored. A way around this is to use a trigger (just like you would handle an update):
CREATE TRIGGER dbo.StudyCreationTime
ON dbo.Study
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE s
SET s.CreationTime = CURRENT_TIMESTAMP
FROM dbo.Study AS s
INNER JOIN inserted AS i
ON s.StudyID = i.StudyID;
END
GO
what value should i have to set for previous studies
This would have to be defined by your business. This doesn't require a technical answer, so no one here can tell you what is right.
I have used below query to adding new column:
alter table Study add Timestamp datetime
This will work just fine, though this will allow nulls. I might suggest making this column non-null, adding a default, and changing the name of the column slightly since timestamp is a reserved word in SQL Server (a datatype that has not much to do with dates or times):
alter table Study add CreateDate datetime not null default current_timestamp;
Note that this will set all rows to the current date and time, so you may want to update them if you have more accurate data. Alternatively, simply create the column as nullable and existing rows won't get the default value, but rather null instead.
Another choice you might have to make is whether to use local time or UTC time (e.g. default getutcdate()). You might want to use the same time that your servers use or that other "CreateDate" columns use.
Is it possible to get last updated time and date of the row using MYSQL server.
Well there is no inbuild feature exists with MySQL. Though you can get the same effect by adding a timestamp column:
ALTER TABLE NAMEYOURTABLE
ADD COLUMN last_update TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
using above to create timestamp with name last_update column will make it pretty much automatically managed and updated. Now you can select from NAMEYOURTABLE the last updated row based on the timestamp.
I have a table with a column which contains a 'valid until' Date and I want to make sure that this can only be set to null in a single row within the table. Is there an easy way to do this?
My table looks like this (postgres):
CREATE TABLE 123.myTable(
some_id integer NOT NULL,
valid_from timestamp without time zone NOT NULL DEFAULT now(),
valid_until timestamp without time zone,
someString character varying)
some_id and valid_from is my PK. I want nobody to enter a line with a null value in column valid_until if there is already a line with null for this PK.
Thank you
In PostgreSQL, you have two basic approaches.
Use 'infinity' instead of null. Then your unique constraint works as expected. Or if you cannot do that:
CREATE UNIQUE INDEX null_valid_from ON mytable(someid) where valid_until IS NULL
I have used both approaches. I find usually the first approach is cleaner and it allows you to use range types and exclude constraints in newer versions of PostgreSQL better (to ensure no two time ranges overlap based on a given given someid), bt the second approach often is useful where the first cannot be done.
Depending on the database, you can't have null in a primary key (I don't know about all databases, but in sql server you can't). The easiest way around this I can think of is to set the date time to the minimum value, and then add a unique constraint on it, or set it to be the primary key.
I suppose another way would be to set up a trigger to check the other values in the table to see if another entry is null, and if there is one, don't allow the insert.
As Kevin said in his answer, you can set up a database trigger to stop someone from inserting more than one row where the valid until date is NULL.
The SQL statement that checks for this condition is:
SELECT COUNT(*)
FROM TABLE
WHERE valid until IS NULL;
If the count is not equal to 1, then your table has a problem.
The process that adds a row to this table has to perform the following:
Find the row where the valid until value is NULL
Update the valid until value to the current date, or some other meaningful date
Insert the new row with the valid until value set to NULL
I'm assuming you are Storing Effective-dated-records and are also using a valid from date.
If so, You could use CRUD stored procedures to enforce this compliance. E.G the insert closes off any null valid dates before inserting a new record with a null valid date.
You probably need other stored procedure validation to avoid overlapping records and to allow deleting and editing records. It may be more efficient (in terms of where clauses / faster queries) to use a date far in the future rather than using null.
I know only Oracle in sufficient detail, but the same might work in other databases:
create another column which always contains a fixed value (say '0') include this column in your unique key.
Don't use NULL but a specific very high or low value. I many cases this is actually easier to use then a NULL value
Make a function based unique key on a function converting the date including the null value to some other value (e.g. a string representation for dates and 'x' for null)
make a materialized view which gets updated on every change on your main table and put a constraint on that view.
select count(*) cnt from table where valid_until is NULL
might work as the select statement. And a check constraint limiting the cnt value to the values 0 and 1
I would suggest inserting to that table through an SP and putting your constraint in there, as triggers are quite hidden and will likely be forgotten about. If that's not an option, the following trigger will work:
CREATE TABLE dbo.TESTTRIGGER
(
YourDate Date NULL
)
CREATE TRIGGER DupNullDates
ON dbo.TESTTRIGGER
FOR INSERT, UPDATE
AS
DECLARE #nullCount int
SELECT #nullCount = (SELECT COUNT(*) FROM TESTTRIGGER WHERE YourDate IS NULL)
IF(#NullCount > 1)
BEGIN
RAISERROR('Cannot have Multiple Nulls', 16, 1)
ROLLBACK TRAN
END
GO
Well if you use MS SQL you can just add a unique Index on that column. That will allow only one NULL. I guess that if you use other RDBMS, this will still function.