Result consisted of more than one row Error 1172 mysql - mysql

Hello im having a hard time with this stored procedure. im getting the error:
Result consisted of more than one row.
here is my stored procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS `dss`.`COSTRET` $$
CREATE DEFINER=`dwadmin`#`192.168.%.%` PROCEDURE `COSTRET`( TDATE DATE)
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE ls_id VARCHAR(8);
DECLARE ld_cost DECIMAL(10,4);
DECLARE ld_retail DECIMAL(10,4);
DECLARE cur1 CURSOR FOR SELECT DISTINCT `id` FROM `prod_performance` WHERE `psc_week` = TDATE;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
-- Get the Cost
CREATE TEMPORARY TABLE IF NOT EXISTS `prod_itemcost`
SELECT DISTINCTROW `itemcode` ID, `mlist` COST
FROM (SELECT `itemcode`, `pceffdate`, `mlist`
FROM `purchcost` a
where `pceffdate` = (SELECT MAX(z.`pceffdate`) FROM `purchcost` z WHERE z.`itemcode` = a.`itemcode`
AND z.`pceffdate` <= TDATE)) tb
ORDER BY `itemcode`;
OPEN cur1;
REPEAT
FETCH cur1 INTO ls_id;
IF NOT done THEN
SELECT DISTINCTROW `cost` INTO ld_cost FROM `prod_itemcost` WHERE id = ls_id;
UPDATE LOW_PRIORITY `prod_performance` SET `current_cost` = ld_cost WHERE `psc_week` = TDATE and `id` = ls_id;
END IF;
UNTIL done END REPEAT;
CLOSE cur1;
-- Destroy Temporary Tables
DROP TEMPORARY TABLES IF EXISTS `prod_itemcost`;
END $$
DELIMITER ;
Any solutions and recommendations are much appreciated!

I'd say the problem is here :
SELECT DISTINCTROW `cost` INTO ld_cost FROM `prod_itemcost` WHERE id = ls_id;
and caused by this returning more than one row.
How you solve it depends on your requirements. Does the existence of multiple rows imply the database is in need of some cleaning, for example? Or should you be taking the first value of 'cost', or perhaps the sum of all 'cost' for id = ls_id?
Edit :
Your INTO clause is attempting to write multiple rows to a single variable. Looking at your SQL, I'd say the underlying problem is that your initial query to pull back just the latest cost for each ID is being hamstrung by duplicates of pceffdate. If this is the case, this SQL :
SELECT DISTINCTROW `itemcode` ID, `mlist` COST
FROM (SELECT `itemcode`, `pceffdate`, `mlist`
FROM `purchcost` a
where `pceffdate` = (SELECT MAX(z.`pceffdate`) FROM `purchcost` z WHERE z.`itemcode` = a.`itemcode`
AND z.`pceffdate` <= TDATE)) tb
will return more rows than just this :
SELECT DISTINCTROW `itemcode` ID
FROM (SELECT `itemcode`, `pceffdate`, `mlist`
FROM `purchcost` a
where `pceffdate` = (SELECT MAX(z.`pceffdate`) FROM `purchcost` z WHERE z.`itemcode` = a.`itemcode`
AND z.`pceffdate` <= TDATE)) tb

This line
SELECT MAX(z.`pceffdate`) FROM `purchcost` z WHERE z.`itemcode` = a.`itemcode`
AND z.`pceffdate` <= TDATE
has got to be the problem. It must be returning more than 1 row. So, the DBMS is trying to set multiple values to the same thing, which of course it cannot do.
Do you need something else in your WHERE clause there?

The problem is that
SELECT DISTINCTROW `itemcode` ID, `mlist` COST
could store multiple costs against each ID, and so
SELECT DISTINCTROW `cost` INTO ld_cost FROM `prod_itemcost` WHERE id = ls_id;
could return multiple rows for each id.
For example, if purchcost contained the following:
itemcode mlist pceffdate
1 10.99 10-apr-2009
1 11.99 10-apr-2009
1 9.99 09-apr-2009
Then temporary table prod_itemcost would contain:
itemcode mlist
1 10.99
1 11.99
These both being values that were in effect on the most recent pceffdate for that itemcode.
This would then cause a problem with selecting mlist into ld_cost for itemcode 1 because there are two matching values, and the scalar ld_cost can only hold one.
You really need to look at the data in purchcost. If it is possible for 1 item to have more than one entry with different mlist values for the same date/datetime, then you need to decide how that should be handled. Perhaps take the highest value, or the lowest value, or any value. Or perhaps this is an error in the data.

