Slope-One recommender implementation using mysql stored procedure - mysql

I am trying to implement Slop-One recommender using mysql stored procedure, the query runs okay and doesn't give any error. But it is not inserting/updating the 'dev' table.
The structure of tables are:
rating (user_id, article_id, rating_value, date)
dev (article1_id, article2_id, count, sum)
The 'dev' table has joint primary key (article1_id, article2_id). The sql for my procedure is as follows:
DELIMITER $$
CREATE PROCEDURE update_matrix(IN user INT(11), IN article INT(11), IN rating TINYINT(1))
BEGIN
DECLARE article_id2 INT(11);
DECLARE rating_diff TINYINT(1);
DECLARE done TINYINT(1) DEFAULT 0;
DECLARE mycursor CURSOR FOR
SELECT DISTINCT article_id, (rating - rating_value)
FROM rating
WHERE user_id = user AND article_id != article;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN mycursor;
FETCH mycursor INTO article_id2, rating_diff;
WHILE(!done) DO
INSERT INTO dev (`article1_id`, `article2_id`, `count`, `sum`)
VALUES (article, article_id2, 1, rating_diff)
ON DUPLICATE KEY UPDATE count = count + 1, sum = sum + rating_diff;
INSERT INTO dev (`article1_id`, `article2_id`, `count`, `sum`)
VALUES (article_id2, article, 1, -rating_diff)
ON DUPLICATE KEY UPDATE count = count + 1, sum = sum - rating_diff;
FETCH mycursor INTO article_id2, rating_diff;
END WHILE;
CLOSE mycursor;
END$$
DELIMITER ;

Related

mysql procedure with if condition

I'm in my first databases class and I'm trying to write a conditional block for a mysql procedure.
This is the procedure:
delimiter //
CREATE PROCEDURE add_ascent(IN cid INT, IN pid INT)
BEGIN
DECLARE count_ascents INT;
SET count_ascents = 0;
SELECT COUNT(`cid`) INTO count_ascents FROM ascents WHERE `cid`=cid AND `pid`=pid;
IF count_ascents < 1 THEN
INSERT INTO ascents (`cid`, `pid`) VALUES (cid, pid);
UPDATE climbers SET climbers.ascents = climbers.ascents + 1 WHERE climbers.id=cid;
UPDATE problems SET problems.ascents = problems.ascents + 1 WHERE problems.id=pid;
END IF;
END;
//
delimiter ;
The goal of the procedure is to only perform the insert and updates if the (cid, pid) pair is not in the the ascents database. After testing, the program doesn't seem to go into the if block at all.
FYI, you might want to consider using an UPSERT, instead of "select/if/insert". For example, mySQL offers INSERT ON DUPLICATE KEY UPDATE.
Here, I suggest:
giving your parameters a DIFFERENT name than the column name, for example iCid and iPid, then
Typing SELECT COUNT(cid) INTO count_ascents FROM ascents WHERE cid=iCid AND pid=iPid and checking the result.

declaring variable inside mysql stored procedure

we are trying to declare a variable inside mysql stored procedure that has transaction implemented in it. but it seems to be giving a syntax error :
following is the syntax of the stored procedure:
CREATE PROCEDURE `sp_MarkAppointmentRefferal`(
p_AppId bigint,
p_NewLocation bigint,
p_userId bigint,
p_ReferralReason varchar(500),
p_NewLocationName varchar(100)
)
begin
declare v_OldLocation int default 0;
set v_OldLocation = (select LocationId FROM appointments where iAppID = p_AppId limit 1 );
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
select -1;
END;
START TRANSACTION;
update table
set is_referred = 1,
referred_timestamp = now(),
referral_reason = p_ReferralReason
where iAppID = p_AppId
limit 1;
-- create a new appointment for the new referred location..
insert into appointments
(vAppName, vAppType, dAppDate, vCell, iPatID, iAppStatus, iuserid, iActive,
dInsertDate, iHSID, daily_ticket_no, LocationId, visit_id, encounter_id, ReferredFrom,ReferredOPDName, opd_name )
select vAppName, vAppType, now(), vCell, iPatID, iAppStatus, p_userId,
1, now(), iHSID, fn_GenerateNextAppointmentTicket(now(),p_NewLocation) , p_NewLocation, visit_id, encounter_id+1,
(select LocationId FROM appointments where iAppID = p_AppId limit 1),
(select OPD_Name FROM appointments where iAppID = p_AppId limit 1), p_NewLocationName
FROM appointments
where iAppID = p_AppId limit 1;
select LAST_INSERT_ID();
COMMIT;
end;
the syntax checker is saying that declare command is not valid here.
have also tried to place this inside the transaction clause and similar error shows up ..
any help is appreciated..
All declare statements should be at the top of the stored procedure body. Moving DECLARE EXIT HANDLER before the SET statement should fix the problem.

