How to block wrong inserts and updates into one table? - sql

Situation is as below. I have a table like here:
Col1 Col2 Col3 Col4 Col5 Col6
a b c 1 e 1
a b c 3 l 1
a b c 1 e 0
a b f 1 f 1
The idea is that I cant update existing data or add new row
which has combination a b c 1 ? 1.
I have to block adding 1 in last column if there
is already some combination of cols 1-3, but I can still may
add same combination with 0 in col 6.

For more complex logic, you use triggers: trigger gets triggered at specified time (insert, update, delete) - before (use word "for") or after.
Your example - trigger that does not allow inserting given combination of columns:
create table MyTable (
Col1 char, Col2 char, Col3 char, Col4 int, Col5 char, Col6 int
);
insert into MyTable (Col1, Col2, Col3, Col4, Col5, Col6)
values ('a', 'b', 'c', 1, 'e', '1');
insert into MyTable (Col1, Col2, Col3, Col4, Col5, Col6)
values ('a', 'b', 'f', 1, 'e', '1');
create trigger [dbo].[trigger_MyTable] on MyTable for insert as
begin
if 0 < (select count(*) from inserted where
Col1='a' and Col2='b' and Col3='c' and Col4=1 and Col6=1)
begin
raiserror 50009 'wrong insert, no way!'
rollback transaction
return
end
end;
-- now it fails
insert into MyTable (Col1, Col2, Col3, Col4, Col5, Col6)
values ('a', 'b', 'c', 1, 'e', '1');
Of course, you can create trigger for update (use "inserted" table), or for delete (use "deleted" table).
You might do other actions (like inserting another row in another table), ...
Give a MSDN try as well: http://msdn.microsoft.com/en-us/library/ms189799(v=SQL.90).aspx

Unless I misunderstood you requirements I think you want a unique constraint across all columns except col5.
Alter Table Foo
ADD CONSTRAINT ak_orf UNIQUE
(Col1, Col2 ,Col3 ,Col4 ,Col6),

Related

Insert different values everytime when using insert into

I have a table which has 3 columns and 6 records, I want to insert the values in another table which has an additional column of sysid, when I use insert into clause it inserts the records but the sysid value is same , I want different values everytime a record insert but I want to insert in bulk as well
Use a sequence:
CREATE SEQUENCE table_name__sysid__seq;
Then:
INSERT INTO table_name (sysid, col1, col2, col3, col4, col5, col6)
VALUES (table_name__sysid__seq.NEXTVAL, 'value1', 'value2', 'value3', 'value4', 'value5', 'value6');
or, for multiple rows:
INSERT INTO table_name (sysid, col1, col2, col3, col4, col5, col6)
SELECT table_name__sysid__seq.NEXTVAL, col1, col2, col3, col4, col5, col6
FROM first_table;
Or else, if you are using Oracle 12 or later, define sysid as an IDENTITY column:
CREATE TABLE table_name (
sysid NUMBER
GENERATED ALWAYS AS IDENTITY
PRIMARY KEY,
col1 VARCHAR2(20),
col2 VARCHAR2(20),
col3 VARCHAR2(20),
col4 VARCHAR2(20),
col5 VARCHAR2(20),
col6 VARCHAR2(20)
);
db<>fiddle here

How to do a select insert statement in sql with a changing value in the column for each row