There is another possibility, that is your parameter "TDATE" same as table field name in uppercase or lowercase or mixed. such as 'tdate', 'tDate', 'TDATE'.
so you should check that. I hit this before.

You are inserting an array in a variable instead of a single value that's why its problem occurs.
Like:
DECLARE name varchar;
select f_name into name from student;
here name will accept only single name instead of multiple name;

Related

UPDATE COALESCE query with null values

Definitely a basic question, but I couldn't find an example.
I'm writing a procedure which merges two rows into the good row. It moves all child rows' ids to being the correct one, replaces all NULL values with available values in the row being removed before finally deleting the 'bad' row.
What I have so far is this:
CREATE DEFINER=`danielv`#`%`
PROCEDURE `emp_merge`(IN `#core_emp_id` int, IN `#bad_emp_id` int)
BEGIN
UPDATE claim SET employee_id = #core_emp_id
WHERE employee_id = #bad_emp_id;
WITH bad_employee_values AS (
SELECT * FROM employee WHERE employee_id = #bad_emp_id
)
UPDATE employee SET
employee.employment_date = COALESCE(employee.employment_date, bad_employee_values.employment_date),
WHERE employee_id = #core_emp_id;
DELETE FROM employee WHERE employee_id = #bad_emp_id;
END
However, I'm getting non-descript error messages and I'm not sure why. I suspect there's an issue with how I'm handling my CTE and coalesce function, but I'm not sure where the gap in my understanding is.
In this statement :
WITH bad_employee_values AS (SELECT * FROM employee WHERE employee_id = #bad_emp_id)
UPDATE employee SET
employee.employment_date = COALESCE(employee.employment_date, bad_employee_values.employment_date),
WHERE employee_id = #core_emp_id;
You are defining CTE bad_employee_values but you are not using it in the UPDATE part of the query, hence you cannot access its columns : for MySQL, bad_employee_values.employment_date is unknown.
It looks like you could simply avoid a CTE here. You could just self-join the table, like so :
UPDATE employee e_core
INNER JOIN employee e_bad ON e_bad.employee_id = #bad_emp_id
SET e_core.employment_date = e_bad.employment_date,
WHERE employee_id = #core_emp_id AND e_core.employment_date IS NULL
This query will simply select the record identified by #core_emp_id, join it with the corresponding "bad" record, and copy the value of employment_date. The second condition in the WHERE clause prevents records whose employment_date is not null from being selected.

Updating 180k rows via MySQL stored procedure & function is too slow - how to speed up

I have the following stored procedure:
CREATE DEFINER=`ST`#`%` PROCEDURE `CalculateCheapestPriceALL`()
BEGIN
UPDATE
tickets
SET
tickets.Cheapest = GetCheapestTicket(tickets.STPerformerID, tickets.STVenueID, tickets.FeedID);
END
The function GetCheapestTicket is as follows:
CREATE DEFINER=`suprtickets`#`%` FUNCTION `GetCheapestTicket`(performerID INT(11), venueID INT(11), feedID INT(11)) RETURNS decimal(10,2)
BEGIN
DECLARE TicketPrice DECIMAL(10,2);
SET TicketPrice =
IFNULL((
SELECT
MIN(tickets.Price)
FROM
tickets
WHERE
tickets.STPerformerID = performerID
AND
tickets.STVenueID = venueID
AND
tickets.FeedID = feedID
AND
tickets.Price > 0
),0);
RETURN TicketPrice;
END
Running the stored procedure currently takes about 10 minutes, and I'm looking for ways to speed this up.
The following image shows a sample of the data:
The idea behind the stored procedure is to find the cheapest price for the same STPerformerID and STVenueID, and then update this in the Cheapest column. So then I can quickly look up the lowest price for each peformer and venue.
There are about 20k individual Perfomers, and a similar amount of Venues.
Thanks for your help.
Your basic problem is that you are running the query to find the lowest price over again for every row, which is very inefficient.
If you combine the two queries into one query. it will execute significantly faster:
UPDATE tickets AS t1
JOIN (SELECT STPerformerID, STVenueID, STFeedID, MIN(Price) AS cheapest
FROM tickets
WHERE Price > 0
GROUP BY STPerformerID, STVenueID, STFeedID) AS t2
USING (STPerformerID, STVenueID, STFeedID)
SET t1.Price = t2.cheapest
To make it perform well, make sure you have a composite index on (STPerformerID, STVenueID, STFeedID) (or at least some subset of these columns).

MYSQL DATABASE create procedure

have a question for you guys,
trying to make a procedure for my mysql table but I need some assistance ...
IM completely block ...
I need to create a procedure that will show the parents name in my table but the table show parents id
ex.
(DELIMITER //
CREATE PROCEDURE fetch_animal_parents (IN animal_id INT, OUT animal_name VARCHAR(10))
BEGIN
DECLARE animal_mom INT DEFAULT 0 ;
DECLARE animal_dad INT DEFAULT 0 ;
DECLARE animal_name_mom VARCHAR(10) ;
DECLARE animal_name_dad VARCHAR(10) ;
SELECT name INTO animal_name, (SELECT name FROM animal WHERE id = child.mother_id) INTO animal_name_mom,
(SELECT name FROM animal WHERE id = child.father_id) INTO animal_name_dad
FROM animal AS child ;
END //)
What im doing wrong ....
................................................................................................
Any input ...
1) why do you select mom/dad's name when you are not using them anywhere?
2) I imagine your procedure should take an child animal id as input and give mom & dad's name as output(that's what you procedure name suggest). In that case you need to either have 2 output value or you need to concatenate those names into 1 variable and return them.
3) #VMai suggested a 2 join format which I would agree. The query will be something like..
SELECT mom.name,dad.name INTO animal_name_mom, animal_name_dad
FROM (select mother_id,father_id from animal where id = <precedure_input>) AS `child`
INNER JOIN (select id,name from animal) AS `mom` ON (mom.id=child.mother_id)
INNER JOIN (select id,name from animal) AS `dad` ON (dad.id=child.father_id)
I see that you have as least tried something on your own (thou very confused). I'd suggest you to start with learning some basic syntax/keyword/functions of mysql before trying procedures. Learn to use GROUP BY, variations of JOIN and you could handle a lot of basic querys.

