ORA-32796: cannot update a generated always identity column - database

I am converting some code from vb.net 2008 to vb.net 2019. I got some warnings in my code that the Oracle reference I was using would be outdated in future versions so I switched to a Oracle.ManagedDataAccess reference.
It seems I can read data but unfortunately when I try to write data, I am running into issues I didn't have before. When I try to update an existing record in my Oracle database, I am getting this error:
ORA-32796: cannot update a generated always identity column
If I change my query to only include the fields I want to update then I get this error:
Dynamic SQL generation failed. No key information found
The second error makes sense but not the first. It seems like there's something about my ID column the new code doesn't like. I'm not a db expert or anything but I am not sure how to fix this.

Looks like table's ID column was created as
id NUMBER GENERATED ALWAYS AS IDENTITY
------
If it was
id NUMBER GENERATED BY DEFAULT AS IDENTITY
----------
then you, I presume, wouldn't get that error.
Anyway: it would help if you posted CREATE TABLE as well as DML you preformed against that table.

The solution is the same as one of my previous answer
If you have generated/created the table with scripts like this:
ID NUMBER GENERATED ALWAYS AS IDENTITY
Then it will not allow you to update or insert the value of the ID column.
if you have generated like this, you could insert or update
ID NUMBER GENERATED BY DEFAULT AS IDENTITY
However, by altering the table you can achieve this
ALTER TABLE [TableName] MODIFY ID GENERATED BY DEFAULT AS IDENTITY (START WITH LIMIT VALUE);
and after updating or inserting you can go back to the previous state by running the following script
ALTER TABLE [TableName] MODIFY ID GENERATED ALWAYS AS IDENTITY (START WITH LIMIT VALUE);

Related

Is there any way to update the modified date time automatically in SQL Server?

Is there any way to update the modified date time automatically in SQL Server.
I do not want to use Triggers. Also I want to avoid providing the value through application while calling SQL query.
Is there any support in SQL or in Dapper etc.
If you want to keep track of the changes in database you can use a feature called
System-Versioned Temporal Table as explained here.
Using a Temporal Table, you will be able to query the recent state of the row as usual, in addition to the ability to query the full history of that row
It's very handy if you are interested in keeping a history of data changes
I am able to solve the problem using Temporal Table. I am not sure is this a elegant solution. Here is how i solved.
Create Table:
CREATE TABLE extable4 (PriKey int PRIMARY KEY, ColValue varchar(200)
, [ModifiedDateTime] datetime2 (2) GENERATED ALWAYS AS ROW START
, [ModifiedExpiryDateTime] datetime2 (2) GENERATED ALWAYS AS ROW END HIDDEN
, PERIOD FOR SYSTEM_TIME (ModifiedDateTime,[ModifiedExpiryDateTime])
) ;
Insert a record with out providing input to ModifiedDatetime.
insert into extable4(PriKey,ColValue) values(1,'Ver 1');
ModifiedDateTime Populated with systime.
update extable4 set ColValue='Ver 1.1' where PriKey=1;
ModifiedDateTime updated now. :)

EF - pass null value to SQL column so default value gets inserted

SQL Server table T2 has 2 columns:
Id INT NOT NULL
CreateDate DateTime NOT NULL, default = (getdate())
This statement inserts the CreateDate value correctly because it uses (getdate()) as default.
Insert T2 (Id)
Values (1)
So far so good. The problem is when I use Entity Framework to insert a row and still wish to use the default (getdate()) value.
Because the CreateDate is defined as NOT NULL, I cannot leave it blank or leave out of the Insert statement when using EF. But I want SQL to generate the timestamp on the server/database side.
Is there a way to handle this?
Thanks to squillman's reference to another SO post, I was able to find the answer.
Go to EDMX diagram, and you can set the StoreGeneratedPattern property to achieve what I am trying to do.
There are three Database Generated Options
Computed : The database generates a value when a row is inserted or updated.
Identity : The database generates a value when a row is inserted.
None : The database does not generate values.
EDIT: Although the picture shows Identity, I had to change it to Computed. The reason is that Identity option only works if the row is Inserted only. If the row is ever updated (other columns updated), then it caused an error. The Computed option seems to work fine with Insert (runs the default script) and Updates (to other columns, default script does not run again).