Basically what I am trying to do in sql is find a way to do a select insert statement where all of the values in the other columns will stay the same but one of the columns value will increase by 1 for every row that is created. I am wondering if there is a way to do that in SQL.
You can use:
INSERT INTO table_name (col1, col2, col3)
SELECT col1, col2, col3 + 1
FROM table_name
Which, for the sample data:
CREATE TABLE table_name (col1, col2, col3) AS
SELECT LEVEL, LEVEL, LEVEL FROM DUAL CONNECT BY LEVEL <= 3;
Then, after the INSERT, the table contains:
COL1
COL2
COL3
1
1
1
2
2
2
3
3
3
1
1
2
2
2
3
3
3
4
And the col1 and col2 values of the inserted rows are the same and the col3 values have been incremented by 1.
If you want to increment the values by the number of rows being inserted then you can use:
INSERT INTO table_name (col1, col2, col3)
SELECT col1, col2, col3 + COUNT(*) OVER ()
FROM table_name
However
If you are attempting to add multiple rows and keep col3 with unique values then you should not use that method and should use a sequence.
If you have the table:
CREATE TABLE table_name (col1, col2, col3) AS
SELECT LEVEL, LEVEL, table_name__col3__seq.NEXTVAL FROM DUAL CONNECT BY LEVEL <= 3;
Then you can insert the rows using:
INSERT INTO table_name (col1, col2, col3)
SELECT col1, col2, table_name__col3__seq.NEXTVAL
FROM table_name
and col3 will be populated using the next sequence values.
db<>fiddle here

delete a row after comparing specific values with other rows in the same table

I have a table like this ( SQL SERVER )
col1 col2 col3 col4 col5
1 Goerge A B ++
2 Alex B B aa
2 Alex B B ++
now the second and the third rows have almost same values except in col5. in this case i want to delete one of them ( i want to be able to decide wich row from both of them i wanna delete ) like the one with value ++ so the table should look like this :
col1 col2 col3 col4 col5
1 Goerge A B ++
2 Alex B B aa
How can that be achieved?
Use CTE with ROW_NUMBER() to find (and delete) your duplicates
WITH CTE_Dup AS
(
SELECT *
, ROW_NUMBER OVER() PARTITION BY (Col1, Col2, Col3, Col4 ORDER BY Col5) RN
-- change ORDER BY criteria to make sure row you want to keep is 1st
FROM YourTable
)
DELETE --Try SELECT * to check before actually deleting
FROM CTE_Dup WHERE RN>1
It is not at all clear the logic you want here for determining which row is a "duplicate" but this example should show you a pretty straight forward way of handling this kind of thing.
declare #Something table
(
col1 int
, col2 varchar(10)
, col3 char(1)
, col4 char(1)
, col5 char(2)
)
insert #Something
values
(1, 'Goerge', 'A', 'B', '++')
, (2, 'Alex', 'B', 'B', 'aa')
, (2, 'Alex', 'B', 'B', '++')
;
with SortedValues as
(
select *
, ROW_NUMBER() over (partition by col1 order by col5 desc) as RowNum
from #Something
)
delete SortedValues
where RowNum > 1
select *
from #Something
You can try the below query. I grouped the columns and get the count of that and handled the conditions in the WHERE clause.
Query execution with the given sample data:
DECLARE #TestTable TABLE (col1 INT, col2 VARCHAR (20), col3 VARCHAR (20), col4 VARCHAR (20), col5 VARCHAR (20));
INSERT INTO #TestTable (col1, col2, col3, col4, col5) VALUES
(1, 'Goerge', 'A', 'B', '++'),
(2, 'Alex', 'B', 'B', 'aa'),
(2, 'Alex', 'B', 'B', '++');
SELECT * INTO #tmpResults FROM (
SELECT col1, col2, col3, col4, col5,
COUNT(*) OVER (PARTITION BY col1, col2, col3, col4 ORDER BY col1 ) AS CCnt
FROM #TestTable
) a
SELECT col1, col2, col3, col4, col5 FROM #tmpResults WHERE Ccnt = 1 AND Col5 = '++'
UNION
SELECT col1, col2, col3, col4, col5 FROM #tmpResults WHERE Ccnt > 1 AND Col5 <> '++';
DROP TABLE #tmpResults
Output:
col1 col2 col3 col4 col5
------------------------------------
1 Goerge A B ++
2 Alex B B aa

Sql insert select from – multiple rows with unique column id