MySQL stored procedure if statement not working

I have the following stored procedure in MySQL
CREATE DEFINER=`test_db`#`%` PROCEDURE `ADD_ATTENDANCE`(IN `programID` INT, IN `clientID` INT, IN `insDate` DATETIME, IN `updDate` DATETIME, IN `insUser` INT, IN `updUser` INT, IN `lessonDate` DATE, IN `lessonTime` TIME)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT 'Add attedance to my calendar'
BEGIN
DECLARE max_sub, availability INT;
DECLARE cursor_max_sub CURSOR FOR SELECT max_sub FROM app_lesson WHERE id = programID;
DECLARE cursor_availability CURSOR FOR SELECT count(*) FROM attendance WHERE program_id = programID AND lesson_date = lessonDate AND lesson_time = lessonTime;
OPEN cursor_max_sub;
OPEN cursor_availability;
read_loop: LOOP
FETCH cursor_max_sub INTO max_sub;
FETCH cursor_availability INTO availability;
IF (availability < max_sub) THEN
insert into attendance (program_id, client_id, ins_date, upd_date, ins_user, upd_user, lesson_date, lesson_time)
values (programID, clientID, insDate, updDate, insUser, updUser, lessonDate, lessonTime);
LEAVE read_loop;
ELSE
insert into attendance_hold (program_id, client_id, ins_date, upd_date, ins_user, upd_user, lesson_date, lesson_time)
values (programID, clientID, insDate, updDate, insUser, updUser, lessonDate, lessonTime);
END IF;
END LOOP;
CLOSE cursor_max_sub;
CLOSE cursor_availability;
END;
Even though the cursor_max_sub is equal to 6 and the cursor_availability is equal to 4 my procedure always executes the else insert statement. Can you please help me out?
Thanks!!!
OK that was tricky... For some reason when i change the max_sub variable into maxNumberOfSubscription everything worked perfectly... Is max_sub some kind of reserved key word for MySQL or there was a complication because my variable had the same name with the returned field of select statement?

Stored Procedure taking ages to execute?

DELIMITER $$
CREATE PROCEDURE Load_Fact_List()
BEGIN
DECLARE Project_Number_Temp INT;
DECLARE Panel_Id_Temp INT;
DECLARE Employee_Id_Temp INT;
DECLARE Zip_Temp VARCHAR(255);
DECLARE Created_Date_Temp DATE;
DECLARE Country_Temp VARCHAR(255);
DECLARE no_more_rows BOOLEAN;
DECLARE loop_cntr INT DEFAULT 0;
DECLARE num_rows INT DEFAULT 0;
DECLARE load_cur CURSOR FOR
SELECT Project_Id, Panel_Id, Employee_Id, Zip, Created_Date
FROM Fact_List;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_more_rows = TRUE;
OPEN load_cur;
select FOUND_ROWS() into num_rows;
the_loop: LOOP
FETCH load_cur
INTO Project_Number_Temp, Panel_Id_Temp, Employee_Id_Temp, Zip_Temp, Created_Date_Temp;
IF no_more_rows THEN
CLOSE load_cur;
LEAVE the_loop;
END IF;
SET Country_Temp= (select Country from Zip where Zip= Zip_Temp);
INSERT INTO Test_Fact
(
Project_Key,
Campaign_Key,
Respondents_Key,
Event_Key,
Employee_Key,
Geography_Key,
Date_Key
)
SELECT (SELECT Project_Key from Project_Dim where Project_Id= Project_Number_Temp AND Quota_Country= Country_Temp),0,(SELECT MAX(Respondents_Key) from Respondents_Dim WHERE Panel_Id= Panel_Id_Temp),1,(select MAX(Employee_Key) from Employee_Dim WHERE Employee_Id= Employee_Id_Temp),(Select Geography_Key from Geography_Dim where Zip= Zip_Temp), (Select Date_Key from Date_Dim where Full_Date= Created_Date_Temp);
SET loop_cntr = loop_cntr + 1;
END LOOP the_loop;
select num_rows, loop_cntr;
END $$
The above code is properly working but it is damn slow. For every 1 hour it is loading 1000 records. I got lacks of records to load into fact table. can anyone suggest me any optimization?
Requirement is to load fact table by looping through other table and gathering required key values from dimension tables.
The usual procedure is actually like this.
You have your dimensions built and you just gathered the data you want to insert into your fact table in a temporary table. Then you insert this data in another temporary table like this:
INSERT INTO tmp_fact_table
(
fact_key,
dim1_key,
dim2_key,
...
fact1,
fact2
...
)
SELECT
ISNULL (f.fact_key, 0),
ISNULL (d1.sid, 0) as whatever,
ISNULL (d2.sid, 0) as whatever2,
...
ISNULL (tt.fact1, 0),
ISNULL (tt.fact2, 0)
FROM
yourTempTable tt
LEFT JOIN Dim1 d1 ON tt.identifying_column = d1.identifying_column
...
LEFT JOIN fact_table f ON
f.dim1_key = d1.sid
AND f.dim2_key = d2.sid
where
fact_key is the identifying column in your fact table
dim1_key is the foreign key in your fact table to the dimensions
fact1 and so on are the facts you want in your fact table, clear
the ISNULL() function returns 0 when no entry is found. 0 is the id of your dummy row in each dimension for unknown data
Then you will have a table where you have the IDs of your dimensions linked to the data you want to import into your fact table with 0 as fact key when the entry in the fact table does not already exist and the ID of the fact table entry otherwise.
Then you update the fact table where tmp_fact_table.fact_key != 0
Then you insert into the fact table where tmp_fact_table.fact_key = 0
That's it.
I'm doing this with millions of rows and it takes about half an hour. 300,000 rows is peanuts.

