Trigger ON Table which fire INSERT into another table which has NOT NULL constraint - sql

CREATE TRIGGER logaction ON temployeelog
AFTER INSERT
AS
BEGIN
INSERT INTO TABLE temployee(ename, experience)
SELECT ename,experience FROM INSERTED
END
The structure of temployee
CREATE TABLE temployee
(
ename VARCHAR(20),
experience INT NOT NULL
)
ALTER TABLE temployeeADD DEFAULT (0) FOR experience
When I don't pass data in the experience column WHILE INSERT I get an error.
Cannot insert the value NULL into column 'experience', table
'temployee'; column does not allow nulls. INSERT fails. The statement
has been terminated.
I wanted to pass NULL Values temployeelog table AND wanted those situation to be handled by 'DEFAULT VALUES kept in temployee'
How can I achieve that?

The table default only comes into play if you don't insert it, so split the insert into one which handles a non-null experience and one which handles a null experience
INSERT INTO TABLE temployee (ename, experience)
SELECT ename, experience
FROM INSERTED
WHERE experience IS NOT NULL;
INSERT INTO TABLE temployee (ename)
SELECT ename
FROM INSERTED
WHERE experience IS NULL;

Related

Unable to create or query tables in online sql interpreter

I've been trying to simply create and display information from these tables on an interpreter that uses sql.js to run.
I've looked through assignment forums and tried to assign primary keys in varying formats based on what was provided on w3schools and also tried to explicitly create a database to put the tables into. no changes.
DROP TABLE IF EXISTS employees;
CREATE TABLE pledges( donorId integer , donor text,
pledge integer, AmountPaid integer,
);
INSERT INTO pledges VALUES (1,'JOHNSON',6,30);
INSERT INTO pledges VALUES (2,'ROGERS',5,100);
INSERT INTO pledges VALUES (1,'RODDUCK',10,50);
INSERT INTO pledges VALUES (1,'PETERS',2,20);
INSERT INTO pledges VALUES (1,'ALBERTSON',7,56);
SELECT * FROM pledges;
The expectation is just for me to create the simple tables and test the queries but it just keeps saying "fetching results"
Your online tool probably swallows the error due to the incorrect CREATE TABLE statement. You have a dangling , after the amountpaid integer definition:
Once that error is fixed (and the pledges table is dropped instead of the employees table), your script runs fine:
DROP TABLE IF EXISTS pledges;
CREATE TABLE pledges
(
donorId integer,
donor text,
pledge integer,
amountpaid integer --<< you had a comma here
);
INSERT INTO pledges VALUES (1,'JOHNSON',6,30);
INSERT INTO pledges VALUES (2,'ROGERS',5,100);
INSERT INTO pledges VALUES (1,'RODDUCK',10,50);
INSERT INTO pledges VALUES (1,'PETERS',2,20);
INSERT INTO pledges VALUES (1,'ALBERTSON',7,56);
SELECT *
FROM pledges;
https://rextester.com/BJJGC94351

use INSERT inside definition of VIEW: CREATE VIEW AS INSERT INTO

