MySQL if exists update else create new - mysql

I have a vet table and a medical table with a 1 to many relationship, and the ID's are auto incremented.
CREATE TABLE vet(
vetID INT NOT NULL AUTO_INCREMENT,
vetPractice varchar(35),
Address varchar(150),
contactNumber varchar (15),
PRIMARY KEY (VetID)
);
CREATE TABLE medical(
medicalID INT NOT NULL AUTO_INCREMENT,
medication VARCHAR (200),
PRIMARY KEY (medicalID),
FOREIGN KEY (vetID) REFERENCES vet(vetID)
);
Users can enter details of a vet, i want a query to determine;
if the the vet details entered already exist, then update the foreign key in vetID(medical) with the entered vetID.
else if the vet does not exist create a new vet and update the foreign key in vetID(medical) with the newly created vetID.

You want to do an upsert in MySql. I think that this link can be helpful.
Example:
INSERT INTO table (x,x,x) VALUES (x,x,x)
ON DUPLICATE KEY UPDATE x=x+x;

You have to do a "select" query to determine whether exists .
Select medicalID from medical where medication=?
This should be executed in a different query as the update , you need to use server language to see if the results brings back a result.Then using an "if" statement determine your routine.
hope this helps.

Related

How we can use the primary key in another table

I have Two table
customer table which has contained the information of the customer. But it has an account number we make a primary key of the account number.
And now the second Table is Bill Table.I've use the account number of the customer table when we update some information about the Bill table then will update is automatically of the particular account number
so, please tell me how we can resolve this problem, and how we can use
the foreign key of Bill table
I think what you are asking is how to update the Customer table at the same time when you are updating Bill table.
You can easily use a stored procedure to achieve this task. Within the stored procedure you can use transactions to make sure the 2nd update happens only if the first update is succeded. Otherwise, you can rollback.
So imagine that this is your customer table:
CREATE TABLE customer (
AccountNum int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
PRIMARY KEY (AccountNum)
);
PRIMARY KEY (AccountNum) > so you have a primary key in that table. Kudos!
CREATE TABLE BillTable (
OrderID int NOT NULL,
OrderNumber int NOT NULL,
AccountNum int NOT NULL,
PRIMARY KEY (OrderID),
FOREIGN KEY (AccountNum) REFERENCES customer(AccountNum)
);
Now you linked customer and BillTable.

What is the correct way of have foreign keys in tables that reference each other

