sql loop with foreign key - mysql

Im trying to generate a bunch of discounts codes. These have foreign key contraints.
At the moment I have
INSERT INTO code (title, code, desc) VALUES ('code1','XPISY9','test code');
INSERT INTO code_details (code_id, used, attempts) VALUES (
SELECT code_id from code where code = 'XPISY9',0,0);
The code_id in code_details is a foreign key for code_id in the code table.
What would be the best way to create a loop where I can generate a set of these values (around 100). I would need the code to be a not repeating random value.
Any help would be appreciated.
THanks

Once you have your 100 or so records in the code table, you can add the code details in one statement:
INSERT INTO code_details (code_id, used, attempts)
SELECT code, 0, 0
FROM code;
Generating the code records in the first place is another matter and is probably best done by using some other tool to generate 100 insert statements in a text file which you can then execute.
I've seen that done with every scripting language possible - chose your favourite. I've even seen Excel used with a column for the id and string formula to generate the insert statements.

Thanks for the help guys. I decided to put together a procedure for this and it worked great:
DELIMITER $$
CREATE PROCEDURE vouchergen(IN length INT(10) ,IN duration VARCHAR(20),IN sponsor VARCHAR(20),IN amount INT(10))
BEGIN
DECLARE i INT DEFAULT 1;
WHILE (i< amount) DO
SET #vcode= CONCAT(BINARY brand , UPPER(SUBSTRING(MD5(RAND()) FROM 1 FOR 6)));
INSERT INTO code (title, code, desc) VALUES (CONCAT(brand,i),#vcode,CONCAT(length,' ',duration));
INSERT INTO code_details (code_id, used, attempts) VALUES (
SELECT code_id from code where code = #vcode,0,0);
SET i=i+1;
END WHILE;
END$$;
I can then call this to gen however many i want:
CALL vouchergen(1,'week',APPL,400);
CALL vouchergen(1,'month',APPL,100);
CALL vouchergen(1,'day',APPL,200);

Related

MySQL add in bulk by passing data in argument for procedure

after searching for a while I could not find a way to add rows in bulk by passing in argument for example a list of values. I know that it is possible to create a for loop, but it would insert each value separately n times, which I assume is bad performancewise. Here is a sample of what I have
CREATE PROCEDURE \`spLogAdd\`(
IN \`userId\` VARCHAR(255),
IN \`isActive\` BIT,
IN \`valueDatetime\` DATETIME,
IN \`valueId\` INT
)
BEGIN
INSERT INTO log_table (user_id, is_active, value_datetime, valueId)
VALUES (\`userId\`, \`isActive\`, \`valueDatetime\`, \`valueId\`);
END;
What I would like to have is a list of userIds('1,2,3,4,5,6') to insert multiple rows with 1 then 2 and so on at once. Other arguments do not need to change. If there is any neat way, please help me to do that.
CREATE PROCEDURE \`spLogBulkAdd\`(
IN \`userId\` VARCHAR(255),
IN \`isActive\` BIT,
IN \`valueDatetime\` DATETIME,
IN \`valueId\` INT
)
BEGIN
INSERT INTO log_table (user_id, is_active, value_datetime, valueId)
VALUES (\`userId\`, \`isActive\`, \`valueDatetime\`, \`valueId\`);
END;

SQL trigger to avoid duplicates with multiple IDs

Good morning,
I found the solution to my problem, but I thought I'd share it anyway as it might be useful for future projects/problems. I have a simple SQL table below which will be the foreign key of my much bigger table of stock prices market data.
CREATE TABLE [StockMarket]
(
[ID] INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
[ReutersRIC] VARCHAR(50),
[BloombergTicker] VARCHAR(50),
[YahooSymbol] VARCHAR(50)
/* other irrelevant columns here*/
)
With that in mind, I am trying to add robustness to the structure as I will be adding from different data sources. For each underlying time series on the financial markets, there are multiple names depending on which data provider you use. I wanted to avoid having multiple lines with different data sources representing the same time series. I needed a trigger which:
1) If the inserted values are not yet in the table, it is simply inserted.
2) if I insert a line for which at least one [ReutersRIC], [BloombergTicker], [YahooSymbol], [ISIN] already exists, I update that specific line instead.
2.1) The update should only happen on Non-Null entrees
My question was how this can be achieved in the best possible way? It took me some time, but I wanted to share the answer below for future reference.
Here is my solution:
CREATE TRIGGER UniqueStockMarketInserts ON [dbo].[StockMarket]
INSTEAD OF INSERT
AS
BEGIN
DECLARE #StockId int
SELECT #StockId = S.ID
FROM [StockMarket] S INNER JOIN [INSERTED] I
ON
S.YahooSymbol = I.YahooSymbol OR
S.ReutersRIC = I.ReutersRIC OR
S.BloombergTicker = I.BloombergTicker OR
S.ISIN = I.ISIN
IF #StockId IS NULL
BEGIN
INSERT INTO [StockMarket] (YahooSymbol,ReutersRIC,BloombergTicker,ISIN)
SELECT I.YahooSymbol, I.ReutersRIC, I.BloombergTicker, I.ISIN
FROM [INSERTED] I
END
ELSE
BEGIN
UPDATE S SET
S.ISIN = ISNULL(S.ISIN,I.ISIN),
S.YahooSymbol = ISNULL(S.YahooSymbol,I.YahooSymbol),
S.ReutersRIC = ISNULL(S.ReutersRIC,I.ReutersRIC),
S.BloombergTicker = ISNULL(S.BloombergTicker,I.BloombergTicker)
FROM INSERTED I, StockMarket S
WHERE S.ID = #StockId
END
END
GO
Here is the test I ran on it with real-life examples (except the ISIN which I made up):
/*-----------TESTING THE TRIGGER--------*/
INSERT INTO StockMarket (ReutersRIC, BloombergTicker) VALUES ('G.TO', 'GG US Equity');
INSERT INTO StockMarket (YahooSymbol, BloombergTicker, ISIN) VALUES ('GOOG', 'GOOG US Equity','US123454321');
INSERT INTO StockMarket (YahooSymbol, ISIN) VALUES ('RDSA','NL111112222')
INSERT INTO StockMarket (YahooSymbol, ReutersRIC) VALUES ('GG', 'G.TO'); /*this should update as per trigger*/
INSERT INTO StockMarket (ReutersRIC, ISIN) Values ('GOOG.OQ','US123454321'); /*this should update as per trigger*/
INSERT INTO StockMarket (YahooSymbol, ReutersRIC) Values ('RDSA', 'RDSa.L'); /*this should update as per trigger*/
And the results:
Hope this can help someone in the future. Happy coding

Mysql Insert if not exist in two column

I looked into MySQL duplicate key but cant figure it out.
I have a table like below:
id series chapter path(can be unique)
I want only insert data and not update. Lets say I have data like below:
seri:Naruto, klasor:567 ==> If both of these exist in table then do not insert.
seri:Naruto, klasor:568 ==> If Naruto exist but 568 does not exist then do insert.
How can I achieve this?
Easiest way would be to define unique index with two columns on that table:
ALTER TABLE yourtable ADD UNIQUE INDEX (seri,klasor);
You may also define two column primary key, which would work just as well.
Then use INSERT IGNORE to only add rows when they will not be duplicates:
INSERT IGNORE INTO yourtable (seri, klasor) VALUES ('Naruto',567);
INSERT IGNORE INTO yourtable (seri, klasor) VALUES ('Naruto',568);
Edit: As per comments, you can't use UNIQUE INDEX which complicates things.
SET #seri='Naruto';
SET #klasor=567;
INSERT INTO yourtable
SELECT seri,klasor FROM (SELECT #seri AS seri, #klasor AS klasor)
WHERE NOT EXISTS (SELECT seri, klasor FROM yourtable WHERE seri=#seri AND klasor=#klasor);
You may use the above query with two local variables or convert it to single statement by replacing the local variables with actual values.
Better way would be to use stored procedure:
CREATE PROCEDURE yourinsert (vseri VARCHAR(8), vklasor INT)
BEGIN
DECLARE i INT;
SELECT COUNT(*) INTO i FROM yourtable WHERE seri=vseri AND klasor=vklasor;
IF i=0 THEN
INSERT INTO yourtable (seri,klasor) VALUES (vseri, vklasor);
END IF;
END;
This would allow you to perform the INSERT using:
CALL yourinsert('Naruto',567);
INSERT INTO table_name (seri, klasor) VALUES ('Naruto',567)
WHERE NOT EXISTS( SELECT seri,klasor FROM table_name WEHERE seri='Naruto' AND klasor=567
)
Hope this helps..

Add a row if there are less than 5, otherwise replace the lowest number in MySQL

I'm pretty stuck on a Mysql query.
I have a table with three columns;
user_id | person_id | score.
The table is going to be used to store top 5 highscores for each person.
I need at query that checks if there is less than five rows for a specific person.
Is there is less, insert new row. But if there is five rows I have to replace the lowest score with the new one.
It is for a webservice written in PHP and the data about the new score is posted to the method as params.
Been stuck for some hours now — is it even possible to make this happen in one query ?
You can use stored procedure in mysql. I dont know the names of the tables but if you look closer you will understand how it works.
DELIMITER $$
DROP PROCEDURE IF EXISTS test $$
CREATE PROCEDURE test( IN testparam VARCHAR(22) )
BEGIN
DECLARE count INT(11);
SET count = (SELECT COUNT(*) FROM persons );
IF count < 5 THEN
insert into table_needed_for_insert values(testparam);
ELSE
update table_needed_for_insert where score=(select min(score) from table_needed_for_insert);
END IF;
select * from table_needed_for_insert
END $$
DELIMITER;
And how to execute this thing CALL test(1); 1 is the parameter, you can create as many as you need.
And from php you can call directly as like
$result = mysql_query("call test(".$param.")");
And here you can check a tutorial on mysql stored procedures:
http://www.mysqltutorial.org/mysql-stored-procedure-tutorial.aspx
It might be possible if you have a unique key which identifies the lowest score. Then you could use the
INSERT ... ON DUPLICATE KEY construct. But you would have to install a trigger which keeps explicit track of the lowest score.
I would propose this scenario (I have not tried it, it is just an idea):
as I understand, you only need 5 ids. you can run a subqueries like these
SELECT MAX(id) AS last_id FROM table
SELECT MIN(score), id AS lowest_id FROM table
then
insert or replace into table (id, ...) values ( MIN(last_id+1, lowest_id), ... )
there are possible mistakes and also only one subquery is possible, but I hope you get the main idea
The simplest way imo is to insert data,
INSERT INTO top_scores (user_id, person_id, score_id) VALUES (1,2,3)
then delete inappropriate rows
DELETE top_scores FROM top_scores
INNER JOIN
(SELECT * FROM top_scores WHERE person_id = 2 ORDER BY score ASC LIMIT 5, 1000000) AS inappropriate_rows
USING (user_id, person_id, score)

Mysql: Insert Procedure with two tables (FK)

Im trying to make an stored Procedure that makes an insert into tables.
The insert effects two tables and there is an FK between them.
CREATE PROCEDURE `db`.`add_user_hr` (
IN in_Pass VARCHAR(45),
IN in_Value VARCHAR(45),
IN in_HR_ID INT,
)
BEGIN
INSERT INTO HR
(
Value
)
VALUES
(
in_Value
);
INSERT INTO User
(
Password,
HR_idHR
)
VALUES
(
in_Pass,
(Get the ID from HR)
);
END
How do I make sure that the correct id gets into User. And
if there is a error in the insert into HR, who do I make
sure it dosent tyr to make an insert into User? Ive
looked into "commit" but don't know how it's used.
Or is there a better way to do this?
In this example I have table UserType. Is this needed to
to find out witch type of user it is later on? And
how do I user this in the insert, select procedure in the
future?
Thx for all the help!
If PK (primary key) has AUTO_INCREMENT options than you can do something like this:
declare value_id_v INT;
insert into hr(value) values(value_in);
set value_id_v = last_insert_id();
Now you can use value_id_v to do inserts. Here is the link to read about this function LAST_INSERT_ID