Stored procedure to generate a unique id column

Good day
I have a situation where two users are saving data to the same database and there are primary key conflicts.
Is it possible to write a stored procedure or trigger which will generate a unique identity by adding two columns.
For instance: I have table2 related to table1 by Table1ID. Increment and seed is 1 for both.
If I had to add a row to table2 I would like the autogenerated ID number to be added to a text column thereby making it unique. So the ID would be something like JoeSoap5.
If you want to generated something unique you can use the build-in function "NEWID()". Type and executed the following code:
SELECT NEWID()
If you need to insert record in second table when record in your first table is inserted, is is possible to implement this using TRIGGERS. In your case you can use "AFTER INSERT TRIGGER" or "BEFORE INSERT TRIGGER" - generally this will be a piece of code that will be executed AFTER/BEFORE row in your first table is inserted.
You don't specify your SQL Server version.
SQL 2012 introduces the concept of a sequence - http://msdn.microsoft.com/en-us/library/ff878091.aspx - which would allow you to do just what you want.

SQL server trigger question

I am by no means a sql programmer and I am trying to accomplish something that I am pretty sure has been done a million times before.
I am trying to auto generate a customer number in sql every time a new customer is inserted, but the trigger (or sp?) will only work if at least the first name, last name and another value called case number is entered. If any of these fields are missing, the system generates an error. If the criteria is met, the system generates and assigns a unique id to that customer that begins with letters GL- and then uses 5 digit number so a customer John Doe would be GL-00001 and Jane Doe would be GL-00002.
I am sorry if I am asking too much but I am basically a select insert update guy and nothing more so thanks in advance for any help.
If I were in this situation, I would:
--Alter the table(s) so that first name, last name and case number are required (NOT NULL) columns. Handle your checks for required fields on the application side before submitting the record to the database.
--If it doesn't already exist, add an identity column to the customer table.
--Add a persisted computed column to the customer table that will format the identity column into the desired GL-00000 format.
/* Demo computed column for customer number */
create table #test (
id int identity,
customer_number as 'GL-' + left('00000', 5-len(cast(id as varchar(5)))) + cast(id as varchar(5)) persisted,
name char(20)
)
insert into #test (name) values ('Joe')
insert into #test (name) values ('BobbyS')
select * from #test
drop table #test
This should satisfy your requirements without the need to introduce the overhead of a trigger.
So what do you want to do? generate a customer number even when these fields arn't populated?
Have you looked at the SQL for the trigger? You can do this in SSMS (SQL Server Managment Studio) by going to the table in question in the Object Explorer, expanding the table and then expanding triggers.
If you open up the trigger you'll see what it does to generate the customer number. If you are unsure on how this code works, then post the code for the trigger up.
If you are making changes to an existing system i'd advise you to find out any implications that changing the way data is inputted works.
For example, others parts of the application may depend on all of the initial values being populated, so after changing the trigger to allow incomplete data to be added, you may inturn break something else.
You have probably a unique constraint and/or NOT NULL constraints set on the table.
Remove/Disable these (for example with the SQL-Server Management Console in Design Mode) and then try again to insert the data. Keep in mind, that you will probably not be able to enable the constraints after your insert, since you are violating conditions after the insert. Only disable or reomve the constraints, if you are absolutely sure that they are unecessary.
Here's example syntax (you need to know the constraint names):
--disable
ALTER TABLE customer NOCHECK CONSTRAINT your_constraint_name
--enable
ALTER TABLE customer CHECK CONSTRAINT your_constraint_name
Caution: If I were you, I'd rather try to insert dummy values for the not null columns like this:
insert into customers select afield , 1 as dummyvalue, 2 as dummyvalue from your datasource
A very easy way to do this would be to create a table of this sort of structure:
CustomerID of type in that is a primary key and set it as identity
CustomerIDPrfix of type varchar(3) which stores GL- as a default value.
Then add your other fields and set them to NOT NULL.
If that way is not acceptable and you do need to write a trigger check out these two articles:
http://msdn.microsoft.com/en-us/library/aa258254(SQL.80).aspx
http://www.kodyaz.com/articles/sql-trigger-example-in-sql-server-2008.aspx
Basiclly it is all about getting the logic right to check if the fields are blank. Experiment with a test database on your local machine. This will help you get it right.