Temporary table definition in MySQL

I have a stored procedure which uses temporary tables so that I can summarize the sales of all the products within a certain product category. When I tried to run the code it failed. I search on google and here on stackoverflow but couldn't find what I had done wrong. I'm using MySQL server 5.5 on Windows Server.
CREATE PROCEDURE `getStatistics`(IN `startDate` date,IN `endDate` date,IN `categoryName` varchar)
BEGIN
CREATE TEMPORARY TABLE procResult(productName VARCHAR, amount INT);
CREATE TEMPORARY TABLE tblProductID(SELECT ID, `name` FROM product WHERE categoryID = (SELECT ID FROM category WHERE `name` = categoryName));
DECLARE done_amt, done_PID INT DEFAULT FALSE;
DECLARE amount, productID INT DEFAULT 0;
DECLARE pidCursor CURSOR FOR SELECT ID, `name` FROM tblProductID;
DECLARE amtCursor CURSOR FOR SELECT orderlines.amount FROM orderlines WHERE orderlines.productID = productID;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done_amt = TRUE;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done_PID = TRUE;
OPEN pidCursor;
pid_loop:LOOP
DECLARE productName VARCHAR;
FETCH pidCursor INTO productID, productName;
IF done_PID THEN
LEAVE pid_LOOP;
END IF;
OPEN amtCursor;
amt_loop:LOOP
DECLARE tmpAmount INT DEFAULT 0;
FETCH amtCursor INTO tmpAmount;
IF done_amt THEN
LEAVE amt_loop;
END IF;
amount = amount + tmpAmount;
END LOOP;
CLOSE amtCursor;
IF amount > 0 THEN
INSERT INTO procResult VALUES (productName, amount);
amount = 0;
END IF;
END LOOP;
CLOSE pidCursor;
END;
You must define the length of VARCHAR type variables, such as the categoryName parameter to your stored procedure;
You must DECLARE all local variables at the very start of a BEGIN ... END compound statement block, before any other commands;
Your syntax for CREATE TABLE ... SELECT is incorrect;
You have declared two handlers for the same SQL condition, only one of which will be executed (indeterminately);
You will need to change your client's statement delimiter in order for it to understand that the semicolons appearing within the procedure body do not terminate the CREATE PROCEDURE statement;
Your entire procedure is an extremely complicated way of doing a fairly simple task in SQL:
CREATE TEMPORARY TABLE procResult
SELECT product.name, SUM(orderlines.amount) AS amount
FROM orderlines
JOIN product ON product.ID = orderlines.productID
JOIN category ON category.ID = product.categoryID
WHERE category.name = ?
GROUP BY product.ID
HAVING amount > 0