Result consisted of more than one row error mysql - mysql

I am trying to get the next available id through a stored procedure but so far I cant make this to work. This is my stored procedure
DELIMITER $$
USE `devt`$$
DROP PROCEDURE IF EXISTS `updateid`$$
CREATE DEFINER=`root`#`%` PROCEDURE `updateid`(IN `tran_id` VARCHAR(15), IN `typ` VARCHAR(15), OUT `lid` VARCHAR(15))
BEGIN
DECLARE id VARCHAR(15);
SET id = '';
SELECT TranID FROM journal WHERE TranID = tranid INTO id;
read_loop: LOOP
SELECT TranID FROM journal WHERE TranID = id INTO id;
IF id = tran_id THEN
UPDATE journaltype SET journaltype.NextRefNbr = journaltype.NextRefNbr + 1 WHERE journaltype.JournalType = typ;
SELECT journaltype.NextRefNbr FROM journaltype WHERE journaltype.JournalType = typ INTO id;
ITERATE read_loop;
ELSE
SET lid= id;
LEAVE read_loop;
END IF;
END LOOP;
END$$
DELIMITER ;**strong text**
when i run the query CALL updateid('17000001','GJ', #test) i get an error Result consisted of more than one row

This error probably means that you either have multiple entries with the same TranID in table journal or multiple entries with the same JournalType in table journaltype.
When using the SELECT...INTO... syntax you have to be sure that the returned resultset will not consist of more than one rows.

ONE of your SELECT statement is returning more than one row you need to be more clear on results for example
Instead of using this :
SELECT journaltype.NextRefNbr FROM journaltype WHERE journaltype.JournalType = typ INTO id;
Use this :
SELECT journaltype.NextRefNbr FROM journaltype WHERE journaltype.JournalType = typ INTO id LIMIT 1;
this will resolve your error!.
Try to use in every SELECT statement if it is using no indexed column in WHERE clause

Related

MySQL query update with subquery multiple values

I need to update a table based on the result of a subquery that brings more than 1 value, but with the query below I get the error return "Subquery returns more than 1 row". I would like to know if it is possible to make a "loop" to update the values ​​with each result presented in my subquery below.
Complete Query
UPDATE estoque_tamanhos tam
SET tam.qtde = tam.qtde - IF(NEW.tipo = 'K', NEW.qtde_prod * NEW.qtde_lote, NEW.qtde_prod)
WHERE tam.estoques_id = (SELECT estoques_id
FROM combo_estoque
WHERE produtos_id = NEW.produtos_id)
AND UPPER(tam.tamanho) = UPPER(NEW.tamanho_prod);
Subquery that returns 2 or more values.
SELECT estoques_id FROM combo_estoque WHERE produtos_id = NEW.produtos_id
Result
produtos_id
estoques_id
246
54
246
207
In the ideal scenario, my query would execute the first value, after the second ... third ... without repeating the previous ones.
You should create a stored procedure using Cursors to iterate each result of your query.
CREATE PROCEDURE UPDATING_ROWS(PRODUTO_ID INT, qtde_prod INT, qtde_lote INT, TIPO INT)
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE estoque_;
DECLARE cursor FOR SELECT estoques_id FROM combo_estoque WHERE produtos_id = NEW.produtos_id) AND UPPER(tam.tamanho) = UPPER(NEW.tamanho_prod)
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO estoque_;
IF done THEN
LEAVE read_loop;
END IF;
UPDATE estoque_tamanhos tam SET tam.qtde = tam.qtde - IF(TIPO = 'K',
qtde_prod * qtde_lote, qtde_prod)
WHERE tam.estoques_id = estoque_;
END LOOP;
END
You have to create a stored procedure like this to iterate each result of your select query. You can read more about this in this link

Foreach Data in Field Insert Selected Field from One Database to Another in MySQL

