How to prevent recursive limit in stored procedure - mysql

I need some help please,I'm having problem with the SP,how can I prevent this not to get recursive limit SQL ERROR(1456).Is there a way to change this SP not to use recursive...what I'm trying to achieve is to sum to all the amount in my left subtree on a given parentid...for example I have parentid 5,so my left is 7 so I want to sum all his amount on his subtree it's(22,500)if I'm not wrong.
Thank you in advance.
I have this table structure
CREATE TABLE `mytree` (
`parentid` INT(11) NOT NULL,
`memberid` INT(11) NOT NULL,
`position` CHAR(1) NOT NULL,
`amount` DECIMAL(10,2) NOT NULL,
UNIQUE INDEX `ck1tree` (`memberid`),
UNIQUE INDEX `ck2tree` (`parentid`, `position`)
)
COLLATE='latin1_swedish_ci'
ENGINE=MyISAM
;
and here is my data in the table mytree
INSERT INTO `mytree` (`parentid`, `memberid`, `position`, `amount`) VALUES
(8, 27, 'R', 0.00),
(8, 28, 'L', 0.00),
(24, 26, 'R', 0.00),
(0, 1, '', 5500.00),
(24, 25, 'L', 0.00),
(21, 24, 'L', 500.00),
(21, 23, 'R', 0.00),
(18, 20, 'R', 1500.00),
(18, 19, 'L', 0.00),
(15, 18, 'R', 2000.00),
(15, 17, 'L', 0.00),
(13, 16, 'L', 0.00),
(13, 15, 'R', 2500.00),
(12, 14, 'R', 0.00),
(12, 13, 'L', 3000.00),
(10, 12, 'R', 3500.00),
(10, 11, 'L', 0.00),
(7, 10, 'R', 4000.00),
(7, 9, 'L', 0.00),
(5, 8, 'R', 500.00),
(5, 7, 'L', 4500.00),
(1, 6, 'R', 0.00),
(1, 5, 'L', 5500.00),
(20, 22, 'R', 0.00),
(20, 21, 'L', 1000.00);
CREATE DEFINER=`root`#`localhost` PROCEDURE `sum_left_amount`(IN `p_memid` INT, OUT `tot_left_amount` DECIMAL(10,2))
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE a decimal(10,2);
DECLARE m int;
DECLARE s decimal(10,2);
select memberid, amount into m, a from mytree
where parentid = p_memid and position = 'L';
call sum_left_amount(m,s);
set tot_left_amount = a + s;
END

Related

Product Filtering PHP and MySQL