how to fetch table records and store in variable in sql server and extract each record

I have 3 tables
Category(Category_ID,Category_Name,Parent,Category_Tag)
News_Category(ID,News_ID,Category)
News(News_ID,Title,Article,News_Tags)
I want to fetch all Category_Tag from Category Table where News_ID=72. I am using following query in sql server:
DECLARE #cat varchar(100)
SET #cat=(select Category_Tag
from Category
where Category_ID in(
select Category
from News_Category
inner join Category on Category.Category_ID = News_Category.Category
where News_ID=72
)
)
but this query is not working for me it is showing error as:- Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
.Also i want to extract each single record from the above query to update News table column News_Tags.Suppose the News_Tags column in News table contains value "Tejpal" and the above query returning two values- National and Interbational. then the final value should be stored in News_Tags Column of News Table as Tejpal,National,International
Please help me here
The error here is pretty descriptive. You have declared a scalar variable which is designed to hold a single value, and you are trying to insert multiple rows into that variable.
You need to either do one of two things, either use a temporary table such as
DECLARE #Cat TABLE (CategoryTag VARCHAR(1000));
INSERT INTO #Car
SELECT C.Category_Tag
FROM Category C
INNER JOIN News_Category N ON N.Category = C.CategoryID
WHERE N.News_ID = 72
or you can concatenate the values to be a single string.
I think in this case you might be looking for the second option which would look something like this. This code is mostly psuedo taking from another script I have, but it should put you on the right track.
DECLARE #CategoryTags VARCHAR(1000);
SET #CategoryTags = (
SELECT STUFF((
SELECT ISNULL(Category_Tag, 'NullTag')
FROM Category C
INNER JOIN News_Category N ON N.Category = C.CategoryID
WHERE N.News_ID = N1.NewsID
FOR XML PATH (''),TYPE).value('(./text())[1]','VARCHAR (MAX)')
,1,0,'') [Categories]
FROM News_Category N1
WHERE N1.News_ID = 72
UPDATE News_Category
SET NewTags = NewTags + #CategoryTags
WHERE News_ID = 72
This might help you.
DECLARE #combinedString VARCHAR(MAX)
SELECT #combinedString = COALESCE(#combinedString + CHAR(13) + CHAR(10), '') + ISNULL(Category_Tag, 'NullTag')
FROM Category
select #combinedString