If I want to do something relatively complicated - something usually done by a stored procedure. Is it possible to make it automatic using a VIEW?
My specific case:
I want output table = input table A + some rows input table B. In a stored procedure, I can make a copy of table A and then INSERT INTO it, but it's not allowed in a view.
Simplified example:
input table is [test_album], and output table = input table + singer Prince.
--create test data
IF OBJECT_ID('[dbo].[test_album]', 'U') IS NOT NULL
DROP TABLE [dbo].[test_album]
CREATE TABLE [test_album] (
id int not null identity(1, 1) primary key,
singer VARCHAR(50) NULL,
album_title VARCHAR(100) NULL
)
INSERT INTO [test_album] (singer, album_title)
VALUES ('Adale', '19'),
('Michael Jaskson', 'Thriller')
--this can be executed as sql code or in stored proc
SELECT *
INTO [result_table]
FROM [test_album]
INSERT INTO [result_table] ([singer])
VALUES ('Prince')
select *
from [result_table]
--id singer album_title
--1 Adale 19
--2 Michael Jaskson Thriller
--3 Prince NULL
----as expected
But I can do this INSERT INTO inside a view.
Real-life case:
additional singers are in a table [extra_singers]
[test_album] may have many other columns (or schema may change) so it's ideal not to type all column names in the code.
--create test data
IF OBJECT_ID('[dbo].[test_album]', 'U') IS NOT NULL
DROP TABLE [dbo].[test_album]
IF OBJECT_ID('[dbo].[extra_singers]', 'U') IS NOT NULL
DROP TABLE [dbo].[extra_singers]
IF OBJECT_ID('[dbo].[result_table]', 'U') IS NOT NULL
DROP TABLE [dbo].[result_table]
CREATE TABLE [test_album] (
id int not null identity(1, 1) primary key,
singer VARCHAR(50) NULL,
album_title VARCHAR(100) NULL,
many_other_columns VARCHAR(100) NULL
)
INSERT INTO [test_album] (singer, album_title)
VALUES ('Adale', '19'),
('Michael Jaskson', 'Thriller')
CREATE TABLE [extra_singers] (
[id] int not null identity(1, 1) primary key,
[name] VARCHAR(50) NULL )
INSERT INTO [extra_singers] ([name])
VALUES ('Prince'),
('Taylor Swift')
--append [extra_singers] to [test_album]
--this can be executed as sql code or in stored proc
SELECT *
INTO [result_table]
FROM [test_album]
INSERT INTO [result_table] ([singer])
SELECT [name]
FROM [extra_singers]
Is there an alternative to this (that is automatic)?
any help's appreciated. Thank u-
a partial solution I can think of:
create view test_view as
select *
from [test_album]
union all
select 3 as id,
'Prince' as singer,
NULL as album_title
but you have to know all the column names in [test_album] and you can't let column [id] do auto-increment
So you may be misunderstanding what a view does, or what an insert is. A view is simply a wrapper around a single select query. It contains exactly one select statement, and nothing else. An insert permanently adds a row of data to a persisted table. The example you gave where you just union the row you want seems valid enough. And certainly if it's the same row you want every time, you would not want to be inserting (or even trying to insert) that row into the underlying table each time
This raises a couple questions though.
If you're always going to be unioning the same single row every time, why not jut add that row to the table?
If, lets say, you don't want that row in the underlying table, cool. But if it's always the same static values, why do you need to include it in the view? Can't it just be assumed it's there?
If it can't be assume to always be the same, you certainly don't want to be changing the VIEW body every time you need it to change. So if it is going to change and you don't want to insert it into the base table, maybe make a second table containing the values you want appended to the base table in the view. Then union the base table and the "extra values" table together instead of a single, hard coded row constructor.

Primary Key Error while inserting record into table