I have two (2) databases of dissimilar Schematics,
db1 migrated from MSSQL to MYSQL
and
db2 created from Laravel Migration.
Here's the challenge:
The tables of db1 do not have id columns (Primary Key) like is easily found on db2 tables. So I kept getting the warning message:
Current selection does not contain a unique column. Grid edit, checkbox, Edit, Copy and Delete features are not available.
So I had to inject the id columns on the tables in the db1
I need to extract fields [level_name, class_name] from stdlist in db1,
Create levels (id,level_name,X,Y) on db2
classes (id,class_name,level_id) on db2
To throw more light: The level_id should come from the already created levels table
I have already succeeded in extracting the first instance using the following snippet:
First Query to Create Levels
INSERT INTO db2.levels(level_name,X,Y)
SELECT class_name as level_name,1 as X,ClassAdmitted as Y
FROM db1.stdlist
GROUP BY ClassAdmitted;
This was successful.
Now, I need to use the newly created ids in levels table to fill up level_id column in the classes table.
For that to be possible, must I re-run the above selection schematics? Is there no better way to maybe join the table column from db1.levels to db2.stdlist and extract the required fields for the new insert schematics.
I'll appreciate any help. Thanks in advance.
Try adding a column for Processed and then do a while exists loop
INSERT INTO db2.levels(level_name,X,Y)
SELECT class_name as level_name,1 as X,ClassAdmitted as Y, 0 as Processed
FROM db1.stdlist
GROUP BY ClassAdmitted;
WHILE EXISTS(SELECT * FROM db2.levels WHERE Processed = 0)
BEGIN
DECLARE #level_name AS VARCHAR(MAX)
SELECT TOP 1 #level_name=level_name FROM db2.levels WHERE Processed = 0
--YOUR CODE
UPDATE db2.levels SET Processed=1 WHERE level_name=#level_name
END
You may need to dump into a temp table first and then insert into your real table (db2.levels) when you're done processing. Then you wouldn't need the Unnecessary column of processed on the final table.
This is what worked for me eventually:
First, I picked up the levels from the initial database thus:
INSERT INTO db2.levels(`name`,`school_id`,`short_code`)
SELECT name ,school_id,short_code
FROM db1.levels
GROUP BY name
ORDER BY CAST(IF(REPLACE(name,' ','')='','0',REPLACE(name,' ','')) AS UNSIGNED
INTEGER) ASC;
Then I created a PROCEDURE for the classes insertion
CREATE PROCEDURE dowhileClasses()
BEGIN
SET #Level = 1;
SET #Max = SELECT count(`id`) FROM db2.levels;
START TRANSACTION;
WHILE #Level <= #Max DO
BEGIN
DECLARE val1 VARCHAR(255) DEFAULT NULL;
DECLARE val2 VARCHAR(255) DEFAULT NULL;
DECLARE bDone TINYINT DEFAULT 0;
DECLARE curs CURSOR FOR
SELECT trim(`Class1`)
FROM db1.dbo_tblstudent
WHERE CAST(IF(REPLACE(name,' ','')='','0',REPLACE(name,' ','')) AS UNSIGNED INTEGER) =#Level
GROUP BY `Class1`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET bDone = 1;
OPEN curs;
SET bDone = 0;
REPEAT
FETCH curs INTO val1;
IF bDone = 0 THEN
SET #classname = val1;
SET #levelID = (SELECT id FROM db2.levels WHERE short_code=#Level limit 1);
SET #schoolId = 1;
SET #classId = (SELECT `id` FROM db2.classes where class_name = #classname and level_id= #levelID limit 1);
IF #classId is null and #classname is not null THEN
INSERT INTO db2.classes(class_name,school_id,level_id)
VALUES(#classname,#schoolId,#levelID);
END IF;
END IF;
UNTIL bDone END REPEAT;
CLOSE curs;
END;
SELECT CONCAT('lEVEL: ',#Level,' Done');
SET #Level = #Level + 1;
END WHILE;
END;
//
delimiter ;
CALL dowhileClasses();
With this, I was able to dump The classes profile matching the previously created level_ids.
The whole magic relies on the CURSOR protocol.
For further details here is one of the documentations I used.

change one table data when single column all data of another table is equal to some value in mysql

I have created 2 tables named snag_list and defect_list. I need to change the status field of snag_list to 2 when all the defect_list status should to be 2
Not sure if this helps but try to create a trigger for defect_list
and check the distinct count of status column if it is one and the value is 2 then update the snag_list a example would look like this
DELIMITER $$
CREATE TRIGGER checkstatus
AFTER UPDATE ON defect_list
FOR EACH ROW
BEGIN
DECLARE cnt INT
SELECT COUNT(DISTINCT status) FROM defect_list INTO cnt
DECLARE st INT
SELECT DISTINCT status FROM defect_list LIMIT 1 INTO st
IF(cnt = 1 AND st = 2)
UPDATE snag_list SET status = 2
ENF IF
END$$
DELIMITER ;
Your question is very vague but I guess this is what you may be looking for.
DECLARE
count_rec VARCHAR2(10);
data_rec VARCHAR2(10);
BEGIN
SELECT COUNT(DISTINCT status) INTO count_rec FROM defect_list;
SELECT DISTINCT status INTO data_rec FROM defect_list;
IF (count_rec = '1' AND data_rec = '2') THEN
UPDATE snag_list SET status = '2';
END IF;
END;
edit -> You can change the datatype of the 2 variables as required. Go with VARCHAR2 if you're unsure whether the data would be numeric.

How to find problems in MySQL stored procedure?

I have the following stored procedure:
DELIMITER $$
CREATE DEFINER=`195414_py82740`#`%` PROCEDURE `getUserMail`(inUserId INT)
BEGIN
DECLARE done INT default 0;
DECLARE tmpMailId INT default -1;
DECLARE tmpFromUserId INT default -1;
DECLARE cursor1 cursor for select id from mail WHERE toUserId=inUserId OR fromUserId=inUserId ORDER BY sentDate desc;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DROP TEMPORARY TABLE IF EXISTS temp_userMail;
CREATE TEMPORARY TABLE temp_userMail LIKE mail;
OPEN cursor1;
REPEAT
FETCH cursor1 INTO tmpMailId;
SET tmpFromUserId = IF ((SELECT fromUserId FROM mail WHERE id=tmpMailId)=inUserId, (SELECT toUserId FROM mail WHERE id=tmpMailId), (SELECT fromUserId FROM mail WHERE id=tmpMailId));
IF EXISTS(SELECT id FROM temp_userMail WHERE fromUserId=tmpFromUserId || toUserId=tmpFromUserId) THEN
SET tmpMailId = 0;
ELSE
INSERT INTO temp_userMail
(`id`,
`fromUserId`,
`toUserId`,
`sentDate`,
`readDate`,
`message`,
`fromUserNickName`,
`toUserNickName`,
`subject`,
`fromUserDeleted`,
`toUserDeleted`)
SELECT
(m1.id,
m1.fromUserId,
m1.toUserId,
m1.sentDate,
m1.readDate,
m1.message,
m1.fromUserNickName,
m1.toUserNickName,
m1.subject,
m1.fromUserDeleted,
m1.toUserDeleted)
FROM mail m1
WHERE m1.id=tmpMailId;
END IF;
UNTIL(done = 1)
END REPEAT;
CLOSE cursor1;
SELECT * FROM temp_userMail ORDER BY sentDate DESC;
END
The SP is saved successfully but when running it I get the cryptic exception
Error Code: 1241: Operand should contain 1 column(s).
I know what the error means but there is no line nr so I have no idea where to look for the problem?
Remove brackets from Your SELECT subquery
dont use
SELECT (id, ... m1.toUserDeleted) ...
use
SELECT id, ... m1.toUserDeleted ...

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