mysql stored procedure checking if record exists - mysql

I created the following stored procedure:
CREATE DEFINER=`root`#`localhost` PROCEDURE `add_summit`(IN `assoc_code` CHAR(5), IN `assoc_name` CHAR(50), IN `reg_code` CHAR(2), IN `reg_name` CHAR(100), IN `code` CHAR(20), IN `name` CHAR(100), IN `sota_id` CHAR(5), IN `altitude_m` SMALLINT(5), IN `altitude_ft` SMALLINT(5), IN `longitude` DECIMAL(10,4), IN `latitude` DECIMAL(10,4), IN `points` TINYINT(3), IN `bonus_points` TINYINT(3), IN `valid_from` DATE, IN `valid_to` DATE)
BEGIN
declare assoc_id SMALLINT(5);
declare region_id SMALLINT(5);
declare summit_id MEDIUMINT(8);
-- ASSOCIATION check if an association with the given code and name already exists
SELECT id INTO assoc_id FROM association WHERE code = assoc_code LIMIT 1;
IF (assoc_id IS NULL) THEN
INSERT INTO association(code, name) VALUES (assoc_code, assoc_name);
set assoc_id = (select last_insert_id());
END IF;
-- REGION check if a region with the given code and name already exists
SET region_id = (SELECT id FROM region WHERE code = reg_code AND name = reg_name AND association_id = assoc_id);
IF (region_id IS NULL) THEN
INSERT INTO region(association_id, code, name) VALUES (assoc_id, reg_code, reg_name);
set region_id = (select last_insert_id());
END IF;
-- SUMMIT check if a summit with given parameters already exists
SET summit_id = (SELECT id FROM summit WHERE association_id = assoc_id AND region_id = region_id);
IF (summit_id IS NULL) THEN
INSERT INTO summit(code, name, sota_id, association_id, region_id, altitude_m, altitude_ft, longitude,
latitude, points, bonus_points, valid_from, valid_to)
VALUES (code, name, sota_id, assoc_id, region_id, altitude_m, altitude_ft, longitude, latitude,
points, bonus_points, valid_from, valid_to);
END IF;
END$$
basically, it should check if a record exists in some tables and, if it doesn't, it should insert it and use the inserted id (auto increment).
The problem is that even if the record exists (for instance in the association table), assoc_id keeps returning null and that leads to record duplication.
I'm new to stored procedures so I may be doing some stupid errors. I've been trying to debug this SP for hours but I cannot find the problem.

A newbie mistake.
I forgot to specify the table name in the field comparison and that leads to some conflicts with param names (for example the param name).
A good idea is to specify some kind of prefix for parameters (like p_) and always specify the name of the table in the SP.

Related

MYSQL TRIGGER doesn't work sql_extras.sql