I am passing datatable as input parameter to a stored procedure. I have created custom type for it.
Here is my stored procedure:
CREATE PROCEDURE [dbo].[Proc_AddEmployee]
#tblEmp EmpType READONLY,
#Code int
AS
BEGIN
INSERT INTO Employee ([Name], [Lname], [Code])
SELECT
[Name], [Lname], #Code
FROM #tblEmp
Here it fetch record from datatable and insert into Employee table.
Table Employee has primary key (combination Name and Lname).
Table Employee:
Nmae LName Code
Rashmi Hirve 89
Rani Mohite 7
DataTable :
Nmae LName
Rani Mohite
Swati More
Reshma Gawade
Problem appears when I try to add record (Rani, Mohite) from datatable to table Employee.
It causes a primary key error at first record and does not proceed further.
I want like this if error come skip that record fetch next record and insert that. There are 8000 records, which I want to pass from datatable to Employee table.
If I checked not exist, then insert will take long time to execute query.How to handle that?
Adding a check for EXISTS on the INSERT statement should not have a significant effect on performance.
INSERT INTO Employee ([Name] ,[Lname] ,[Code])
SELECT [Name] ,[Lname] ,#Code
FROM #tblEmp AS t
WHERE NOT EXISTS
( SELECT 1
FROM Employee AS e
WHERE e.Name = t.Name
AND e.Lname = t.Lname
);
This is fairly safe, but still vulnerable to a race condition. I think the safest way to do the insert, with is to use MERGE with the locking hint HOLDLOCK:
MERGE Employee WITH(HOLDLOCK) AS t
USING #tbl AS s
ON s.Name = t.Name
AND s.LName = t.LName
WHEN NOT MATCHED THEN
INSERT ([Name] ,[Lname] ,[Code])
VALUES (s.Name, s.Lname, #Code);
If the table has a primary key that is not set to auto generate then it will error when you try to insert a record without the key. You will need to either set the primary key field as an identity seed or you can include the primary key with the insert.

In Oracle, How to handle NULL values when inserted to a Table

I have one table, which has a filed. When I insert in that table with the Empty value like '' or null, it should get converted to 'DUMMY-VALUE'.
--Have one table;
CREATE TABLE TEST ( FIELD1 VARCHAR2(50) );
--When I insert ''
INSERT INTO TEST(FIELD1) VALUES('');
SELECT * FROM TEST
--Expected Result 'DUMMY-VALUE' but not NULL
I can apply NVL('','DUMMY-VALUE') in INSERT statement but I am allowed to change CREATE statement only.
For Now, I am handing this with TRIGGER but , wondering if there is any alternative in 11g however I know about DEFAULT ON NULL for oracle 12c.
You can do like this:
create table TEST (FIELD1 VARCHAR2(50) default 'DUMMY-VALUE' );
and when you want to insert
you should insert without that field if the values is NULL or empty
Try this:
CREATE TABLE TEST (FIELD1 VARCHAR2(50) DEFAULT 'DUMMY-VALUE');
then use the DEFAULT keyword in the INSERT statement:
INSERT INTO TEST (FIELD1) VALUES (DEFAULT);
SQLFiddle here
Share and enjoy.

How to add data to two tables linked via a foreign key?

If I were to have 2 tables, call them TableA and TableB. TableB contains a foreign key which refers to TableA. I now need to add data to both TableA and TableB for a given scenario. To do this I first have to insert data in TableA then find and retrieve TableA's last inserted primary key and use it as the foreign key value in TableB. I then insert values in TableB. This seems lika a bit to much of work just to insert 1 set of data. How else can I achieve this? If possible please provide me with SQL statements for SQL Server 2005.
That sounds about right. Note that you can use SCOPE_IDENTITY() on a per-row basis, or you can do set-based operations if you use the INSERT/OUTPUT syntax, and then join the the set of output from the first insert - for example, here we only have 1 INSERT (each) into the "real" tables:
/*DROP TABLE STAGE_A
DROP TABLE STAGE_B
DROP TABLE B
DROP TABLE A*/
SET NOCOUNT ON
CREATE TABLE STAGE_A (
CustomerKey varchar(10),
Name varchar(100))
CREATE TABLE STAGE_B (
CustomerKey varchar(10),
OrderNumber varchar(100))
CREATE TABLE A (
Id int NOT NULL IDENTITY(51,1) PRIMARY KEY,
CustomerKey varchar(10),
Name varchar(100))
CREATE TABLE B (
Id int NOT NULL IDENTITY(1123,1) PRIMARY KEY,
CustomerId int,
OrderNumber varchar(100))
ALTER TABLE B ADD FOREIGN KEY (CustomerId) REFERENCES A(Id);
INSERT STAGE_A VALUES ('foo', 'Foo Corp')
INSERT STAGE_A VALUES ('bar', 'Bar Industries')
INSERT STAGE_B VALUES ('foo', '12345')
INSERT STAGE_B VALUES ('foo', '23456')
INSERT STAGE_B VALUES ('bar', '34567')
DECLARE #CustMap TABLE (CustomerKey varchar(10), Id int NOT NULL)
INSERT A (CustomerKey, Name)
OUTPUT INSERTED.CustomerKey,INSERTED.Id INTO #CustMap
SELECT CustomerKey, Name
FROM STAGE_A
INSERT B (CustomerId, OrderNumber)
SELECT map.Id, b.OrderNumber
FROM STAGE_B b
INNER JOIN #CustMap map ON map.CustomerKey = b.CustomerKey
SELECT * FROM A
SELECT * FROM B
If you work directly with SQL you have the right solution.
In case you're performing the insert from code, you may have higher level structures that help you achieve this (LINQ, Django Models, etc).
If you are going to do this in direct SQL, I suggest creating a stored procedure that takes all of the data as parameters, then performs the insert/select identity/insert steps inside a transaction. Even though the process is still the same as your manual inserts, using the stored procedure will allow you to more easily use it from your code. As #Rax mentions, you may also be able to use an ORM to get similar functionality.