I am trying to copy multiple records using one query using insert select from.
Insert into tab_A(colId, col1, col2, col3)
Select colId, col1, col2, col3 form tab_A
Where colId in ( 2,4,6)
Would it be possible to assign different colId for new entries? For example colid 2 should be replaced with 23, 4 with 24 and 6 with 25. How could I achieve it in a single query?
this would work
Insert into tab_A(colId, col1, col2, col3)
Select 23 , col1, col2, col3 form tab_A Where colId = 2 UNION ALL
Select 24 , col1, col2, col3 form tab_A Where colId = 4 UNION ALL
Select 25 , col1, col2, col3 form tab_A Where colId = 6
If you give some more info I could provide somthing more reusable. Should/is colId (be) an identity column?
EDIT
This would work in this very specialised case
Insert into tab_A(colId, col1, col2, col3)
Select ((colId - 4) * (-1)) + colId + 20 , col1, col2, col3
form tab_A Where colId IN (2, 4, 6)
The function newId = ((oldId - 4) * (-1)) + oldId + 20 is obviously specific to the stated problem.
EDIT2
I suspect somthing like this is more generic approach is appropriate.
DECLARE #MaxColID INT
BEGIN TRANSACTION
SELECT #MaxColID = MAX(ColID) FROM tab_A
INSERT tab_A(colId, col1, col2, col3)
SELECT row + #MaxColID, col1, col2, col3
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY ColID) row, col1, col2, col3
FROM tab_A WHERE colID IN (2, 4, 6)
)
COMMIT
EDIT 3
If you think EDIT 2 is actually what you want then you really want to make ColID an IDENTITY column, then you could do this.
INSERT tab_A (col1, col2, col3)
SELECT col1, col2, col3 FROM tab_A WHERE colId IN (2, 4, 6)
I dont see col4 or col6 in your query, but is this what you want:
Insert into tab_A(colId, col1, col2, col3)
Select colId, col1, 23, col3 form tab_A
Where colId in ( 2,4,6)
have you just tried adding the disired difference to colId -
In your case, since you need to replace 2 by 23, difference is 21.
Insert into tab_A(colId, col1, col2, col3)
Select colId+21, col1, col2, col3
form tab_A Where colId in ( 2,4,6)
Note: I missed the part, that the differnce is not consistent in your case.
The proposed solution will work only if difference is same
There are a few options:
Add the new ID column to the original table and populate it with the new values before you do this insert, selecting the new ID column instead of the old. This would be the tidiest solution I think.
Alternative - Modify the ID value on the insert based on a rule e.g.
INSERT INTO tab_A(colID, col1, col2, col3)
SELECT colId + 20, col1, col2, col3
FROM tab_A
WHERE colID IN(2,4,6)
Last resort - Process the insert sequentially with a cursor, modifying the ID value each time.
You could also write case in the select. when 2 then 23 or whatever value.

Merge with same target and source table

I have one table where I want to check if record exists leave it alone, if not insert new row and update previous row. I am wondering if I can use merge here like below ?
CREATE TABLE a
(keycol INT PRIMARY KEY,
col1 INT NOT NULL,
col2 INT NOT NULL,
col3 INT NOT NULL);
INSERT INTO a VALUES (1,0,0,0),(2,0,0,0);
MERGE INTO a
USING select 1 from a where col1 = 3
WHEN NOT MATCHED THEN
UPDATE SET
col2 = 2,
col2 = 2,
col3 = 2
where col1 = 3
WHEN NOT MATCHED THEN
INSERT (keycol, col1, col2, col3)
VALUES (4, 0, 0, 0)
Thanks,
MERGE INTO a
USING (
VALUES (3,3,2,2),
(4,0,0,0)
) AS source (keycol, col1, col2, col3)
ON a.keycol = source.keycol
AND a.col1 = source.col1
WHEN MATCHED THEN
UPDATE
SET col2 = source.col2,
col3 = source.col3
WHEN NOT MATCHED THEN
INSERT (keycol, col1, col2, col3)
VALUES (keycol, col1, col2, col3);