I need to select IDs of products that have specific racketCondition id.
Table racket_attribute:
enter image description here
Table racket_condition:
enter image description here
Table racket_option:
enter image description here
My condition is: if the user select 1, 5, 10, and 21 which will get exactly product_id 16 but if the select 1, 5, 10, 20 then it will pot up 'no data found' or find the which product id which fulfills the racketCondition id.
racket_option SQL script:
CREATE TABLE racket_option (
racketOption_id int(11) NOT NULL,
product_id int(11) NOT NULL,
racketCondition_id int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
--
-- Dumping data for table racket_option
INSERT INTO racket_option (racketOption_id, product_id, racketCondition_id) VALUES
(1, 16, 1),
(2, 16, 5),
(3, 16, 10),
(5, 21, 1),
(6, 21, 5),
(7, 23, 1),
(8, 23, 2),
(9, 27, 1),
(10, 28, 1),
(11, 29, 1),
(12, 16, 21),
(13, 21, 20),
(14, 23, 20),
(15, 27, 20),
(16, 28, 20),
(17, 30, 21),
(18, 30, 7),
(19, 30, 11),
(20, 21, 8),
(21, 16, 8);
--
-- Indexes for dumped tables
--
-- Indexes for table racket_option
ALTER TABLE racket_option
ADD PRIMARY KEY (racketOption_id),
ADD KEY racketCondition_FK (racketCondition_id),
ADD KEY productID_FK4 (product_id);

How get from the table all the nodes that have no parent nodes?

How do I get from a table all nodes that have no parent nodes?
I am using a (Closure Table) template.
I need to get all nodes that have no parent nodes.
Consider the fact that each node refers to itself. That is, each node itself is a parent and child node in relation to itself.
It looks something like this.
Below I am showing a test database.
-- phpMyAdmin SQL Dump
-- version 5.1.0
-- https://www.phpmyadmin.net/
--
-- Host: localhost
-- Generation Time: Oct 15, 2021 at 06:30 PM
-- Server version: 8.0.25
-- PHP Version: 8.0.3
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET #OLD_CHARACTER_SET_CLIENT=##CHARACTER_SET_CLIENT */;
/*!40101 SET #OLD_CHARACTER_SET_RESULTS=##CHARACTER_SET_RESULTS */;
/*!40101 SET #OLD_COLLATION_CONNECTION=##COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Database: `closure`
--
-- --------------------------------------------------------
--
-- Table structure for table `category_name`
--
CREATE TABLE `category_name` (
`id` bigint NOT NULL,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_ru_0900_ai_ci DEFAULT NULL,
`level` int DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_ru_0900_ai_ci;
--
-- Dumping data for table `category_name`
--
INSERT INTO `category_name` (`id`, `name`, `level`) VALUES
(1, 'Electronics', 0),
(2, 'TV sets', 0),
(3, 'Sensory', 0),
(4, 'Backlit', 0),
(5, 'On wheels', 0),
(6, 'Anti-glare', 0),
(7, 'Super thin', 0),
(8, 'Wall', 0),
(9, 'Telephone', 0),
(10, 'Shell', 0),
(11, 'Button', 0),
(12, 'Sensory', 0),
(13, 'Retractable', 0),
(14, 'Auto', 0),
(15, 'Manual', 0),
(16, 'For home', 0),
(17, 'For bathroom', 0),
(18, 'Rug', 0),
(19, 'With animals', 0),
(20, 'Obstruction', 0),
(21, 'Soap dish ', 0),
(22, 'With holes', 0),
(23, 'Transparent', 0),
(24, 'For kitchen', 0),
(25, 'Pans', 0),
(26, 'With handles', 0),
(27, 'Non-stick', 0),
(28, 'pans', 0),
(29, 'Steam', 0),
(30, 'With lids', 0),
(31, 'Test', 0);
-- --------------------------------------------------------
--
-- Table structure for table `tree_path`
--
CREATE TABLE `tree_path` (
`children` bigint NOT NULL,
`parent` bigint NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_ru_0900_ai_ci;
--
-- Dumping data for table `tree_path`
--
INSERT INTO `tree_path` (`children`, `parent`) VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1),
(6, 1),
(7, 1),
(8, 1),
(9, 1),
(10, 1),
(11, 1),
(12, 1),
(13, 1),
(14, 1),
(15, 1),
(2, 2),
(3, 2),
(4, 2),
(5, 2),
(6, 2),
(7, 2),
(8, 2),
(3, 3),
(4, 3),
(5, 3),
(4, 4),
(5, 5),
(6, 6),
(7, 6),
(8, 6),
(7, 7),
(8, 8),
(9, 9),
(10, 9),
(11, 9),
(12, 9),
(13, 9),
(14, 9),
(15, 9),
(10, 10),
(11, 10),
(12, 10),
(11, 11),
(12, 12),
(13, 13),
(14, 13),
(15, 13),
(14, 14),
(15, 15),
(16, 16),
(17, 16),
(18, 16),
(19, 16),
(20, 16),
(21, 16),
(22, 16),
(23, 16),
(24, 16),
(25, 16),
(26, 16),
(27, 16),
(28, 16),
(29, 16),
(30, 16),
(17, 17),
(18, 17),
(19, 17),
(20, 17),
(21, 17),
(22, 17),
(23, 17),
(18, 18),
(19, 18),
(20, 18),
(19, 19),
(20, 20),
(21, 21),
(22, 21),
(23, 21),
(22, 22),
(23, 23),
(24, 24),
(25, 24),
(26, 24),
(27, 24),
(28, 24),
(29, 24),
(30, 24),
(25, 25),
(26, 25),
(27, 25),
(26, 26),
(27, 27),
(28, 28),
(29, 28),
(30, 28),
(29, 29),
(30, 30);
--
-- Indexes for dumped tables
--
--
-- Indexes for table `category_name`
--
ALTER TABLE `category_name`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tree_path`
--
ALTER TABLE `tree_path`
ADD PRIMARY KEY (`children`,`parent`),
ADD KEY `FK_PARENT` (`parent`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `category_name`
--
ALTER TABLE `category_name`
MODIFY `id` bigint NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=33;
--
-- Constraints for dumped tables
--
--
-- Constraints for table `tree_path`
--
ALTER TABLE `tree_path`
ADD CONSTRAINT `FK_CHILDREN` FOREIGN KEY (`children`) REFERENCES `category_name` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `FK_PARENT` FOREIGN KEY (`parent`) REFERENCES `category_name` (`id`) ON DELETE CASCADE;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=#OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=#OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=#OLD_COLLATION_CONNECTION */;
Perhaps the answer will be like this.
+----+--------------+-------+----------+--------+
| id | name | level | children | parent |
+----+--------------+-------+----------+--------+
| 1 | Electronics | 0 | 1 | 1 |
| 16| For home | 0 | 16 | 16 |
+----+--------------+-------+----------+--------+
I'd use NOT EXISTS () to check that there are no parent rows in the tree_path table (other than itself).
SELECT
*
FROM
category_name c
WHERE
NOT EXISTS (
SELECT *
FROM tree_path t
WHERE t.parent != c.id
AND t.children = c.id
)
AND EXISTS (
SELECT *
FROM tree_path t
WHERE t.parent = c.id
AND t.children = c.id
)
Demo : https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=55698aa8b51f99d42db63feda15148a7
(Edited to exclude categories that are not in tree_path)

MySQL query with reference to many to many table

Assuming the following tables:
area
-id
-title
properties
-id
-title
-area_id
categories
-id
-title
properties_categories
-property_id
-category_id
The following query is very close to the correct answer but is not correct. Could you advise what the correct query is?
select a.id, a.title, count(p.id)
FROM area AS a,properties AS p, properties_categories AS pc
WHERE a.id = p.area_id
AND pc.category_id IN (1,2,3)
AND pc.property_id = p.id
GROUP BY a.id;
OR
SELECT A.id, A.title, COUNT(B.id)
FROM area A LEFT JOIN properties B
ON A.id=B.area_id
JOIN properties_categories C
ON C.property_id=B.id
WHERE C.category_id IN (1,2,3)
GROUP BY A.id, A.title;
If I write a query where the following only draws from the area and properties table you have the correct results.
SELECT A.id, A.title, COUNT(B.id) FROM area A LEFT JOIN properties B ON A.id=B.area_id GROUP BY A.id, A.title
Here is the data dump to experiment with:
CREATE TABLE `area` (
`id` int(10) UNSIGNED NOT NULL,
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `area` (`id`, `title`) VALUES
(2, 'Test1'),
(3, 'Test2'),
(4, 'Test3'),
(5, 'Test4'),
(6, 'Test5');
CREATE TABLE `categories` (
`id` int(10) UNSIGNED NOT NULL,
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `categories` (`id`, `title`) VALUES
(1, 'Category A'),
(2, 'Category B'),
(3, 'Category C'),
(4, 'Category D'),
(5, 'Category E'),
(6, 'Category F');
CREATE TABLE `properties` (
`id` int(11) NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`area_id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `properties` (`id`, `name`, `area_id`) VALUES
(2, 'Property A', 2),
(3, 'Property B', 2),
(4, 'Property C', 2),
(5, 'Property D', 2),
(7, 'Property E', 2),
(8, 'Property F', 2),
(10, 'Property G', 2),
(11, 'Property H', 2),
(12, 'Property I', 2),
(13, 'Property J', 2),
(14, 'Property K', 2),
(19, 'Property L', 2),
(20, 'Property M', 4),
(21, 'Property O', 2),
(22, 'Property P', 2),
(23, 'Property Q', 2),
(24, 'Property R', 2),
(27, 'Property S', NULL),
(29, 'Property T', 2),
(30, 'Property U', 2),
(32, 'Property V', 2),
(33, 'Property W', 2),
(34, 'Property X', 5),
(35, 'Property Y', 5),
(36, 'Property Z', 5),
(37, 'Property A1', 5),
(38, 'Property A2', 3),
(39, 'Property A3', 6);
CREATE TABLE `properties_categories` (
`category_id` int(11) NOT NULL,
`property_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `properties_categories` (`category_id`, `property_id`) VALUES
(2, 2),
(6, 2),
(2, 3),
(6, 3),
(2, 4),
(6, 4),
(2, 5),
(6, 5),
(2, 7),
(6, 7),
(2, 8),
(6, 8),
(2, 10),
(6, 10),
(2, 11),
(6, 11),
(2, 12),
(6, 12),
(2, 13),
(6, 13),
(2, 14),
(6, 14),
(5, 7),
(5, 3),
(5, 14),
(5, 4),
(5, 12),
(5, 11),
(5, 13),
(5, 5),
(5, 10),
(5, 8),
(2, 20),
(3, 20),
(2, 19),
(6, 19),
(2, 21),
(2, 22),
(2, 23),
(5, 23),
(6, 23),
(1, 22),
(2, 24),
(6, 24),
(2, 29),
(2, 30),
(5, 30),
(2, 33),
(5, 33),
(6, 33),
(2, 32),
(5, 32),
(6, 32),
(1, 34),
(2, 34),
(3, 34),
(4, 34),
(2, 35),
(5, 35),
(2, 36),
(4, 36),
(5, 36),
(2, 37),
(4, 37),
(5, 37),
(2, 38),
(2, 39),
(4, 39),
(5, 39),
(1, 39),
(5, 24),
(4, 38);
Try this:
SELECT A.id, A.title, COUNT(B.id)
FROM area A LEFT JOIN properties B
ON A.id=B.area_id
JOIN properties_categories C
ON C.property_id=B.id
WHERE C.category_id IN (1,2,3)
GROUP BY A.id, A.title;
See MySQL Join Made Easy for insights on using joins in mysql.

Filter result with two where clauses in it

I want to filter property with two type multi checkbox :
1 - Option
2 - Type
Here is my tables for this type:
propety_type:
CREATE TABLE IF NOT EXISTS `property_type` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`PropertyNumber` int(4) NOT NULL,
`TypeNumber` int(50) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_persian_ci AUTO_INCREMENT=25 ;
INSERT INTO `property_type` (`ID`, `PropertyNumber`, `TypeNumber`) VALUES
(13, 53, 1),
(14, 53, 2),
(15, 53, 3),
(16, 54, 3),
(17, 54, 5),
(18, 55, 6),
(19, 55, 8),
(20, 56, 3),
(21, 56, 2),
(22, 56, 1),
(23, 54, 1),
(24, 55, 1);
property_option:
CREATE TABLE IF NOT EXISTS `property_option` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`PropertyNumber` int(11) NOT NULL,
`OptionNumber` int(11) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=53 ;
INSERT INTO `property_option` (`ID`, `PropertyNumber`, `OptionNumber`) VALUES
(35, 53, 1),
(36, 53, 2),
(37, 53, 3),
(39, 54, 3),
(40, 54, 5),
(41, 55, 6),
(42, 55, 8),
(43, 56, 2),
(45, 56, 1),
(46, 56, 3),
(47, 56, 8),
(48, 53, 9),
(49, 53, 4),
(50, 55, 1),
(51, 54, 2),
(52, 54, 1);
My query :
SELECT property.PropertyNumber
FROM property
INNER JOIN property_option ON property.PropertyNumber = property_option.PropertyNumber
WHERE property_option.OptionNumber IN (1,3 )
GROUP BY property.PropertyNumber
HAVING COUNT(DISTINCT property_option.ID) =2
INNER JOIN property_type ON property.PropertyNumber = property_type.PropertyNumber
WHERE property_type.TypeNumber IN (1,2 )
GROUP BY property.PropertyNumber
HAVING COUNT(DISTINCT property_type.ID) =2
But when i test this in phpmyadmin, i get this error:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INNER JOIN property_option ON property.PropertyNumber = property_option.Property' at line 9
If you want to make sure the rows returned fulfills the requirement of having both specified options as well as both specified types then you can use the query below.
SELECT p.PropertyNumber
FROM property p
JOIN property_option USING (PropertyNumber)
JOIN property_type USING (PropertyNumber)
WHERE OptionNumber IN (1,8)
AND TypeNumber IN (1,2)
GROUP BY p.PropertyNumber
HAVING COUNT(DISTINCT OptionNumber) = 2
AND COUNT(DISTINCT TypeNumber) = 2;
Sample SQL Fiddle

Need help for my stored procedure please

I have this data and table structure,I am creating MySQL stored procedure to sum all the amount in the leftchild of the parentid, I don't have enough knowledge in stored procedure.and I need some help please because I'm lost.
CREATE TABLE IF NOT EXISTS `mytree` (
`parentid` int(11) NOT NULL,
`memberid` int(11) NOT NULL,
`position` char(1) NOT NULL,
`amount` decimal(10,2) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `mytree` (`parentid`, `memberid`, `position`, `amount`) VALUES
(8, 27, 'R', 0.00),
(8, 28, 'L', 0.00),
(24, 26, 'R', 0.00),
(0, 1, '', 5500.00),
(24, 25, 'L', 0.00),
(21, 24, 'L', 500.00),
(21, 23, 'R', 0.00),
(18, 20, 'R', 1500.00),
(18, 19, 'L', 0.00),
(15, 18, 'R', 2000.00),
(15, 17, 'L', 0.00),
(13, 16, 'L', 0.00),
(13, 15, 'R', 2500.00),
(12, 14, 'R', 0.00),
(12, 13, 'L', 3000.00),
(10, 12, 'R', 3500.00),
(10, 11, 'L', 0.00),
(7, 10, 'R', 4000.00),
(7, 9, 'L', 0.00),
(5, 8, 'R', 500.00),
(5, 7, 'L', 4500.00),
(1, 6, 'R', 0.00),
(1, 5, 'L', 5500.00),
(20, 22, 'R', 0.00),
(20, 21, 'L', 1000.00);
here is my stored proc
CREATE DEFINER=`root`#`localhost` PROCEDURE `count_left_right_amount`(IN `p_memid` INT, OUT `tot_left_amount` DECIMAL(10,2))
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE row_total decimal(10,2);
DECLARE total decimal(10,2);
DECLARE m_left int;
DECLARE run_left int;
DECLARE p_id int;
set total = 0;
select memberid into p_id from mytree where position = 'L' AND parentid = p_memid;
WHILE p_id != 0 DO
select amount into row_total from mytree where parentid = p_id
GROUP BY parentid;
select memberid into m_left from mytree where parentid = p_id;
set total = total + row_total;
set p_id = m_left;
END WHILE;
END
Example if the parentid is 5 ,so the leftchild is 7 then go down to his subtree sum it all,so the total amount in the left child is '22500'? please correct me if I'm wrong.
please help me.
Thank you in advance.