select max value of a column in table with no rows - sql

I am using oracle database
While inserting a row in a table, i need to find the max value of a column and increment it by 1, and use that value in row i am inserting.
INSERT INTO dts_route
(ROUTE_ID, ROUTE_UID, ROUTE_FOLDER)
VALUES (
(SELECT MAX(ROUTE_ID) + 1 FROM route) ,
ROUTE_UID,
ROUTE_FOLDER)
This works fine if their is at least one entry in table.
But returns null when their are no entries in table.
How can i get default value of 1 when their are no entries in table.

SELECT COALESCE(MAX(ROUTE_ID),0) ...

This is not a safe way of creating an auto-increment field. You can use an Oracle sequence to achieve this goal.
As for the null, you can use NVL to give a default value (say, 0) in case the function returns null.

Use sequence for the ID. You need to create sequence. See below link
http://www.basis.com/onlinedocs/documentation/b3odbc/sql_sequences.htm

Use:
INSERT INTO dts_route
(ROUTE_ID)
SELECT COALESCE(MAX(r.route_id), 0) +1
FROM ROUTE r
...but you really should be using a sequence to populate the value with a sequential numeric value:
CREATE SEQUENCE dts_route_seq;
...
INSERT INTO dts_route
(ROUTE_ID)
SELECT dts_route_seq.NEXTVAL
FROM DUAL;

Set a default for NULL
SELECT NVL(MAX(ROUTE_ID),0)
though using a sequence might be easier if you don't mind the odd gaps in your route ids

select 0 when null, then it will be 0+1 which is a correct number compared to null+1
SELECT isnull(MAX(ROUTE_ID),0) + 1 FROM route

If you are concerned about there being gaps in your route ids then create the sequence with the NOCACHE clause:
CREATE SEQUENCE dts_route_seq NOCACHE;
Note that there is a performance hit because Oracle now has to "commit" each time you increment the sequence.

Related

Alter / Update PostgreSQL Sequence

How can I update the last_value field in my sequence and add 1 to it?
The query I tried: ALTER SEQUENCE "seq_hours" SET 'last_value' = 'last_value' + 1
However this did not work.
Use setval() with a subquery to get the value from a table, e.g.
SELECT setval('seq_hours', (SELECT max(last_value)+1 FROM t));
EDIT: This solution only makes sense if you want to set the current value of a sequence based on a value from a given table. If you only want the next possible value of a sequence you should use nextval as #a_horse_with_no_name suggested (see comments)

How to auto_increment a value from a column when inserting a new row

I know that it seems similar to some questions, but I hope mine is different.
I work with an Oracle Database
I want to have an auto_increment on a column by using
COMPUTED column and LAST_VALUE(column) + 1
So I have the following request :
ALTER TABLE schema.table (
ADD SK NUMBER ALWAYS AS (LAST_VALUE(SK)+1)
);
Is it gonna do the trick with only that ?
Or do I need to add a FOR EACH ROW sentence so that fits with my need of auto_increment ?
EDIT According to G00dy's comment:
The sequence :
create sequence SK_SEQUENCES
increment by 1
start with 1
nomaxvalue
minvalue 1
nocycle
order
keep;
The table :
create table schema.test(
isCurrent CHAR(10),
SK NUMBER
);
If I understand the comment from #g00dy,
I need to add the Sequence as a value for my column SK,
so I have this :
insert into schema.test(SK)
values (SK_SEQUENCES.nextval)
Then ok, it works
But when I'm adding value to the isCurrent column,
there's no auto_increment on the SK column
I guess, to have the auto_increment I need to create a trigger.
Maybe I'll have to use trigger/sequence in order to fix my issue but I don't want to..
No, it won't work.
Firstly, the syntax is generated always, not just always, and there are no brackets around the add clause. However, this still won't work:
alter table demo
add sk integer generated always as (last_value(sk)+1);
fails with:
ORA-30484: missing window specification for this function
because last_value is an analytic function that needs to be part of a query and have a window specification like over (partition by xxx order by yyy). You can't use an analytic function as a column default.
From Oracle 12.1 you can define an identity column as:
alter table demo
add sk integer generated always as identity;
In earlier Oracle versions you would need to either specify the sequence.nextval when inserting, or else create a trigger as
create sequence sk_seq;
create or replace trigger demo_generate_sk_trg
before insert on demo for each row
begin
:new.dummy := sk_seq.nextval;
end;
/

Insert value into an old identity field

I have a table which had an identity column.
for many reasons we had to remove the identity from that column.
I have a system that inserts a value to that table by the old way, passes null for the identity column.
is there a simple way to define identity column to receive a value in case it is passed to it, and if a value of null is passed, to make that table to set a unique value to that field that is not found in that table (act like identity).
What i mean is, if there is value, insert it.
And if the system tries to insert null act like an identity.
Thanks in advance.
A trigger seems like a good choice for this situation, but there are a lot of ways you can handle the situation.
The example below creates an INSTEAD OF insert trigger that gets the columns that were supposed to be inserted, and generates a new value via a function if the ID column is null.
CREATE TRIGGER myTrigger ON myTable
INSTEAD OF INSERT
AS
INSERT INTO myTable (myIDcolumn, anotherColumn)
SELECT COALESCE(myIDColumn, dbo.SomeMethodToCreateID), anotherColumn
FROM inserted
How that SomeTheodToCreateID function is to work is up to you. One thing you could do is change the SELECT to combine max plus row_number:
SELECT (COALESCE(myIDColumn,
(SELECT MAX(myIDColumn) FROM myTable) + ROW_NUMBER() OVER(ORDER BY anotherColumn)
)
...
Try This
DBCC CHECKIDENT ( '[dbo].[Customers]', RESEED, 1 )

Query for first occurence of null value in SQLite

I have a table which I dynamically fill with some data I want to create some statistics for. I have one value which has some values following a certain pattern, so I created an additional column where I map the values to other values so I can group them.
Now before I run my statistics, I need to check if I have to remap these values which means that I have to check if there are null values in that column.
I can do a select like this:
select distinct 1
from my-table t
where t.status_rd is not null
;
The disadvantage is, that this returns exactly one row, but it has to perform a full select. Is there some way that I can stop the select for the first encounter? I'm not interested in the exact row, because when there is at least one row, I have to run an update on all of them anyway, but I would like to avoid running the update unnecessarily everytime.
In Oracle I would do it with rownum, but this doesn't exist in SQLite
select 1
from my-table t
where t.status_rd is not null
and rownum <= 1
;
Use LIMIT 1 to select the first row returned:
SELECT 1
FROM my_table t
WHERE t.status_rd IS NULL
LIMIT 1
Note: I changed the where clause from IS NOT NULL to IS NULL based on your problem description. This may or may not be correct.

Intervals: How can I make sure there is just one row with a null value in a timstamp column in table?

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.