I have two tables
threads table
_id recipient_id type
1 1
2 1
3 2
and addresses table
_id address
1 HELLO
2 BYE
recipient_id is mapped to addresses table's _id
I need to update type to a specific value if address is HELLO. How do i do it? I have already tried
UPDATE threads SET threads.type = 106 FROM threads
INNER JOIN
addresses ON addresses._id = threads.recipient_ids
AND
addresses.address LIKE '%HELLO%';
But i am getting an error near ".": syntax error .
What is the correct syntax to update a column?
You can use the IN operator:
sqlite> .dump
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE threads (_id integer primary key, recipient_id integer, type text);
INSERT INTO "threads" VALUES(1,1,NULL);
INSERT INTO "threads" VALUES(2,1,NULL);
INSERT INTO "threads" VALUES(3,2,NULL);
CREATE TABLE addresses (_id integer primary key, address text);
INSERT INTO "addresses" VALUES(1,'HELLO');
INSERT INTO "addresses" VALUES(2,'BYE');
COMMIT;
sqlite> update threads set type = 106 where _id in
...> (select t._id from threads t, addresses a
...> where t.recipient_id = a._id and a.address like '%HELLO%');
sqlite> .dump
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE threads (_id integer primary key, recipient_id integer, type text);
INSERT INTO "threads" VALUES(1,1,'106');
INSERT INTO "threads" VALUES(2,1,'106');
INSERT INTO "threads" VALUES(3,2,NULL);
CREATE TABLE addresses (_id integer primary key, address text);
INSERT INTO "addresses" VALUES(1,'HELLO');
INSERT INTO "addresses" VALUES(2,'BYE');
COMMIT;
Related
create table Hotel
(
hotel_id integer primary key NOT NULL,
hotel_name varchar(50) NOT NULL UNIQUE,
location_ varchar(50) NOT NULL,
rates varchar(10) check(rates in ('5star','4star','3star','2star','1star')),
);
create table Room
(
room_no integer primary key NOT NULL,
total_rooms integer NOT NULL,
room_price real check (room_price >= 0),
hotel_id integer foreign key references Hotel
);
insert into Hotel values(1,'sevensay','gamapaha','4star')
insert into Hotel values(2,'sarasvi','gamapaha','3star')
insert into Hotel values(3,'galadari','colombo','5star')
insert into Hotel values(4,'kingsbary','colombo','4star')
insert into Hotel values(5,'niramliii','gamapaha','5star')
insert into Hotel values(6,'sadalnka','kandy','3star')
insert into Hotel values(7,'sri lnkani','kandy','5star')
insert into Room values(100,10000,1)
insert into Room values(220,20000,2)
insert into Room values(160,1000,3)
insert into Room values(100,12000,4)
insert into Room values(50,15000,5)
insert into Room values(80,10000,6)
insert into Room values(100,20000,7)
drop table Room
drop table Hotel
select * from Hotel
select * from Room
create trigger rooms_availability
on Room
for insert
as
begin
declare #hotel_id integer
declare #total_rooms integer
select #hotel_id = hotel_id from inserted
select #total_rooms = count(*) from Room where hotel_id = #hotel_id
rollback transaction
if #total_rooms > 80
begin
print 'we have only 80 rooms .we cannot book the other rooms'
end
end
insert into Room values(300,10000,6)
How can I handle this error?
Msg 2627, Level 14, State 1, Line 25
Violation of PRIMARY KEY constraint 'PK__Room__1967F4191F8BEC00'. Cannot insert duplicate key in object 'dbo.Room'. The duplicate key value is (506).
The statement has been terminated.
The error you are showing is caused from trying to insert a row into Room with a duplicate primary key. However the code you provide doesn't have that error. And if you use an identity column (recommended for primary keys) you will never have that issue.
The more important issue is in your trigger, where you are not handling that fact that Inserted can have multiple rows. You can handle this correctly using a set based approach:
create trigger rooms_availability
on Room
for insert
as
begin
if exists (
select 1
from Room
where hotel_id in (select hotel_id from Inserted)
group by hotel_id
having count(*) > 80
)
begin
print 'We have only 80 rooms. We cannot book the other rooms.'
rollback;
end;
end
Note: I assume Print is being used for debugging. Once its working you will want to use throw.
I'm using database first approach with EF core and trying to figure out a clean solution to the below problem -
Consider a Student attendance table (irrelevant columns removed) below that stores date of class and allows the student to enter his class rating -
create table Student (
Id int Identity(1, 1) not null,
ClassDate smalldatetime not null,
ClassRatingByStudent varchar(250) not null
)
This is a webapp where school attendance system automatically populates the above table at EOD and then the student (let's say a few days later) is required to add class ratings. When the table is populated by the school attendance system, there is nothing in the ClassRatingByStudent column. Then when the student logs in, he must add the rating.
As you see, ClassRatingByStudent must be null when the school attendance system populates the table and must be not-null when the student saves his changes. One obvious solution is make ClassRatingByStudent column nullable ad handle it in the code but I'm wondering if there is a neater database (or maybe EF) level solution exists or some sort of pattern/architecture guidelines for this type of scenarios?
I don't know but maybe CHECK constraint could help you:
CREATE TABLE TestTable(
ID int NOT NULL IDENTITY,
RatingAllowed bit NOT NULL DEFAULT 0, -- switcher
RatingValue varchar(250),
CONSTRAINT PK_TestTable PRIMARY KEY(ID),
CONSTRAINT CK_TestTable_RatingValue CHECK( -- constraint
CASE
WHEN RatingAllowed=0 AND RatingValue IS NULL THEN 1
WHEN RatingAllowed=1 AND RatingValue IS NOT NULL THEN 1
ELSE 0
END=1
)
)
INSERT TestTable(RatingAllowed,RatingValue)VALUES(0,NULL)
INSERT TestTable(RatingAllowed,RatingValue)VALUES(1,'AAA')
-- The INSERT statement conflicted with the CHECK constraint "CK_TestTable_RatingValue"
INSERT TestTable(RatingAllowed,RatingValue)VALUES(0,'AAA')
INSERT TestTable(RatingAllowed,RatingValue)VALUES(1,NULL)
I found a variant how to check using another table as switcher
CREATE TABLE TableA(
ID int NOT NULL IDENTITY PRIMARY KEY,
StudentID int NOT NULL,
Grade int
)
CREATE TABLE TableB(
StudentID int NOT NULL PRIMARY KEY
)
GO
-- auxiliary function
CREATE FUNCTION GradeIsAllowed(#StudentID int)
RETURNS bit
BEGIN
DECLARE #Result bit=CASE WHEN EXISTS(SELECT * FROM TableB WHERE StudentID=#StudentID) THEN 1 ELSE 0 END
RETURN #Result
END
GO
-- constraint to check
ALTER TABLE TableA ADD CONSTRAINT CK_TableA_Grade CHECK(
CASE dbo.GradeIsAllowed(StudentID) -- then we can use the function here
WHEN 1 THEN CASE WHEN Grade IS NOT NULL THEN 1 ELSE 0 END
WHEN 0 THEN CASE WHEN Grade IS NULL THEN 1 ELSE 0 END
END=1)
GO
-- Tests
INSERT TableB(StudentID)VALUES(2) -- allowed student
INSERT TableA(StudentID,Grade)VALUES(1,NULL) -- OK
INSERT TableA(StudentID,Grade)VALUES(2,5) -- OK
INSERT TableA(StudentID,Grade)VALUES(1,4) -- Error
INSERT TableA(StudentID,Grade)VALUES(2,NULL) -- Error
INSERT TableB(StudentID)VALUES(1) -- add 1
UPDATE TableA SET Grade=4 WHERE StudentID=1 -- OK
UPDATE TableA SET Grade=NULL WHERE StudentID=1 -- Error
Suppose B and C are both subclass and A is a superclass. B and C can not have same id (disjoint)
CREATE TABLE a(id integer primary key);
CREATE TABLE b(id integer references a(id));
CREATE TABLE c(id integer references a(id));
insert into a values('1');
insert into a values('2');
insert into b values('1');
insert into c values('2');
Could I use a trigger to prevent the same id appearing in tables B and C?
"b and c can not have same id"
So you want to enforce a mutually exclusive relationship. In data modelling this is called an arc. Find out more.
We can implement an arc between tables without triggers by using a type column to distinguish the sub-types like this:
create table a (
id integer primary key
, type varchar2(3) not null check (type in ( 'B', 'C'))
, constraint a_uk unique (id, type)
);
create table b (
id integer
, type varchar2(3) not null check (type = 'B')
, constraint b_a_fk foreign key (id, type) references a (id, type)
);
create table b (
id integer
, type varchar2(3) not null check (type = 'C')
, constraint c_a_fk foreign key (id, type) references a (id, type)
);
The super-type table has a unique key in addition to its primary key; this provides a reference point for foreign keys on the sub-type tables. We still keep the primary key to insure uniqueness of id.
The sub-type tables have a redundant instance of the type column, redundant because it contains a fixed value. But this is necessary to reference the two columns of the compound unique key (and not the primary key, as is more usual).
This combination of keys ensures that if the super-type table has a record id=1, type='B' there can be no record in sub-type table C where id=1.
Design wise this is not good but we can do it using the below snippet. You can create a similar trigger on table b
CREATE TABLE a(id integer primary key);
CREATE TABLE b(id integer references a(id));
CREATE TABLE c(id integer references a(id));
create or replace trigger table_c_trigger before insert on c for each row
declare
counter number:=0;
begin
select count(*) into counter from b where id=:new.id;
if counter<>0 then
raise_application_error(-20001, 'values cant overlap between c and b');
end if;
end;
insert into a values('1');
insert into a values('2');
insert into b values('1');
insert into b values('2');
insert into c values('2');
You can use Oracle Sequence:
CREATE SEQUENCE multi_table_seq;
INSERT INTO A VALUE(1);
INSERT INTO A VALUE(2);
INSERT INTO B VALUE(multi_table_seq.NEXTVAL()); -- Will insert 1 in table B
INSERT INTO C VALUE(multi_table_seq.NEXTVAL()); -- Will insert 2 in table C
...
With trigger:
-- Table B
CREATE TRIGGER TRG_BEFORE_INSERT_B -- Trigger name
BEFORE INSERT -- When trigger is fire
ON A -- Table name
DECLARE
v_id NUMBER;
BEGIN
v_id := multi_table_seq.NEXTVAL();
BEGIN
SELECT TRUE FROM C WHERE id = v_id;
RAISE_APPLICATION_ERROR(-20010, v_id || ' already exists in table C');
EXCEPTION WHEN NO_DATA_FOUND -- Do nothing if not found
END;
END;
And same trigger for table C who check if id exists in table B
I want to execute following sql code.
--1
CREATE TABLE User_Type(
User_Type_ID Integer NOT NULL PRIMARY KEY,
User_Type_Name Char(20 ) NOT NULL
);
CREATE SEQUENCE User_Type_seq;
CREATE TRIGGER User_Type_ID_trg
BEFORE INSERT ON User_Type
FOR EACH ROW
BEGIN
SELECT User_Type_seq.NEXTVAL INTO :new.User_Type_ID
FROM DUAL;
END;
/
When I write it by hand to sql developer, it works. But I need a lot of block like this. So, I've edited those with notepad++ and copy/paste to sql developer again. This time; tables and sequences were created but it gives an error about trigger code (I've taken this routine with select from user_errors)
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: ERROR 103
;
Here is the full code which doesn't work. create table and sequences codes works, but the trigger code doesn't.
--1
CREATE TABLE User_Type(
User_Type_ID Integer NOT NULL PRIMARY KEY,
User_Type_Name Char(20 ) NOT NULL
);
CREATE SEQUENCE User_Type_seq;
CREATE TRIGGER User_Type_ID_trg
BEFORE INSERT ON User_Type
FOR EACH ROW
BEGIN
SELECT User_Type_seq.NEXTVAL INTO :new.User_Type_ID
FROM DUAL;
END;
/
--2
CREATE TABLE Users(
User_ID Integer NOT NULL PRIMARY KEY,
User_Password Char(8 ) NOT NULL,
User_Name Char(20 ) NOT NULL,
User_Type_ID Integer NOT NULL
);
CREATE SEQUENCE Users_seq;
CREATE TRIGGER User_ID_trg
BEFORE INSERT ON Users
FOR EACH ROW
BEGIN
SELECT Users_seq.NEXTVAL INTO :new.User_ID
FROM DUAL;
END;
/
--3
CREATE TABLE Admin(
Admin_ID Integer NOT NULL PRIMARY KEY,
E_mail Char(20 ) NOT NULL,
Phone_Number Char(20 ) NOT NULL,
User_ID Integer NOT NULL
);
CREATE SEQUENCE Admin_seq;
CREATE TRIGGER Admin_ID_trg
BEFORE INSERT ON Admin
FOR EACH ROW
BEGIN
SELECT Admin_seq.NEXTVAL INTO :new.Admin_ID
FROM DUAL;
END;
/
--4
CREATE TABLE City(
City_ID Integer NOT NULL PRIMARY KEY,
City_Name Char(20 ) NOT NULL
);
CREATE SEQUENCE City_seq;
CREATE TRIGGER City_ID_trg
BEFORE INSERT ON City
FOR EACH ROW
BEGIN
SELECT City_seq.NEXTVAL INTO :new.City_ID
FROM DUAL;
/
I've searched similar questions but no response to solve my problem.
Sorry for English, thank you...
You're just missing an END; in your final trigger:
CREATE TRIGGER City_ID_trg
BEFORE INSERT ON City
FOR EACH ROW
BEGIN
SELECT City_seq.NEXTVAL INTO :new.City_ID
FROM DUAL;
END;
/
Everything else is already created and compiled successfully.
Incidentally, from 11g you can assign a sequence directly in PL/SQL, withouth having to select from dual:
...
BEGIN
:new.City_ID := City_seq.NEXTVAL;
END;
/
It was solved. Unfortunately, a letter mistake I have not understood yet why, but:
it must be
create trigger
instead of
CREATE TRIGGER
I have the following stored procedure, I have two tables here, Movie and Director. Both need to be updated when a new movie has been created or added. How do you handle FKs in stored procedures? The FK in this case is director_id. It is a primary key in Director but a FK in Movie Do I need to specify it twice like so? I am getting conflict errors
CREATE PROCEDURE Book_Book_Creation
#Book_id_arg DECIMAL(12),
#author_id_arg DECIMAL(12),
#type_id_arg DECIMAL(12),
#title_arg VARCHAR(64), -
#copyright_arg DECIMAL(4),
#dauthor_id_2_arg DECIMAL(12),
#author_fname_arg VARCHAR (64),
#author_lname_arg VARCHAR (64)
AS
BEGIN
INSERT INTO Book(Book_id, author_id,genre_id, title, copyright)
VALUES (#author_arg, #author_id_arg, #type_id_arg, #title_arg, #copyright_arg);
INSERT INTO Author(author_id, author_fname, author_lname)
VALUES (#director_id_2_arg, #director_fname_arg, #director_lname_arg)
END;
EXECUTE Book_Book_Creation 32,32,1,'Tempting',2013,32,'Taylor','Mendez';
Basically, you just need to do this:
insert into the Director table first
get the newly inserted ID from that table (assuming that the Director_Id column is your primary key and is of type INT IDENTITY)
then insert into the Movie table with that new ID
Something like this:
DECLARE #NewDirectorID INT
INSERT INTO Director (Director_id, Director_fname, director_lname)
VALUES (#director_id_2_arg, #director_fname_arg, #director_lname_arg)
SELECT #NewDirectorID = SCOPE_IDENTITY()
INSERT INTO Movie (Movie_id, director_id,genre_id, title, copyright)
VALUES (#movie_id_arg, #NewDirectorID, #genre_id_arg, #title_arg, #copyright_arg);
I don't see why you would pass in the director's ID as a parameter - twice!
Try this one -
ALTER PROCEDURE dbo.Movie_Movie_Creation12
#movie_id_arg DECIMAL(12),
#director_id_arg DECIMAL(12),
#genre_id_arg DECIMAL(12),
#title_arg VARCHAR(64),
#copyright_arg DECIMAL(4),
#director_fname_arg VARCHAR (64),
#director_lname_arg VARCHAR (64)
AS BEGIN
INSERT INTO dbo.Director (Director_id, Director_fname, director_lname)
SELECT #director_id_arg, #director_fname_arg, #director_lname_arg
INSERT INTO dbo.Movie (Movie_id, director_id,genre_id, title, copyright)
SELECT #movie_id_arg, #director_id_arg, #genre_id_arg, #title_arg, #copyright_arg
END
EXECUTE dbo.Movie_Movie_Creation12
#movie_id_arg = 32
, #director_id_arg = 32
, #genre_id_arg = 1
, #title_arg = 'Argo'
, #copyright_arg = 2012
, #director_fname_arg = 'Ben'
, #director_lname_arg = 'Affleck'