How can I delete MySQL records which have a field which is not numeric?

Due to a data corruption, we have a database field (Mysql 5) which has been populated with text. Its a custom field in the ExpressionEngine CMS and was not set as numeric only. I need to delete only those records for which this field has been incorrectly populated. It contains a URL instead of an ID e.g. 10937.
I need to run a query / stored procedure which will find only those records which have been incorrectly populated i.e do not contain a numeric ID and delete those records, plus linked records in another table.
I would welcome advice on the best way to do this. I could do it from PHP but was hoping to do it in a stored procedure as this would be a useful skill to learn. This question has details of a function which can test if a field is numeric. But I actually need the opposite.
The query I have which will select the records in question is:
SELECT field_id_58 as 'release_id' , ewt.entry_id FROM exp_weblog_data ewd
LEFT JOIN exp_weblog_titles ewt ON ewt.`entry_id` = ewd.`entry_id`
WHERE ewt.weblog_id = 15
This returns all the cms entry_ids I am dealing with, including the ones I want to delete. The field with the incorrect data is field_id_58. The fact that this field has been incorrectly populated means we now have duplicate records in tables ewt and ewd.
Here's what I have so far:
DELIMITER //
CREATE PROCEDURE `proc_DEL_DUPLICATE_PR`
BEGIN
DECLARE empty INT;
DECLARE result ??? # not sure what data type this should be
DECLARE cur1 CURSOR FOR SELECT field_id_58 as 'release_id' , ewt.entry_id FROM exp_weblog_data ewd
LEFT OUTER JOIN exp_weblog_titles ewt ON ewt.`entry_id` = ewd.`entry_id`
WHERE ewt.weblog_id = 15;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET empty=1;
OPEN cur1;
SET empty =0;
WHILE empty = 0 DO
FETCH cur1 INTO result;
#if the release_id in the result row contains a URL string then delete rows for tables ewt, ewd for that entry_id
END IF;
END WHILE;
CLOSE cur1;
END //
You can use regular expressions to find non-numeric fields. The following query will find any rows for which the specified column's value is non-numeric:
SELECT * FROM table_name WHERE column_name REGEXP '[^0-9].+'
Any rows which have a purely numeric value will not be returned. If your DELETE statement uses the same WHERE clause, that should do it.
To delete the rows that contain non-numeric column values, try this query:
DELETE FROM exp_weblog_titles ewt
INNER JOIN exp_weblog_data ewd ON
ewt.`entry_id` = ewd.`entry_id`
WHERE ewt.weblog_id = 15 AND ewd.field_id_58 REGEXP '[^0-9].+';
DELETE FROM exp_weblog_data ewd WHERE ewd.field_id_58 REGEXP '[^0-9].+';
It first deletes all of the relevant rows from the child table, then deletes the parent table rows. Use at your own risk, obviously.
The SQL actually needed to look like this:
DELETE FROM ewt
USING exp_weblog_titles AS ewt
INNER JOIN exp_weblog_data ewd ON ewt.entry_id = ewd.entry_id
WHERE ewt.weblog_id = 15
AND ewd.field_id_58 REGEXP '[^0-9].+';
DELETE FROM exp_weblog_data ewd WHERE ewd.field_id_58 REGEXP '[^0-9].+';