The tables will build, but every time I try to insert values into the table I get a 1452 error of foreign key constraints fails. I wonder if the problem has to do with EMPLOYEE table has a foreign key for STORE_CODE in the STORE table, and STORE table has a foreign key for EMP_CODE in EMPLOYEE table. Is the circular reference the problem here?
ALTER TABLE EMPLOYEE DROP FOREIGN KEY STORE_CD;
ALTER TABLE STORE DROP FOREIGN KEY REGION_CD;
ALTER TABLE STORE DROP FOREIGN KEY EMPLOYEE_CD;
DROP TABLE IF EXISTS EMPLOYEE, REGION, STORE;
CREATE TABLE EMPLOYEE (
EMP_CODE int NOT NULL PRIMARY KEY,
EMP_TITLE varchar(4),
EMP_LNAME varchar(15),
EMP_FNAME varchar(15),
EMP_INITIAL varchar(1),
EMP_DOB datetime,
STORE_CODE int NOT NULL
) Engine=InnoDB;
-- Table Region
CREATE TABLE REGION (
REGION_CODE int NOT NULL PRIMARY KEY,
REGION_DESCRIPT varchar(20)
) Engine=InnoDB;
-- Table Store
CREATE TABLE STORE (
STORE_CODE int NOT NULL PRIMARY KEY,
STORE_NAME varchar(20) NOT NULL,
STORE_YTD_SALES numeric NOT NULL,
REGION_CODE int NOT NULL,
EMP_CODE int NOT NULL
) Engine=InnoDB;
ALTER TABLE EMPLOYEE ADD CONSTRAINT STORE_CD
FOREIGN KEY STORE_CD(STORE_CODE) REFERENCES STORE(STORE_CODE);
ALTER TABLE STORE ADD CONSTRAINT REGION_CD
FOREIGN KEY REGION_CD(REGION_CODE) REFERENCES REGION(REGION_CODE);
ALTER TABLE STORE ADD CONSTRAINT EMPLOYEE_CD
FOREIGN KEY EMPLOYEE_CD(EMP_CODE) REFERENCES EMPLOYEE(EMP_CODE);
It's not possible to have mutual foreign keys unless you allow at least one of the columns to be NULL. Otherwise you can never have a consistent set of tables: If you add the store first, it will refer to a nonexistent employee; if you add the employee first, it will refer to a nonexistent store.
So you need to allow the referencing column to be NULL. Then you can add a row to the first table with NULL in the referencing column, add a row to the second table, then fill in the referencing column in the first table with the ID from the second table.
In my experience with relational databases, I think you should create an
intermediate table to conect "store" with "employee" (lets name it (store_has_employee) with the atributes(idstore(fk), idemployee(fk) and isManager(boolean)).
Then you should insert the "regions" first, so you can insert a "store", then when you have registered "employees", all you have to do is conect them in "store_has_employee", and if you want to say that is the manager, just insert isManager=true.
This is the most eficient way to do it and to get faster queries.
Hope it helps.
Which one you Want to insert first? If EMPLOYEE then Make STORE_CD (nullable=true) in EMPLOYEE After that Insert STORE item with EMPLOYEE id and Update EMPLOYEE with store code.You can use Transaction for this whole process.
Due to my lack of understanding SQL, the simplest solution for me has been to remove the foreign key from the employee table so that I don't have a circular reference. Then populate the employee table first the other tables afterwards.

Mysql trigger on Delete to multiple tables (also error 1235)

I have 3 tables that are called:
character_
learned_skills
skills
"character_" contains certain informations on a list of characters, while the table "skills" contrains a list of skills.
the 3rd table is the list of the skills each character has learned.
However I want to able ones a character has been deleted from the character_ table, it also deletes the name of that character and the skills it has learned from the table "learned_skills".
I assume that a trigger is required in this situation. I know that the syntax is:
CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR REACH ROW tigger_statement;
However I can't figure out how the trigger_statement should look like.
CREATE TRIGGER delete_char_ AFTER DELETE ON character_ FOR REACH ROW trigger_statement
Is it enough with a sigle statement or does it require several statements and or cascade?
What would you do in this situation?
CREATE TABLE character_ (
Name_ varchar (30) NOT NULL,
Class varchar (30),
World_Type varchar (15),
Str integer ,
WS integer ,
BS integer ,
Fel integer ,
Per integer ,
Int_ integer ,
Agi integer ,
WP integer ,
Tough integer ,
PRIMARY KEY (Name_) ,
FOREIGN KEY (Class) REFERENCES Class(Class_name),
FOREIGN KEY (World_Type) REFERENCES World_Type(Name_) );
CREATE TABLE Skills (
SkillName varchar (30) NOT NULL,
Type_ varchar (30),
Characteristic varchar (30),
Descriptor varchar (30),
PRIMARY KEY (SkillName) );
CREATE TABLE Learned_Skills (
Character_Name varchar (30) NOT NULL,
Skill_Name varchar (40) NOT NULL,
PRIMARY KEY (Character_Name,Skill_Name),
FOREIGN KEY (Character_Name) REFERENCES character_(Name_),
FOREIGN KEY (Skill_Name) REFERENCES Talents(TalentName) );
UPDATE:
So I have had help to understand and make a DELETE trigger, but I have found out that need to create a multiple trigger on two tables, I know that its not possible to create a trigger on two with the same triggertime and event, but is there a way around it? What I need is the following:
DELIMITER //
CREATE TRIGGER delete_char_ AFTER DELETE ON character_
FOR EACH ROW begin
DELETE FROM learned_skills
WHERE learned_skills.Character_Name = old.Name_;
DELETE FROM learned_talents
WHERE learned_talents.Character_Name = old.Name_;
END;
//
DELIMITER ;
When I run this code I get error code:
1235, this version of mysql doesn't yet support 'multiple triggers with the samme action time and event for one table
Here is what it would look like:
CREATE TRIGGER delete_char_ AFTER DELETE ON character_
FOR EACH ROW
DELETE FROM learned_skills
WHERE learned_skills.Character_Name = old.Name_;
You will need to replace <field> with whatever the primary key is of the character_. This will delete anything from the learned_skills table that has the <field> of the character_ being deleted.

One field with two references in MySQL

I have three tables:
CREATE TABLE Address (
ResidentID CHAR(5) NOT NULL,
Location varchar(255) NOT NULL,
KEY ResidentID(ResidentID)
);
CREATE TABLE Customer (
CustomerID CHAR(5) NOT NULL,
ContactName varchar(40) NOT NULL,
PRIMARY KEY (CustomerID)
);
CREATE TABLE Supplier (
SupplierID CHAR(5) NOT NULL,
SupplierName varchar(40) NOT NULL,
PRIMARY KEY (SupplierID)
);
I want to store CustomerID and SupplierID in the Address.ResidentID field with using of foreign keys:
ALTER TABLE Address ADD CONSTRAINT fk_CustomerID1 FOREIGN KEY(ResidentID) REFERENCES Customer(CustomerID);
ALTER TABLE Address ADD CONSTRAINT fk_SupplierID1 FOREIGN KEY(ResidentID) REFERENCES Supplier(SupplierID);
But second 'ALTER TABLE' raises Error: relation already exists
Any suggestions?
Data example:
CustomerID ContactName
C0001 Den
SupplierID ContactName
S0001 John
So Address table should contains:
ResidentID Location
C0001 Alaska
S0001 Nevada
You need to either reference addresses from the Customer / Supplier (if they only have one) or two different columns.
The reason you see in this SQLFiddle You cannot INSERT the required columns into the Address table if the ResidentID references BOTH tables. You could only insert lines that would match the contents of Customer AND Supplier but you want an OR connection that you can't create that way.
(Note: In my solutions I assume addresses to be optional. As Tom pointed out in the comments that may not be what you wanted, or expected. Make sure to mark the FK Columns in the first solution as NOT NULL if you want addresses to be mandatory, its more complicated for the second one. You have to mind the correct insertion order then.)
Either:
CREATE TABLE Address (
AddressID CHAR(5) NOT NULL,
Location varchar(255) NOT NULL,
PRIMARY KEY (AddressID)
);
CREATE TABLE Customer (
CustomerID CHAR(5) NOT NULL,
AddressID CHAR(5),
ContactName varchar(40) NOT NULL,
PRIMARY KEY (CustomerID)
);
CREATE TABLE Supplier (
SupplierID CHAR(5) NOT NULL,
AddressID CHAR(5),
SupplierName varchar(40) NOT NULL,
PRIMARY KEY (SupplierID)
);
ALTER TABLE Customer ADD CONSTRAINT fk_AddressID_Cust FOREIGN KEY(AddressID) REFERENCES Address(AddressID);
ALTER TABLE Supplier ADD CONSTRAINT fk_AddressID_Supp FOREIGN KEY(AddressID) REFERENCES Address(AddressID);
or
CREATE TABLE Address (
CustomerID CHAR(5),
SupplierID CHAR(5),
Location varchar(255) NOT NULL,
PRIMARY KEY (CustomerID, SupplierID)
);
CREATE TABLE Customer (
CustomerID CHAR(5) NOT NULL,
ContactName varchar(40) NOT NULL,
PRIMARY KEY (CustomerID)
);
CREATE TABLE Supplier (
SupplierID CHAR(5) NOT NULL,
SupplierName varchar(40) NOT NULL,
PRIMARY KEY (SupplierID)
);
ALTER TABLE Address ADD CONSTRAINT fk_CustomerID1 FOREIGN KEY(CustomerID) REFERENCES Customer(CustomerID);
ALTER TABLE Address ADD CONSTRAINT fk_SupplierID1 FOREIGN KEY(SupplierId) REFERENCES Supplier(SupplierID);
The approach you're trying is (a) not possible and (b) undesirable even if it was possible.
The best approach is to have a CustomerAddress table and a SupplierAddress table, each with a single FK to the matching base table; or if you must, a cross-reference table with appropriate constraints.
If your motivation for having a single Address table was code reuse, you can still do that ... think in terms of a template xxxAddress table design that can refer to any base xxx table. You can write non-database code that treats the base table name as a parameter and then could handle any number of xxxAddress tables as you add more base tables over time.
Or if your motivation for having a single Address table was to simplify reporting, you can always create a view or stored proc that returns a union of all such tables + an added field to indicate the base table for each address row.
Angelo I am revising this a bit based on your comment ---
Angelo, I ran your sample code in a local MySQL instance (not SQLFiddle) and observed an error.
I was surprised (you learn something every day) that MySQL did allow two foreign key constraints to be defined on the same field; however when you attempt to insert data, when trying to point the FK to the Customer table, I get an error saying a foreign key constraint fails referencing the Supplier table; and vice versa for the insert trying to point the FK to the Supplier table.
So my revised statement is (a) it is possible to create the hydra-headed FK in at least some DBMSs -- verified in MySQL, MS SQL Server and Oracle -- although (b) this only makes sense to use when the foreign key can refer to the same logical entity by ID across multiple tables (e.g. to ensure there is a corresponding record in all required tables, for example); and (c) if used to refer to multiple tables where the primary key is NOT the same logical entity, only works if by chance the same primary key value just happens to exist in all referenced tables, which is likely to lead to subtle, hard-to-find errors.
In other words, your example would work when attempting to insert a record referring to Customer ID=3 only if there was also a Supplier ID=3, which are really logically unrelated.
So my slightly revised answer to the OP is, what you're trying to do is not possible (or logical) when the foreign key is referring to different ENTITIES, as in the OP example of Customers and Suppliers.

Insert null if violates a constraint in mysql?

I have a country and let's say user tables, and in case a submitted country does not match a constraint I want a null go there instead.
create table countries(
ccode char(2), primary key (ccode)
);
create table users(
ccode char(2), foreign key (ccode) references countries(ccode)
);
insert into countries values('ru'),('us'),('hk');
Now if the user submitted an nonexistent code, eg:
insert into users values('xx');
The query would actually fail due to the fk constaint. But I want it to write a null instead. How can we do this?
Answering my own question it looks like this is the way to do it:
(But if you suggest a better answer I will accept it of course)
insert into users values((select ccode from countries where ccode='x'));
^ This will return a code, and a null if it didn't match - which is what I want.