Set insert trigger - value to highest value in column + 1 - sql

I have a lists table with the following columns
lists:
- id
- category_id
- name
- sort_order
When adding a new row to the table I want to set the value of the sort order to the highest sort order value + 1 where the category_id is the same as the new row's category_id. Is there a way to achieve this?
UPDATE
So with the recommnendation to create an insert trigger I tried this
CREATE FUNCTION set_list_sort_order()
RETURNS trigger AS $$
BEGIN
NEW.sort_order := select (select sort_order from lists where category_id = NEW.category_id order by sort_order DESC limit 1) + 1
RETURN NEW;
END
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER set_list_sort_order_trigger
BEFORE INSERT ON lists
FOR EACH ROW
EXECUTE PROCEDURE set_list_sort_order()
But I get this error:
ERROR: syntax error at or near "select"
LINE 4: NEW.sort_order := select (select sort_order from lists w...

You can set up a trigger. Or you can set up the logic directly in the insert:
insert into lists (category_id, name, sort_order)
select category_id, name,
coalesce(max(sort_order) + 1, 1)
from (values (?, ?)) v(category_id, name) left join
lists l
using (category_id)
group by v.category_id, v.name;
Note that a query like this could have race conditions. So, you might want to go the route of using a trigger.

you can try to create stored procedure with something like this:
DEClARE #category_id INT = 1
;WITH NextNum AS
(
SELECT
CASE
WHEN MAX(Table1.sort_order) IS NULL THEN 1
ELSE MAX(Table1.sort_order) + 1
END AS NextValue
FROM Table1 AS Table1
WHERE Table1.category_id = #category_id
)
INSERT INTO Table1
(
id
category_id
name
sort_order
)
SELECT #id,
#category_id
#name
NextNum.NextValue
FROM NextNum

Related

Inserting values into a table if the condition in a select query isnt met

I have a table t1 in my oracle database
id name
1 A
2 B
3 C
4 D
5 E
I have used a sequence to add the ids to the table
INSERT INTO t1 (t1seq.nextval, 'A')
I want to now select the id associated with a specific name from the table and if it doesn't exist, insert the name into t1.
SELECT FROM t1 WHERE name = 'F'
should insert a row to t1 if it doesn't exist, I'm trying to use IF EXISTS in oracle but receiving errors.
try this trick
SQL :
IF EXISTS(SELECT * FROM t1 WHERE name = 'F')
BEGIN
RAISERROR (15600,-1,-1, 'DATA EXIST');
RETURN
END
INSERT INTO t1(id,name) values (t1seq.nextval, 'F')
thank u.
You can use the function something like this
...
BEGIN
SELECT ID INTO LV_ID FROM T1 WHERE NAME = P_IN_NAME;
EXCEPTION WHEN NO_DATA_FOUND THEN
LV_ID := NULL;
END;
IF LV_ID IS NULL THEN
LV_ID := T1SEQ.NEXTVAL;
INSERT INTO T1(ID, NAME) VALUES (LV_ID, P_IN_NAME);
END IF;
...
RETURN LV_ID;

SQL FUNCTION - one alias in SELECT AND WHERE

I want to insert to NewTable some id(found by calledMethod) from table 'inserted' when this id actually it's not in this table(NewTable)
Actually i'm using this method (calledMethod)twice. How to reduce this using for example alias?
CREATE TRIGGER TriggerName
ON Table
AFTER INSERT
AS
BEGIN
INSERT INTO NewTable
(
FirstId
SecondId
)
SELECT
I.ID
CalledMethod(I.Name)
FROM INSERTED I
WHERE CalledMethod(I.Name)
NOT IN (SELECT SecondId FROM NewTable)
END
GO
The second problem occures when I want insert two rows at the same time.
Insert Into Table
(
Name
)
Values
('ro'),('ro-RO')
In this situation, the method returns the same index and both will be added. How to resolve this problem.
In this situation, the method returns the same index
This is example of calledMethod
CREATE FUNCTION CalledMethod
(
#internalName nvarchar(50)
)
RETURNS int
AS
BEGIN
return case
when #internalName Like 'ro%' then 6
when #internalName Like 'sk%' then 7
when #internalName Like 'bg%' then 9
end
END
I believe this is what you need:
CREATE TRIGGER TriggerName
ON Table
AFTER INSERT
AS
BEGIN
INSERT INTO NewTable
(
FirstId
SecondId
)
SELECT
min(I.ID),
x.called
FROM INSERTED I
CROSS APPLY
(SELECT CalledMethod(I.Name) called) x
WHERE
x.called NOT IN (SELECT SecondId FROM NewTable)
GROUP BY x.called
END

Update while copy records

I want to copy records from one table to another. While doing this I want to set a flag of those records I copy.
This is how I would do it (simplified):
BEGIN TRANSACTION copyTran
insert into destination_table (name)
select top 100 name
from source_table WITH (TABLOCKX)
order by id
update source_table
set copy_flag = 1
where id in (select top 100 id from source_table order by id)
COMMIT TRANSACTION copyTran
Is there an easier way?
By leveraging OUTPUT clause you can boil it down to a single UPDATE statement
UPDATE source_table
SET copy_flag = 1
OUTPUT inserted.name
INTO destination_table(name)
WHERE id IN
(
SELECT TOP 100 id
FROM source_table
ORDER BY id
)
Note: Now tested. Should work just fine.
The problem with your query is, that you may get different records in your UPDATE if someone inserts some data while you are running your query. It is saver to use the INSERTED keyword.
Declare #temp TABLE (Id integer);
INSERT INTO destination_table (name)
OUTPUT INSERTED.Id into #temp
SELECT TOP 100 name
FROM source_table
ORDER BY id
UPDATE source_table
SET copy_flag = 1
WHERE Id IN (SELECT Id FROM #temp)
I think that you could use a temporary table in which you will store the top 100 ids from your source table, after having ordered them. This way you will avoid executing the select statement in where clause of update for each id.
BEGIN TRANSACTION copyTran
insert into destination_table (name)
select top 100 name
from source_table
order by id
declare #Ids TABLE(id int)
#Ids = (select top 100 id from source_table order by id)
update source_table
set copy_flag = 1
where id in (SELECT * FROM #Ids)
COMMIT TRANSACTION copyTran

Find missing numbers in a column

I have this column in T-SQL:
1
2
3
7
10
have SQl a function for detect the missing numbers in the sequence 4,5,6 and 8,9
I have try
something like
if ( a-b >1 ) then we have a missing number
with coalesce but i dont understand .
Thanks by any orientation
You can try this:
DELCARE #a
SET #a = SELECT MIN(number) FROM table
WHILE (SELECT MAX(number) FROM table ) > #a
BEGIN
IF #a NOT IN ( SELECT number FROM table )
PRINT #a
SET #a=#a+1
END
The following query will identify where each sequence starts and the number that are missing:
select t.col + 1 as MissingStart, (nextval - col - 1) as MissingSequenceLength
from (select t.col,
(select min(t.col) from t t2 where t2.col > t.col) as nextval
from t
) t
where nextval - col > 1
This is using a correlated subquery to get the next value in the table.
I know this is a late answer, but here is a query that uses recursive table expressions to get the missing values between the minimum and maximum values in a table:
WITH CTE AS
(
--This is called once to get the minimum and maximum values
SELECT nMin = MIN(t.ID), MAX(t.ID) as 'nMax'
FROM Test t
UNION ALL
--This is called multiple times until the condition is met
SELECT nMin + 1, nMax
FROM CTE
WHERE nMin < nMax
)
--Retrieves all the missing values in the table.
SELECT c.nMin
FROM CTE c
WHERE NOT EXISTS
(
SELECT ID
FROM Test
WHERE c.nMin = ID
)
This was tested with the following schema:
CREATE TABLE Test
(
ID int NOT NULL
)
INSERT INTO Test
Values(1)
INSERT INTO Test
Values(2)
INSERT INTO Test
Values(3)
INSERT INTO Test
Values(7)
INSERT INTO Test
Values(10)

simple insert procedure, check for duplicate

I am creating a program that is going to insert data into a table which is pretty simple
But my issue is I want my insert statement to make sure that it isnt inserting duplicate data
I want to somehow check the table the data is going into to make sure that there isnt a row with the same indivualid and categoryid and value
So if I am inserting
indivualid = 1
categorid = 1
value = 1
and in my table there is a row with
indivualid = 1
categorid = 1
value = 2
my data would still be inserted
but if there was a row with
indivualid = 1
categorid = 1
value = 1
then it wouldnt
I tried this
IF #value = 'Y'
OR #value = 'A'
OR #value = 'P'
AND NOT EXISTS
(SELECT categoryid,
individualid
FROM ualhistory
WHERE categoryid = #cat
AND individualid = #id)
INSERT INTO individuory(categoryid, individualid, value, ts)
VALUES (#cat,
#id,
#yesorno,
getdate())
but it still inserts duplicates.
You can do that in the following manner:
insert into
individuory(categoryid, individualid, value, ts)
VALUES (#cat, #id, #yesorno, getdate())
where not exists
(select 1 from individuory where categoryid=#cat and individualid=#id)
Now, the exact problem with your approach is that you are not associating the ORs and therefore, the condition becomes true and always inserts the data. You can change your statement to this:
if ((#value = 'Y' or #value = 'A' or #value = 'P')
and not EXISTS
(SELECT categoryid, individualid FROM ualhistory WHERE categoryid = #cat
and individualid = #id) )
INSERT INTO individuory(categoryid, individualid, value, ts)
VALUES (#cat, #id, #yesorno, getdate())
And I think it will work also.
ALTER TABLE individuory
ADD CONSTRAINT myConstarint
UNIQUE (categoryid, individualid, value)
Add a UNIQUE constraint on (individualid, categoryid, value) and the server won't let you insert a duplicate row.
http://msdn.microsoft.com/en-us/library/ms189862.aspx