Stored procedure used to insert datas in two tables - mysql

I am using a stored procedure to insert data into two tables. But when I insert the datas the total number of rows in the first table and the second table is different, so it means that sometimes it only inserted the datas in the first table but failed to insert it in the second table. But this case should not happen in my case as the Id of the two tables is related to each other. How can I solve this problem? So that when it will insert datas in both tables or no table if an error occurs so that the number of datas are the same in both the table. My stored procedure is as follows:
Begin
insert into base_table(imgPath,store,apparelType) values (imgPath,store,apparelType);
insert into data_table(cvID,color) values
(LAST_INSERT_ID(),color);
END

To make sure that the 1st query has been successfully executed, the best way would be to add an Identity column in your base_table, then proceed as follows;
DECLARE #LAST_INSERT_ID INT
DECLARE #EXECUTION_OK char(1)
SET #EXECUTION_OK = 1
insert into base_table(imgPath,store,apparelType) values (imgPath,store,apparelType)
SELECT #LAST_INSERT_ID = SCOPE_IDENTITY()
insert into data_table(cvID,color) values (#LAST_INSERT_ID, color)
GO
If exists( Select cvID from data_table where cvID= #LAST_INSERT_ID)
Begin
#EXECUTION_OK = 0
End
SCOPE_IDENTITY: Returns the last identity value inserted into an identity column in the same scope. A scope is a module: a stored procedure, trigger, function, or batch. Therefore, two statements are in the same scope if they are in the same stored procedure, function, or batch.
You can also use the mysql_affected_rows() function to verify that the query has been successful.

Related

Call Stored Procedure While Inserting

I am trying to insert values from one table to another one using the following insert sql query
INSERT INTO [dbo].[table2]
SELECT Exec [StoredProcedure],
[Column1]
,[Column2]
FROM [dbo].[table1]
[table2] has the following columns:
RecNo, <-- INT
Column1, <--VARCHAR(50)
Column2 <--VARCHAR(50)
[StoredProcedure] main purpose is that every time a new row to be inserted in table2 it selects the maximum value from RecNo from table2 and adds 1 to that number to create the next number (sequential).
Here is the script for the stored procedure .
GO
ALTER PROCEDURE [dbo].[UpdateRcnoNumbers]
#MaxRcno INT OUTPUT
AS
BEGIN
SELECT #MaxRcno=MAX(Recno) FROM [table2]
SELECT #MaxRcno=#MaxRcno+1
RETURN #MaxRcno
END
But I am getting an error and I am not able to call the stored procedure ? Any suggestion please .
Thank you in advance
You should write a function for this purpose , read here
The problem is, Stored Procedures don't really return output directly. They can execute select statements inside the script, but have no return value.
MySQL calls stored procedures via CALL StoredProcedureName(); And you cannot direct that output to anything, as they don't return anything (unlike a function).
Here
MySQL Call Command

MySQL 100% get last insert id LAST_INSERT_ID();

MySQL has LAST_INSERT_ID(); function which gets the last insert.
But this is not safe: If i run some query then get LAST_INSERT_ID() and between the two another query is executed I can get the wrong id.
This can happen in multiple threads using the same connection, or using pconnect (persistend connection for multiple users)
Is there safe method for getting the ID that i want 100% ?
Thanks
Store procedure may help in the case:
Create table test (id int AUTO_INCREMENT primary key, name varchar(50) )
Store procedure as:
delimiter $$
DROP PROCEDURE IF EXISTS InserData$$
CREATE PROCEDURE InserData(IN _Name VARCHAR(50))
BEGIN
START TRANSACTION;
INSERT INTO test(name) VALUES (_Name);
SELECT LAST_INSERT_ID() AS InsertID;
COMMIT;
END
Call the stored procedure using
CALL InserData('TESTER')
Give it a try as we have transaction statement but it can't ensure the value in multi threaded environment.
The link Mysql thread safety of last_insert_id explain it will work based on per connection model.
Is using SELECT Max(ID) FROM table safer than using SELECT last_insert_id(), where they run as 2 separate queries?
According to your question the table must have a primary key.
So you can get last record from MAX(ID)

What is faster: to call a user-declareed function within a query or to set the value by trigger?

There is a declared MySQL function GETUSERID() returning an integer value. How to make a record insert faster: setting the value from inside a query like
INSERT INTO ttable
(idtoset, some_other_field...)
VALUES (GETUSERID(), value1...);
or call
INSERT INTO ttable
(some_other_field...)
VALUES (value1...);
and fill idtoset by a trigger that fires before insert?
What if the query is performing multiple row insert like
INSERT INTO ttable
(idtoset, some_other_field...)
VALUES (GETUSERID(), value1...),
(GETUSERID(), value2...),
...
(GETUSERID(), valueN...);
?
Edit
I have just investigated the answer of #Rahul.
I created a ttest table with two triggers
CREATE TRIGGER `tgbi` BEFORE INSERT ON `ttest` FOR EACH ROW BEGIN
SET NEW.testint=1;
END;
CREATE TRIGGER `tgbi` BEFORE UPDATE ON `ttest` FOR EACH ROW BEGIN
SET NEW.testint=2;
END;
If I am not mistaken, should the before insert trigger call UPDATE SET the second trigger is expected to fire as well and the created testint value might be =2, but it is =1 in every inserted row. Could that mean that the engine optimises INSERT procedure and sets the value simultaneously with that set manually by query?
Appended on request of #Rick-James. The question is not about the definite function. It is actually about any function. Any function will be called same number of times if the record is inserted from trigger or from INSERT query. That is why I am wondering what is better from the point of MySQL engine - to call it manually setting the value in inserted records or filling it by means of triggers?
CREATE DEFINER=`***`#`***` FUNCTION `GETUSERID`() RETURNS int(10)
BEGIN
DECLARE id_no INT DEFAULT -1;
SELECT `id` INTO id_no FROM `tstuff`
WHERE `tstuff`.`user_name`=
(SELECT SUBSTRING_INDEX(USER(), '#', 1)) LIMIT 1;
RETURN id_no;
END
What is faster? No idea since I haven't done a bench marking on that but doing an direct INSERT operation would better to my knowledge instead of inserting and then perform an UPDATE through trigger.
Does what you are doing currently not working? you can as well make it a INSERT .. SELECT operation like
INSERT INTO ttable (idtoset, some_other_field...)
SELECT GETUSERID(), value1..., valuen FROM DUAL;
In past versions of MySQL, using a before insert trigger to populate a not nullable column didn't work as MySQL was evaluating the provided columns before the trigger. That's why whenever I have such a situation, I usually tend to go with functions instead of triggers.
From a performance point of view, since the before insert trigger is evaluated before actually writing data so the time needed to perform this is almost the same as immediately getting the value with the function and without trigger. But if all you are doing in the trigger is set the user ID, then I really see no reason to use a trigger.

SQL check if existing row, if not insert and return it

I'm having a problem with my sql query. I need to insert a data that needs to be checked first if it is existing or not. If the data is existing the sql query must return it, if not insert and return it. I already google it but the result is not quite suitable to my problem. I already read this.
Check if a row exists, otherwise insert
How to 'insert if not exists' in MySQL?
Here is a query that' I'm thinking.
INSERT INTO #tablename(#field, #conditional_field, #field, #conditional_field)
VALUES(
"value of field"
(SQL QUERY THAT CHECK IF THERE IS AN EXISTING DATA, IF NOT INSERT THE DATA and RETURN IT, IF YES return it),
"value of feild",
(SQL QUERY THAT CHECK IF THERE IS AN EXISTING DATA, IF NOT INSERT THE DATA and RETURN IT, IF YES return it)
);
Please take note that the conditional field is a required field so it can't be NULL.
Your tag set is quite weird, I'm unsure you require all the technologies listed but as long as Firebird is concerned there's UPDATE OR INSERT (link) construction.
The code could be like
UPDATE OR INSERT INTO aTable
VALUES (...)
MATCHING (ID, SomeColumn)
RETURNING ID, SomeColumn
Note that this will only work for PK match, no complex logic available. If that's not an option, you could use EXECUTE BLOCK which has all the power of stored procedures but is executed as usual query. And you'll get into concurrent update error if two clients execute updates at one time.
You could split it out into 2 steps
1. run a select statement to retrieve the rows that match your valus. select count (*) will give you the number of rows
2. If zero rows found, then run the insert to add the new values.
Alternatively, you could create a unique index form all your columns. If you try to insert a row where all the values exist, an error will be returned. You could then run a select statement to get the ID for this existing row. Otherwise, the insert will work.
You can check with if exists(select count(*) from #tablename) to see if there is data, but with insert into you need to insert data for all columns, so if there is only #field missing, you cant insert values with insert into, you will need to update the table and go with a little different method. And im not sure, why do you check every row? You know for every row what is missing? Are you comparing with some other table?
You can achieve it using MySQL stored procedure
Sample MySQL stored procedure
CREATE TABLE MyTable
(`ID` int, `ConditionField` varchar(10))
;
INSERT INTO MyTable
(`ID`, `ConditionField`)
VALUES
(1, 'Condition1'),
(1, 'Condition2')
;
CREATE PROCEDURE simpleproc (IN identifier INT,ConditionData varchar(10))
BEGIN
IF (SELECT ID FROM MyTable WHERE `ConditionField`=ConditionData) THEN
BEGIN
SELECT * FROM MyTable WHERE `ConditionField`=ConditionData;
END;
ELSE
BEGIN
INSERT INTO MyTable VALUES (identifier,ConditionData);
SELECT * FROM MyTable WHERE `ConditionField`=ConditionData;
END;
END IF;
END//
To Call stored procedure
CALL simpleproc(3,'Condition3');
DEMO

Referential Insert - Stored Procedure - SQL Server 2008

I working in .Net Application. Here in my aspx page, i am having 3 Tabs (i.e) Tab 1, Tab 2,Tab 3. The first Tab contains some Textbox controls, the Second tab contains some combo box controls and same as Third tab contains some controls. I want to save all these three tab controls to THREE different tables in SQL Database. Only one Stored Procedure should be used for this. The PRIMARY KEY of the FIRST table should be saved in the SECOND and THIRD table. ( LIKE, REFERENTIAL INSERT ). Here is my SP...
ALTER PROCEDURE [dbo].[Insert]
(#Name NVARCHAR(50))
AS
BEGIN
SET NOCOUNT ON
DECLARE #TableOnePrimaryKey INT
BEGIN
INSERT INTO TABLEONE(Name)
VALUES (#Name)
SELECT #TableOnePrimaryKey=##IDENTITY
SELECT CAST(##IDENTITY AS INT)
INSERT INTO TABLETWO(TableTwoIDColumn)
VALUES (#TableOnePrimaryKey)
SELECT #TableOnePrimaryKey=##IDENTITY
SELECT CAST(##IDENTITY AS INT)
INSERT INTO TABLETHREE(TableThreeIDColumn)
VALUES (#TableOnePrimaryKey)
SELECT #TableOnePrimaryKey=##IDENTITY
SELECT CAST(##IDENTITY AS INT)
INSERT INTO TABLEFOUR(TableFourIDColumn)
VALUES (#TableOnePrimaryKey)
END
But, its the TABLE ONE Primary key is not got saved in other tables. How to Fix this..
Use scope_identity() instead of ##identity. And you should not assign the value to #TableOnePrimaryKey more than once. If you have an identity column in the other tables you loose the identity you got from the first insert.
ALTER PROCEDURE [dbo].[Insert]
(#Name NVARCHAR(50))
AS
BEGIN
SET NOCOUNT ON
DECLARE #TableOnePrimaryKey INT
INSERT INTO TABLEONE(Name)
VALUES (#Name)
SET #TableOnePrimaryKey=SCOPE_IDENTITY()
INSERT INTO TABLETWO(TableTwoIDColumn)
VALUES (#TableOnePrimaryKey)
INSERT INTO TABLETHREE(TableThreeIDColumn)
VALUES (#TableOnePrimaryKey)
INSERT INTO TABLEFOUR(TableFourIDColumn)
VALUES (#TableOnePrimaryKey)
END
I'd be using scope_identity over identity.
From http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/
"To avoid the potential problems associated with adding a trigger
later on, always use SCOPE_IDENTITY() to return the identity of the
recently added row in your T SQL Statement or Stored Procedure."
Try that and see if it fixes your issue.
Edit: I meant to mention that I think you need to set the variable differently. Try the following;
SET #TableOnePrimaryKey = (SELECT SCOPE_IDENTITY())
SELECT CAST(#TableOnePrimaryKey AS INT)
etc etc