Why it doesn't work?
I understand that:
line no.: 9, 21
id int NOT NULL IDENTITY(1, 1), should be AUTO_INCREMENT
id int NOT NULL AUTO_INCREMENT
line no.: 24
wrong column name it can be longs instead of long:
longs decimal(9,6) NOT NULL,
line no.:
out of ; on the end of line 36
out of ; on the end of line 44
line 38, 47 longs instead of long:
INSERT INTO city (city_name, lat, longs, country_id)
but I don't know where is problem below line no.: 91
-- Create new database
CREATE DATABASE lesson7;
USE lesson7;
-- 1. Primary and foreign keys
-- Table: country
CREATE TABLE country (
id int NOT NULL IDENTITY(1, 1),
country_name char(128) NOT NULL,
country_name_eng char(128) NOT NULL,
country_code char(8) NOT NULL,
CONSTRAINT country_ak_1 UNIQUE (country_name),
CONSTRAINT country_ak_2 UNIQUE (country_name_eng),
CONSTRAINT country_ak_3 UNIQUE (country_code),
CONSTRAINT country_pk PRIMARY KEY (id)
);
-- Table: city
CREATE TABLE city (
id int NOT NULL IDENTITY(1, 1),
city_name char(128) NOT NULL,
lat decimal(9,6) NOT NULL,
long decimal(9,6) NOT NULL,
country_id int NOT NULL,
CONSTRAINT city_pk PRIMARY KEY (id),
CONSTRAINT city_country FOREIGN KEY (country_id) REFERENCES country (id)
);
-- Fill the tables
INSERT INTO country (country_name, country_name_eng, country_code)
VALUES ('Deutschland', 'Germany', 'DEU'),
('Srbija', 'Serbia', 'SRB'),
('Hrvatska', 'Croatia', 'HRV'),
('United States of America', 'United States of America', 'USA'),
('Polska', 'Poland', 'POL')
INSERT INTO city (city_name, lat, long, country_id)
VALUES ('Berlin', 52.520008, 13.404954, 1),
('Belgrade', 44.787197, 20.457273, 2),
('Zagreb', 45.815399, 15.966568, 3),
('New York', 40.730610, -73.935242, 4),
('Los Angeles', 34.052235, -118.243683, 4),
('Warsaw', 52.237049, 21.017532, 5)
-- Can we do this?
INSERT INTO city (city_name, lat, long, country_id)
VALUES ('Wien', 48.2084885, 16.3720798, 6);
-- Let's try to delete Poland
DELETE FROM country WHERE id = 5;
-- And check the result
SELECT * FROM city;
SELECT * FROM country;
-- We can remove the constraint using its name
ALTER TABLE city DROP CONSTRAINT city_country;
-- And add it once again with different rescrictions
ALTER TABLE city
ADD CONSTRAINT city_country
FOREIGN KEY (country_id)
REFERENCES country (id)
ON UPDATE CASCADE
ON DELETE CASCADE;
-- Let's try to delete Poland once again
DELETE FROM country WHERE id = 5;
-- And check the results
SELECT * FROM country;
SELECT * FROM city;
-- Triggers
/*
DML (data manipulation language) triggers they react to DML commands.
These are INSERT, UPDATE, and DELETE
DDL (data definition language) triggers they react to DDL commands.
These are CREATE, ALTER, and DROP
*/
/*
DROP <object> IF EXISTS before its creation is helpful in two ways:
1) We could get an arror trying to create a duplicate, we prevent it using DROP
2) If we want to DROP someting non-existent, we can get an error so we check that condidtion first
Combining two above should result in smooth execution
*/
-- Trigger to handle inserts with missing 'country_name' or 'country_name_eng' values
DROP TRIGGER IF EXISTS t_country_insert;
GO
CREATE TRIGGER t_country_insert ON country INSTEAD OF INSERT
AS BEGIN
DECLARE #country_name CHAR(128);
DECLARE #country_name_eng CHAR(128);
DECLARE #country_code CHAR(8);
SELECT #country_name = country_name, #country_name_eng = country_name_eng, #country_code = country_code FROM INSERTED;
IF #country_name IS NULL SET #country_name = #country_name_eng;
IF #country_name_eng IS NULL SET #country_name_eng = #country_name;
INSERT INTO country (country_name, country_name_eng, country_code) VALUES (#country_name, #country_name_eng, #country_code);
END;
-- 'country_name' has NOT NULL constraint, but thanks to the trigger, this insert works fine
SELECT * FROM country;
INSERT INTO country (country_name_eng, country_code) VALUES ('United Kingdom', 'UK');
SELECT * FROM country;
-- Trigger to prevent removal of record from parent table if there are records in child table referencing it
DROP TRIGGER IF EXISTS t_country_delete;
GO
CREATE TRIGGER t_country_delete ON country INSTEAD OF DELETE
AS BEGIN
DECLARE #id INT;
DECLARE #count INT;
SELECT #id = id FROM DELETED;
SELECT #count = COUNT(*) FROM city WHERE country_id = #id;
IF #count = 0
DELETE FROM country WHERE id = #id;
ELSE
THROW 51000, 'can not delete - country is referenced in other tables', 1;
END;
-- Example
SELECT * FROM country;
SELECT * FROM city;
DELETE FROM country WHERE id = 4;
/*
Functions - idea behind them is to avoid writing the same code over and over again
*/
-- Example: function returning if point on the map is located in a western or eastern hemisphere
-- Input: single decimal value (longitude)
-- Output: single char value (position)
-- It's an example of a "scalar-valued function" - returns a single value
CREATE FUNCTION east_or_west (
#long DECIMAL(9,6)
)
RETURNS CHAR(4) AS
BEGIN
DECLARE #return_value CHAR(4);
SET #return_value = 'same';
IF (#long > 0.00) SET #return_value = 'east';
IF (#long < 0.00) SET #return_value = 'west';
RETURN #return_value
END;
-- Examples
SELECT * FROM city;
SELECT city_name, dbo.east_or_west(long) AS 'position'
FROM city;
-- Example: function returning cities from table 'city' located to the east of a given point
-- Input: single decimal value (longitude of a point)
-- Output: filtered table 'city'
-- It's an example of a "table-valued function" - returns a table (multiple values)
CREATE FUNCTION east_from_long (
#long DECIMAL(9,6)
)
RETURNS TABLE AS
RETURN
SELECT *
FROM city
WHERE city.long > #long;
-- Example
SELECT *
FROM east_from_long(0.00);
/*
Stored procedures - idea behind them is to put multiple operations
(inserting, updating, deleting, retrieving data) into one "black box" that can be called multiple times
using various parameters
*/
DROP PROCEDURE IF EXISTS p_cities_all;
GO
CREATE PROCEDURE p_cities_all
-- procedure returns all rows from the customer table
AS BEGIN
SELECT *
FROM city;
END;
-- Execute the procedure with EXEC, procedure uses no parameters
EXEC p_cities_all;
-- Another example, procedure returns the entire row for the given id
DROP PROCEDURE IF EXISTS p_city;
GO
CREATE PROCEDURE p_city (#id INT)
AS BEGIN
SELECT *
FROM city
WHERE id = #id;
END;
-- Execute using EXEC and providing the value for a parameter (id of a row)
EXEC p_city 4;
SELECT * FROM country;
SELECT * FROM city;
-- Example: procedure inserting city from germany (no 'country_id' value is needed while inserting records)
DROP PROCEDURE IF EXISTS p_city_in_germany_insert;
GO
CREATE PROCEDURE p_city_in_germany_insert (#city_name CHAR(128), #lat DECIMAL(9, 6), #long DECIMAL(9, 6))
AS BEGIN
INSERT INTO city(city_name, lat, long, country_id)
VALUES (#city_name, #lat, #long, 1);
END;
-- Example, let's insert Munich to our table
SELECT * FROM city;
EXEC p_city_in_germany_insert 'Munich', 48.13743, 11.57549;
SELECT * FROM city;
-- Example: deleting rows based on 'id'
DROP PROCEDURE IF EXISTS p_city_delete;
GO
CREATE PROCEDURE p_city_delete (#id INT)
AS BEGIN
DELETE
FROM city
WHERE id = #id;
END;
-- Example, delete city with id = 1
EXEC p_city_delete 1;
-- Results
SELECT * FROM city;

SQL - Procedure function

Trying to create a Procedure to (Insert, Delete and, Update) values in employee_details.
CREATE DEFINER=`root`#`localhost` ALTER PROCEDURE `alter_employeedetails`(in employee_id int(11), employee_name VARCHAR(30), employee_join_date date,
employee_desgination varchar(30), employee_salary bigint(20), employee_address varchar(30),
employee_contact varchar(30), employee_email_id varchar(30)
BEGIN
IF #StatementType = 'Insert'
BEGIN
insert into employee_details values
(employee_id, employee_name, employee_join_date, employee_desgination, employee_salary, employee_address, employee_contact, employee_email_id)
END
IF #StatementType = 'Update'
BEGIN
UPDATE employee_details SET
(employee_name = #employee_name, employee_join_date = #employee_join_date, employee_designation = #employee_desgination,
employee_salary = #employee_salary, employee_address = #employee_address, employee_contact = #employee_contact, employee_email_id = #employee_email_id)
WHERE employee_id = #employee_id
END
else IF #StatementType = 'Delete'
BEGIN
DELETE FROM employee_details where employee_id = #employee_id
END
end
Quite a few errors in that code...
You forgot to prefix all the parameters with the "#" symbol.
Forgot to include "#StatementType" as a parameter.
Update had brackets around it.
You cannot specify int(11) (employee_id) or bigint(20)
(salary). It's either int / bigint (you don't specify the length
for int/bigint datatypes). And is salary correct as bigint? MSSQL has a "money"
datatype, or you could use decimal(8,2) or something similar. You
might be multiplying the salary by 100 to shift the decimal place for
all I know?
When inserting, do you really want to insert a employee Id? This would normally be an auto-incrementing primary key
Insert statement missing the fields you were populating. Required if using the "values" keyword like you had specified.
Hopefully this is closer to what you want.
ALTER PROCEDURE alter_employeedetails
(#StatementType as varchar(25), #employee_id int, #employee_name VARCHAR(30), #employee_join_date date,
#employee_designation varchar(30), #employee_salary bigint, #employee_address varchar(30),
#employee_contact varchar(30), #employee_email_id varchar(30))
AS
BEGIN
IF #StatementType = 'Insert'
BEGIN
insert into employee_details
(employee_id, employee_name, employee_join_date, employee_designation, employee_salary, employee_address, employee_contact, employee_email_id)
values
(#employee_id, #employee_name, #employee_join_date, #employee_designation, #employee_salary, #employee_address, #employee_contact, #employee_email_id)
END
ELSE IF #StatementType = 'Update'
BEGIN
UPDATE employee_details
SET
employee_name = #employee_name,
employee_join_date = #employee_join_date,
employee_designation = #employee_designation,
employee_salary = #employee_salary,
employee_address = #employee_address,
employee_contact = #employee_contact,
employee_email_id = #employee_email_id
WHERE employee_id = #employee_id
END
ELSE IF #StatementType = 'Delete'
BEGIN
DELETE FROM employee_details where employee_id = #employee_id
END
END

Stored Procedure in mySQL workbench (INSERT INTO error)

I'm running into an error in my stored procedure, and after numerous YT videos and forums, I still have no clue where I'm going wrong. Given what I'm trying to do, it all seems to look correct.
Here's the deal. I take in some information to buy some stock, I use an IF to make sure that I have enough money to make the purchase, I then insert the purchase information into my TRADES table and update the cash balance in ACCOUNTS to reflect the spending of $$.
I can't even test to see if it works correctly because it won't run. The only error I'm getting is at INSERT INTO, in which it says error: INTO (into) is not valid input at this position
I have done ALL of my insert statements the exact same way, and have no idea why this particular syntax is incorrect? Any help would be greatly appreciated! Below are two approaches, both with errors.
CREATE PROCEDURE `BUY` (TID INT,ID INT, CASH INT, T_NAME VARCHAR(4) ,
TCOUNT INT, TBUYDATE DATE, TBUYPRICE INT )
BEGIN
IF (ACCOUNT.CASH_BALANCE >= (TCOUNT * TBUYPRICE),
INSERT INTO TRADES (TRADE_ID, ACCOUNT_ID, TRADE_NAME, TRADE_COUNT, TRADE_BUYDATE, TRADE_BUYPRICE)
VALUES (TID, ID, T_NAME, TCOUNT, TBUYDATE, TBUYPRICE)
AND UPDATE ACCOUNT.CASH_BALANCE
WHERE ACCOUNT.ACCOUNT_ID = ID
SET ACCOUNT.CASH_BALANCE = (ACCOUNT.CASH_BALANCE - (TCOUNT * TBUYPRICE)),
NULL
)
END
I have also tried the following, however I get an error on END missing subclause or other elements before end
CREATE PROCEDURE `BUY` (TID INT,ID INT, CASH INT, T_NAME VARCHAR(4) , TCOUNT
INT, TBUYDATE DATE, TBUYPRICE INT )
BEGIN
IF (ACCOUNT.CASH_BALANCE >= (TCOUNT * TBUYPRICE))
THEN
INSERT INTO TRADES (TRADE_ID, ACCOUNT_ID, TRADE_NAME, TRADE_COUNT,
TRADE_BUYDATE, TRADE_BUYPRICE)
VALUES (TID, ID, T_NAME, TCOUNT, TBUYDATE, TBUYPRICE);
UPDATE ACCOUNT.CASH_BALANCE
SET ACCOUNT.CASH_BALANCE = (ACCOUNT.CASH_BALANCE - (TCOUNT * TBUYPRICE))
WHERE ACCOUNT.ACCOUNT_ID = ID;
ELSE #noinsert
END
There are multiple errors/corrections:
The Delimiter command was not used, so he gets confused on the end of statement and the end of the procedure definition
The account table needs to be selected in an exists statement
I've used a local variable l_cash instead of repeating TCOUNT * TBUYPRICE (Not an error).
The ELSE statement was not necessary and an END IF; was missing.
Update statement corrected.
Here is the corrected code:
DELIMITER $$
CREATE PROCEDURE `BUY` (TID INT,ID INT, CASH INT, T_NAME VARCHAR(4) , TCOUNT
INT, TBUYDATE DATE, TBUYPRICE INT)
BEGIN
DECLARE l_cash INT DEFAULT 0;
SET l_cash = TCOUNT * TBUYPRICE;
IF EXISTS(SELECT 1 FROM Account WHERE ACCOUNT_ID = ID AND CASH_BALANCE >= l_cash) THEN
INSERT INTO TRADES (TRADE_ID, ACCOUNT_ID, TRADE_NAME, TRADE_COUNT,
TRADE_BUYDATE, TRADE_BUYPRICE)
VALUES (TID, ID, T_NAME, TCOUNT, TBUYDATE, TBUYPRICE);
UPDATE ACCOUNT
SET CASH_BALANCE = (CASH_BALANCE - l_cash)
WHERE ACCOUNT_ID = ID;
END IF;
END$$
DELIMITER ;

Stored procedure : Data truncation: Truncated incorrect DOUBLE value

I lack experience building stored procedures and have encountered this error that I cannot understand the reasoning behind :
[2015-09-29 01:01:55] [22001][1292] Data truncation: Truncated incorrect DOUBLE value: '5609d3e6c89be'
The value '5609d3e6c89be' is the "FlightID".
My stored procedure code :
DROP PROCEDURE IF EXISTS initFlight;
CREATE PROCEDURE initFlight (flightid VARCHAR(50))
BEGIN
-- rules, player should only fly if not in jail, not in missions
-- and is in the city the flight will take off from
DECLARE fname VARCHAR(50); -- flight name
DECLARE depart int; -- city number of departure
DECLARE dest int; -- city number of destination
-- assign values to our variables
select flightname, source_airport, destination_airport
into fname, depart, dest
from airport_flights where id = flightID;
-- show in console the variable values for debugging
-- select concat(" fname: ", fname, " depart: ", depart, " dest: ", dest);
-- set players flying means p.live = '-1'
update `[players]` as p set p.live = '-1' where p.id in (
select id from airport_tickets where flight = flightID
) and p.live = depart;
-- insert into alerts a message for players boarding the flight (are in the city of departure)
insert into player_alerts (alert_text, player_id)
select concat("Boarding flight ", fname) as alert_text, p.id as player_id from `[players]` as p
where p.id in (
select id from airport_tickets where flight = flightID
) and p.live = depart;
-- insert into alerts a message for players that missed the flight (are not in the city of departure)
insert into player_alerts (alert_text, player_id)
select concat("You missed flight ", fname) as alert_text, id as player_id from `[players]` as p
where p.id in (
select id from airport_tickets where flight = flightID
) and p.live != depart;
-- stop sales
update airport_flights set selling_tickets = 0 where id = flightID;
END;
call initFlight('5609d3da016bf');
What is happening here? Why is my "string" being coverted into a double and then truncated?
airport_flights.id is varchar(50)
airport_flights.source_airport is int(11)
airport_flights.destination_airport is int(11)
airport_tickets.id is varchar(50)
airport_tickets.flight is varchar(50)
airport_tickets.owner_id is int(11)
`[players]`.id is int(11)
`[players]`.live is int(11)
`[players]`.name is varchar(200)
player_alerts.id is int(11)
player_alerts.alert_text is varchar(250)
PS: if you need any more information let me know and criticism is as always welcome
After much head bumping around I found out that the problem was in the sub-queries where I was mixing the airport_tickets.id (varchar) with the player.id (int) when I wanted to match airport_tickets.owner_id with player.id.
I only found this out when removing everything and re-writing it all as a measure of removing any code blindness (when your brain reads what it thinks the code does instead of what is actually written).

Stored procedure for Inserting Data into 3 tables. Not working.

I have 3 tables-
1. Country (CountryName, CID (PK- AutoIncrement))
2. State (SID(PK- AutoIncrement), StateName, CID (FK to Country)
3. City (CityName, CID, SID (FK to State)
Now I need to insert only the name into the three tables with CountryName, StateName and CityName.. The IDs need to get updated.
Create PROCEDURE sp_place(
#CountryName char(50),
#StateName varchar(50),
#CityName nchar(20)
)
AS
DECLARE #CountryID int, #StateID int, #CityID int;
Set NOCOUNT OFF
BEGIN TRANSACTION
INSERT INTO dbo.Country VALUES (#CountryName);
SET #CountryID = SCOPE_IDENTITY();
IF ##ERROR <> 0
BEGIN
ROLLBACK
RETURN
END
Insert into dbo.State VALUES (#StateName, #CountryID);
SET #StateID = SCOPE_IDENTITY();
IF ##ERROR <> 0
BEGIN
ROLLBACK
RETURN
END
Insert into dbo.City VALUES (#CityName, #StateID);
SET #CityID= SCOPE_IDENTITY();
Commit
When I Enter Country twice, the value shouldn't get changed.
Eg: If I enter India the value of CountryID=1, when I again enter India, the value of CountryID shouldn't get increased.
How'd I perform that? My SP changes for every insertion.
You can check if the country already exist and retrieve the countryID
IF NOT EXISTS(Select 1 FROM Country Where CountryName=#Country)
BEGIN
INSERT INTO dbo.Country VALUES (#CountryName);
SET #CountryID = SCOPE_IDENTITY();
END
ELSE
Select #CountryID = CountryID From Country Where CountryName=#Country
You can do the same for State and City if required
Hello try with this syntax
IF EXISTS (SELECT * FROM Country WHERE CountryName= #CountryName)
BEGIN
UPDATE dbo.Country
SET CountryName = #CountryName
WHERE CountryId = (SELECT CountryId FROM dbo.Country WHERE CountryName= #CountryName);
END
ELSE
BEGIN
INSERT INTO dbo.Country(CountryName) VALUES (#CountryName);
END
-- For the identity you must just add identity to your column in your creation script
Why dont you set Unique Constraint on CountryName column that won't allow you to insert duplicate countries at all
You need the MERGE syntax
http://technet.microsoft.com/en-us/library/bb510625.aspx
or to check manually (ie: with IF EXISTS (...) ) for the existence of the country before inserting.