Can you limit the number of rows in a (database) table?

We have a database (SQL Server 2005) which we would like to get under source control. As part of that we are going to have a version table to store the current version number of the database. Is there a way to limit that table to only holding one row? Or is storing the version number in a table a bad idea?
Ended up using this approach:
CREATE TABLE [dbo].[DatabaseVersion]
(
[MajorVersionNumber] [int] NOT NULL,
[MinorVersionNumber] [int] NOT NULL,
[RevisionNumber] [int] NOT NULL
)
GO
Insert DataBaseVersion (MajorVersionNumber, MinorVersionNumber, RevisionNumber) values (0, 0, 0)
GO
CREATE TRIGGER DataBaseVersion_Prevent_Delete
ON DataBaseVersion INSTEAD OF DELETE
AS
BEGIN
RAISERROR ('DatabaseVersion must always have one Row. (source = INSTEAD OF DELETE)', 16, 1)
END
GO
CREATE TRIGGER DataBaseVersion_Prevent_Insert
ON DataBaseVersion INSTEAD OF INSERT
AS
BEGIN
RAISERROR ('DatabaseVersion must always have one Row. (source = INSTEAD OF INSERT)', 16, 1)
END
GO
Use a trigger.
Generalize the table to hold "settings" and make it a key/value pair
CREATE TABLE Settings (Key nvarchar(max), Value nvarchar(max))
Then make a unique index on Key.
CREATE UNIQUE INDEX SettingsIDX ON Settings (Key)
That will create a table with unique key value pairs, one of which can be Version.
INSERT INTO Settings (Key, Value) VALUES ('Version','1');
You can use Joe Celko's default+primary+check technique:
create table database_version (
lock char(1) primary key default 'x' check (lock='x'),
major_version_number int NOT NULL,
minor_version_number int NOT NULL,
revision_number int NOT NULL
);
Fiddle with it
Not at all. You can simply add another, ascending column to that table (date, id, whatever), and then order the query by that other column descendingly and limit the result to 1 row:
SELECT v.version FROM version v ORDER by v.date DESC LIMIT 1;
This way you even get a history of when each version was reached.
Edit:
The above sql query wouldn't work on SQL Server since it doesn't support the LIMIT statement. One would have to circumvent that deficiency, possibly as described in this "All Things SQL Server" blog entry.
Based on your comments to other responses, it seems that:
You don't want users to just modify the value.
You only ever want one value returned.
The value is static, and scripted.
So, might I suggest that you script a function that returns the static value? Since you'll have to script an update to the version number anyway, you'll simply drop and recreate the function in your script when you update the database.
This has the advantage of being usable from a view or a procedure, and since a function's return value is read-only, it can't be modified (without modifying the function).
EDIT: You also wouldn't have to worry about convoluted solutions for keeping a table constrained to one row.
Just a suggestion.
Keeping a version number for the database makes total sense. However I prefer to have a Version table that can contain multiple rows with fields for the version number, the time the update occured and the user that performed the upgrade.
That way you know which upgrade scripts have been run and can easily see if they have been run out of sequence.
When you want to read the current version number you can just read the most recent record.
If you only store one record you have know way of knowing if a script has been missed out. If you want to be really clever you can put checks in you upgrade scripts so they won't run unless the previous version of the database is correct.
By creating the one allowable original row as part of the database initialization script, and (also in that script) removing Insert permissions to that table for all logins (Only Updates will be allowed)
You might also want to disallow deletes as well...

Resources