SQL result to multidimensional array (SQL to markdown file) - php

I am trying to transfer data from a MySQL database (with relational columns) to a markdown file (Pico CMS). For that I created the following SQL query to get the data:
SELECT DISTINCT
rqypj_mt_links.link_name,
rqypj_mt_links.link_desc,
rqypj_mt_links.address,
rqypj_mt_links.city,
rqypj_mt_links.state,
rqypj_mt_links.country,
rqypj_mt_links.postcode,
rqypj_mt_links.telephone,
rqypj_mt_links.fax,
rqypj_mt_links.email,
rqypj_mt_links.website,
rqypj_mt_links.price,
rqypj_mt_links.lat,
rqypj_mt_links.lng,
rqypj_mt_links.zoom,
rqypj_mt_cats.cat_name,
rqypj_mt_images.filename,
rqypj_mt_cfvalues.value,
rqypj_mt_customfields.caption
FROM rqypj_mt_links
LEFT JOIN rqypj_mt_cl
ON rqypj_mt_links.link_id = rqypj_mt_cl.link_id
LEFT JOIN rqypj_mt_cats
ON rqypj_mt_cl.cat_id = rqypj_mt_cats.cat_id
LEFT JOIN rqypj_mt_images
ON rqypj_mt_links.link_id = rqypj_mt_images.link_id
LEFT JOIN rqypj_mt_cfvalues
ON rqypj_mt_links.link_id = rqypj_mt_cfvalues.link_id
LEFT JOIN rqypj_mt_customfields
ON rqypj_mt_cfvalues.link_id = rqypj_mt_customfields.cf_id
ORDER BY rqypj_mt_links.link_id, rqypj_mt_cl.cat_id
LIMIT 100
This qives the following result
Title | desc | adress | cats | etc.
But when a title has multiple cats I get multiple rows with the same data only the cat row difference. Therefore I am looking for the best way to transfer the SQL data in to a PHP array. F.e.:
$result['title']
$result['desc']
$result['cats'][0]
$result['cats'][1]
Etc.
I guess that way it w'll be more easy to write the markdown file. Hopefully someone can get me some advise about the best approach and some PHP tips/scripts.
Thanks in advance!
Jelte

I think you want to do something similar to this question and similarly you can use GROUP_CONCAT.
Look at this SQL Fiddle. Maybe it will help you :-)
Schema:
CREATE TABLE link
(
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255),
PRIMARY KEY (id)
);
CREATE TABLE cat
(
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255),
PRIMARY KEY (id)
);
CREATE TABLE has_cat
(
`link_id` INT,
`cat_id` INT,
FOREIGN KEY (link_id) REFERENCES link(id),
FOREIGN KEY (cat_id) REFERENCES cat(id)
);
Values:
INSERT INTO link (`name`)
VALUES
('John'),
('Calvin')
;
INSERT INTO cat (`name`)
VALUES
('Garfield'),
('Nermal'),
('Hobbes')
;
INSERT INTO has_cat (link_id, cat_id)
VALUES
(1, 1),
(1, 2),
(2, 3)
;
Query:
SELECT link.name AS link, GROUP_CONCAT(cat.name) AS cats
FROM link, has_cat, cat
WHERE
link.id = has_cat.link_id AND
cat.id = has_cat.cat_id
GROUP BY link.name
Result:
| link | cats |
|--------|-----------------|
| Calvin | Hobbes |
| John | Garfield,Nermal |
Make a PHP array from it
From here, you can explode the comma separated string into an array:
var_dump( explode( ',', $result['cats'] ) );
That will give you:
array(2)
(
[0] => string(8) "Garfield"
[1] => string(6) "Nermal"
)

Related

Mysql query based on columns matches

I don’t know how to make this with mysql, I only know how to do basic queries, I want to show a list of result based on matches, Results will be shown based on the same value of the answers…answers may have a value from 1-10
+++++++++++++++TABLE++++++++++++
id | userName | answer1 | answer2 | answer3 | answer4….
10 Jhon 1 1 3 8
11 Anne 1 2 4 8
12 Mike 7 4 5 7
etc…
++++++++++++++++++++++++++++++++++++++++
If I send the values in the query I want that check the answers and show the result sorted my matches,
more matches first…no matches last
So if i send the results:
answer1=1 answer2=1 answer3=7 answer4=2...
the result should be(give back the id)
10 11 12
Your table design is not fine, you should separate it into users and questions table.
If you cannot change the table design you can solve you problem using this query:
select
id,
username,
if(answer1 = :an1, 1, 0) + if(answer2 = :an2, 1, 0) + if(answer3 = :an3, 1, 0) + if(answer4 = :an4, 1, 0) as total
from
table
order by total desc
UPDATE:
Better design for this problem:
Check the SQLFiddle: http://sqlfiddle.com/#!9/6c145/2 with a live demo.
Create Users Table
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL
);
Create Questions Table
CREATE TABLE questions (
id INT PRIMARY KEY,
correct_answer INT NOT NULL
);
Create User Answers Table
CREATE TABLE user_answers (
user_id INT,
question_id INT,
user_answer TINYINT,
PRIMARY KEY (user_id, question_id),
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE NO ACTION ON UPDATE NO ACTION,
FOREIGN KEY (question_id) REFERENCES questions (id) ON DELETE NO ACTION ON UPDATE NO ACTION
);
Than to retrieve the data you can use the query:
SELECT
tmp.id,
tmp.username,
sum(tmp.is_correct) as total
FROM (
SELECT
users.id,
users.username,
IF (questions.correct_answer = user_answers.user_answer, 1, 0) as is_correct
FROM
users
INNER JOIN user_answers on users.id = user_answers.user_id
INNER JOIN questions on user_answers.question_id = questions.id
) tmp
GROUP BY tmp.id, tmp.username
ORDER BY total desc;

PHP/MySQL - Trouble when trying to select two columns where id from table1 is equal to id from table2

Here is my query:
$query = 'SELECT * extensa_econt_city as econt_city, extensa_econt_office as econt_office WHERE econt_city.city_id = econt_office.city_id';
I am trying to select all the rows from table extensa_econt_city and extensa_econt_office where city_id from extensa_econt_city is equal to city_id from extensa_econt_office.
Then when i get this information i have to create FORECH loop. It is important to be FORECH not while loop.
Here is my sample code:
<?PHP
foreach($results as $row){
echo $row['econt_city.name'];
echo $row['econt_office.name'];
}
?>
In this foreach loop i have to select row name from extensa_econt_office and extensa_econt_city.
Structure:
I hope you understand what i am asking.
Can you help me out resolve this problem.
Thanks in advance!
I think this might do what you mean.
select
c.`city_id`,
c.`post_code`,
c.`type`,
c.`name`,
c.`name_en`,
c.`zone_id`,
c.`country_id`,
c.`office_id`
o.`FIELD_NAME` as 'ALIAS',
o.`NEW_FIELD_NAME` as 'OTHER ALIAS'
from `extensa_econt_city` c
left outer join `extensa_econt_office` o on o.`city_id`=c.`city_id`
Once the tables are aliased ( in this case the aliases are c & o ) you can select either all records using * ( unless there are duplicated names in which case you would get an error ) or, as above, select the desired fields directly in the query.
Once the query is set the FOREACH loop can select he record by the name / alias defined in the sql
All you are looking for is the name column, not all columns (select *) from what you have shown. Don't drag down your system with wildcards as such (with select *). Also do an explicit join.
Here is a visual of my pretend schema, as I am not suggesting it is yours.
Do an explicit join, unlike your join in a where clause (that style is circa 1995)
Schema
create table extensa_econt_city
( id int auto_increment primary key,
city_id int not null,
name varchar(100) not null
);
create table extensa_econt_office
( id int auto_increment primary key,
city_id int not null,
name varchar(100) not null
);
insert extensa_econt_city(city_id,name) values (1,'eec name1'),(2,'eec name2'),(3,'eec name3');
insert extensa_econt_office(city_id,name) values (1,'EEO name1'),(2,'EEO name2'),(3,'EEO name3');
The Query
select eec.name as eec_name,eeo.name as eeo_name
from extensa_econt_city eec
join extensa_econt_office eeo
on eeo.city_id=eec.city_id;
Results
+-----------+-----------+
| eec_name | eeo_name |
+-----------+-----------+
| eec name1 | EEO name1 |
| eec name2 | EEO name2 |
| eec name3 | EEO name3 |
+-----------+-----------+
I am trying to select all the rows from table extensa_econt_city and
extensa_econt_office where city_id from extensa_econt_city is equal to
city_id from extensa_econt_office...
In this foreach loop I have to select row name from extensa_econt_office and extensa_econt_city.
SELECT eec.name AS ee_city_name,
eeo.name AS ee_office_name,
FROM extensa_econt_city eec
LEFT JOIN extensa_econt_office eeo ON eec.city_id = eeo.city_id
And in the PHP foreach loop, you can access the data like this:
<?php
foreach($results as $row){
echo $row['ee_city_name'];
echo $row['ee_office_name'];
}

How can i get the result from DB if one column have several keywrods?

Well, I've a table called keywords and there are 2 columns.
1) kid
2) keywords (keyword value)
and I've another table called contact_details where there a column called keyword. In this keyword column I'm inserting many keyword from keywordstable. So 2 tables is look like this...
Keywords table:
kid keyword
1 php
1 mysql
1 html
1 css
1 css3
1 wp
1 photoshop
1 3d
contact_details table:
cid name phone keyword
1 alex 123 php, mysql, hmtl
2 alex1 124 php, html, css3
3 alex2 125 wp, html, css
4 alex3 126 photoshop, 3d
5 alex4 127 html, 3d, php
6 alex5 128 mysql, wp, html
Now I've a search box which is searching people (name From contact_details table) by using keyword value. In search box, Search value could be few keywords. I mean it's could be php, mysql, html or could be php, 3d, photoshop.
So My question is : how can I write a Sql query to get the result ? I want to get all name which match the search keyword/s from contact_details table ?
Is there any field need to add in keywords table ? Can not get an IDEA :(
Select name from contact_details where keyword like '%<search keywords>%'
Like search keyword key php then you need pass php in query and will get list of all name which having keywords as php'
Select name from contact_details where keyword like '%php%'
hope this will resolve your issue.
Proper approach,
Make kid as primary key in Keyword table
Keywords table:
kid keyword
1 php
2 mysql
3 html
Remove keywords column from contact_details table.
contact_details table:
cid name phone
1 alex 123
2 alex1 124
3 alex2 125
Make one more table which having many to many relationship and you need insert the relationship here so that no need touch again keywords and contact_details table again.
keyword_contact_mapping
kcid kid_fk cid_fk
1 1 1
2 1 2
3 1 3
4 2 1
5 2 1
6 2 2
7 2 3
Sql query (Not tested you can also use alias)
select name from contact_details join keyword_contact_mapping on kid_fk =(select kid from Keywords where keyword='php')
Assuming you have the ID when the name is selected, you can use:
SELECT Keyword from Keywords_Table
WHERE ID = <ID>
USE AdventureWorksDW2008R2
GO
IF OBJECT_ID('Keywords') IS NOT NULL
BEGIN
DROP TABLE Keywords
END
IF OBJECT_ID('Contact_Details') IS NOT NULL
BEGIN
DROP TABLE Contact_Details
END
IF OBJECT_ID('Keyword_ContactDetails') IS NOT NULL
BEGIN
DROP TABLE Keyword_ContactDetails
END
/* automate id's with identity. Or, do you want to specify the the keyword id manually?
*/
CREATE TABLE Keywords(
Keywords_ID INT IDENTITY(1,1) NOT NULL
,Keyword NVARCHAR(100)
CONSTRAINT PK_Keywords PRIMARY KEY
(
Keywords_ID
)
)
/* You must plan each column data type by careful consideration
I am using the phone example here to demonstrate different business requirements
the lenghts and datatype may need to change for localization
*/
CREATE TABLE Contact_Details
(
Contact_Details_ID INT IDENTITY(1,1) NOT NULL
,First_Name VARCHAR(100)
,Last_Name VARCHAR(100)
,Phone VARCHAR(10)
,Phone_EXT VARCHAR(3)
,Phone_International NVARCHAR(15)
CONSTRAINT PK_Contact_Details PRIMARY KEY
(
Contact_Details_ID
)
)
CREATE TABLE Keyword_ContactDetails
(
Keyword_ID INT
,Contact_Details_ID INT
,DateTime_Created DATETIME
CONSTRAINT PK_KeywordContact PRIMARY KEY
(
Keyword_ID
,Contact_Details_ID
)
/*Enforce referential integrity,
prevents adding keywords that don't exist
prevents deleting a keyword if it is referenced
*/
FOREIGN KEY (Keyword_ID) REFERENCES Keywords(Keywords_ID),
FOREIGN KEY (Contact_Details_ID) REFERENCES Contact_Details(Contact_Details_ID)
)
/* Populate keywords
*/
INSERT INTO Keywords(Keyword) VALUES ('PHP')
INSERT INTO Keywords(Keyword) VALUES ('MYSQL')
INSERT INTO Keywords(Keyword) VALUES ('HTML')
INSERT INTO Keywords(Keyword) VALUES ('CSS')
/* Add contact details
*/
INSERT INTO Contact_Details(
First_Name
,Last_Name
,Phone
,Phone_EXT
,Phone_International)
VALUES(
'Abe'
,'Lincoln'
,'2129996677'
,'123'
,'na')
/* Assign PHP Keyword to Abe Lincoln
*/
DECLARE #keywordID int = 0
,#contactDetails int = 0
set #keywordID = (select Keywords_ID from Keywords where Keyword = 'PHP')
set #contactDetails = (select Contact_Details_ID from Contact_Details where Last_Name = 'Lincoln')
INSERT INTO Keyword_ContactDetails(
Keyword_ID
,Contact_Details_ID
,DateTime_Created)
VALUES(
#keywordID
,#contactDetails
,CURRENT_TIMESTAMP)
SELECT * FROM Contact_Details C
JOIN Keyword_ContactDetails KC
ON KC.Contact_Details_ID = C.Contact_Details_ID
JOIN Keywords K
ON K.Keywords_ID = KC.Keyword_ID

PHP - MySQL Search database table return result with percentage match

On my site I allow the users to select what they like or have interest in. This is done using a pre-defined drop down menu, so every time the user logs into the site they get a list of users that have the same interest as them.
This is done by taking the logged in user's interests (store in db) and matching with other user on the site, using MySQL WHERE clause. But what I am having trouble is how to show percentage or score next to each users to show how close they match the logged in user interest.
For example:
user1 -- 60% match to your interest
user1 -- 30% match to your interest
user2 -- 20% match to your interest
Each user have 5 different interest, if all match than its 100% match.
A sample of table structure:
CREATE TABLE IF NOT EXISTS `helloworld` (
`id` int(9) NOT NULL AUTO_INCREMENT,
`like1` varchar(300) NOT NULL,
`like2` varchar(300) NOT NULL,
`like3` varchar(300) NOT NULL,
`name` varchar(300) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
example query:
SELECT * FROM helloworld WHERE like1='football' AND like2='art'
I was thinking using COUNT function, but I am unsure? or should I be using sub queries?
EDIT : i am using PHP for server side language. user can NOT type their own likes, must use the pre defined list.
Here's how I do it. Assume that $like1, $like2 and $like3 are the values from your current user:
SELECT (IF(like1='$like1',1,0) + IF(like2='$like2',1,0) + IF(like3='$like3',1,0))/3*100 match_percent,
COUNT(id)
FROM helloworld
GROUP BY match_percent;
You have a many-to-mant relationship between user and likes. Your table violates 1NF - you have a "repeating group" of the like columns. Instead, have a separate association table to handle this:
create table user_likes (
user_id int(9) NOT NULL,
like_name varchar(300) NOT NULL
);
Now you can use simpler queries to get the count of matches - I'll leave that to you to work out :)
Hint: You could use a bit mask to help determine matches, assigning a predefined power of 2 number to each distinct like_name (help is a like_names table).
You'd better check that at PHP level. Considering each user's interests, you may get the score using count() over the result of array_intersect() to compare the visitor and other user interests (http://www.php.net/manual/en/function.array-intersect.php). If you allow 5 interests, that would be (5 * count(array_intersect({params})))%. For no match, 0%, for 4 matches, 80%.
First off, I think you need a different schema. The one you have will make your task very difficult, because it's not flexible enough. I recommend something like this:
CREATE TABLE `users` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(300) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `likes` (
`user` INT NOT NULL,
`interest` VARCHAR NOT NULL,
PRIMARY KEY (`user`,`interest`)
);
(Sorry, I don't remember how to set up a FK relationship in MySQL, but I'm sure you can figure that out easily enough.)
Then, to determine the number of 'likes' for each user:
SELECT COUNT(*)
FROM users
JOIN likes ON likes.user=users.id
WHERE users.name = 'bob';
Then to determine how many likes two users have in common:
SELECT COUNT(*)
FROM users AS u1
JOIN likes AS l1 ON (l1.user = u1.id)
JOIN likes AS l2 ON (l1.interest = l2.interest)
JOIN users AS u2 ON (l2.user = u2.id)
WHERE u1.name = 'bob'
AND u2.name = 'alice';
Then based on these three numbers, you can calculate your percentages as you wish--probably in your client code, but you could use sub-selects to do it all SQL-side if you want.
Example:
USERS:
id | name
----+-------
1 | bob
2 | alice
LIKES:
user | interest
------+----------
1 | fish
1 | baseball
2 | fish
2 | cooking
2 | baseball
Running the first query for bob and alice will show that bob has 2 interests, and that Alice has 3 interests. Then running the second query will show that they bob and alice together have 2 shared interests.
You can then show Bob that Alice shares 100% of his interests (2/2 = 100%), and you can show Alice that Bob shares 66% (2/3 = 66%) of her interests.
This will do it with your current schema:
select
t2.id,
t2.name
sum(
t1.like1 in (t2.like1, t2.like2, t2.like3, t2.like4, t2.like5) +
t1.like2 in (t2.like1, t2.like2, t2.like3, t2.like4, t2.like5) +
t1.like3 in (t2.like1, t2.like2, t2.like3, t2.like4, t2.like5) +
t1.like4 in (t2.like1, t2.like2, t2.like3, t2.like4, t2.like5) +
t1.like5 in (t2.like1, t2.like2, t2.like3, t2.like4, t2.like5)
) * 20 as percent_match
from helloworld t1
left join helloworld t2 on t1.id != t2.id
group by 1, 2
order by 3 desc;
This works because true in mysql is 1 - summing the truths will total the number of matches.

deleting nested categories from a table

I have a table called categories which looks like this
+-------------+--------------+---------------+
| id | catName | parentId |
+-------------+--------------+---------------+
| 1 | Category 1 | 0 |
| 2 | Category 2 | 0 |
| 3 | Sub Cat 1 | 1 |
| 4 | Sub Cat 2 | 1 |
| 5 | Sub sub cat 1| 4 |
| 6 | Sub sub cat 2| 4 |
| 7 | Category 2 | 0 |
+-------------+--------------+---------------+
It would be easy to delete a category and its direct child:
mysql_query("DELETE FROM `categories` WHERE `id`='$id'");
mysql_query("DELETE FROM `categories` WHERE `parentId`='$id'");
However I need to be able to delete ALL children of a category. For example if Category 1 was deleted Sub Cat 1, Sub Cat 2, Sub sub cat 1, Sub sub cat 2 will be deleted
Any help appreciated.
You could use foreign keys, a very nice feature of mysql. This is a kind of integrity check for referencing different relations. If you create a foreign key, mysql ensures that referenced entries exist, for example. During the creation of a foreign key, you can define what mysql should do if the "parent element" is deleted. You can specify "SET NULL", "UPDATE" or "DELETE CASCADE". This means, if you delete a category, every connected sub category is deleted as well. And because of the fact that every sub category is the parent category of a sub sub category, those are deleted as well.
Here is a simple recursive script for deleting your category and all the nested categories nested inside.
try {
$db = new PDO(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASS);
}catch( PDOException $e ) {
echo $e->getMessage();
}
class Category {
function delete_category($parrent){
global $db;
$stmt = $db->prepare("SELECT `id` FROM `categories` WHERE `parrentId`=:parrentId");
$stmt->execute(array('parrentId'=>$parrent));
while($category = $stmt->fetchObject('Category')){
$category->delete_category($category->id);
}
$stmt = $db->prepare("DELETE FROM `category` WHERE `id` = :id");
$stmt->execute(array('id'=>$parrent));
}
function __construct(array $data = NULL) {
if( empty($data) )
return;
foreach( $data as $field => $value ) {
$this->$field = $value;
}
}}
Where $db is your PDO object for connecting with the database. It may have some bugs, as i just modified mine to suit your problem. Hope this helps.
PS: for calling your function you just do: $category=new Category();
$category->delete_category($_GET['id'])
Quoted my original answer for clarity.
UPDATE 1: The problem with the table splitting is that it isn't clear that there is a fixed number of sub, sub, categories. For this to work, you would need to split into as many tables as there are subcategories, each with foreign keys back to their parent ids. Not practical if the number of sub (or sub sub) categories is dynamic.
This is a situation where I think you would benefit in changing your
table design. If you split the two tables into categories and
subcategories you could take advantage of the foreign key
functionality as described by strauberry. For example (these don't
look like tables, but hopefully this makes sense) Stuff in parentheses
is explanation:
categories
id (primary key)
catName
subcategories
sub_id (primary key)
id (foreign key referencing primary key of categories table)
subCatName
Then when you create the categories table, you can use the ON DELETE
CASCADE option. This will mean that whenever you delete a category
from the categories table, all related subcategories in the
subcategories table will be deleted automatically for you by MySQL.
Powerful, and reduces your code, and you don't have to make sure all
deletions happen in the right tables manually. Hope that clarifies a
little.
UPDATE 2: The problem with this option is, well, it won't work :) MySQL will not allow you to subquery on the same table that you are doing the DELETE on. So what appeared at first to be a simple problem... isn't.
If you can't change the table design then you could do the following
(substitute the id you actually want to delete for
category_id_to_delete):
DELETE FROM categories
WHERE id = category_id_to_delete OR id IN (
SELECT id
FROM categories
WHERE parentID = category_id_to_delete
)
So, I did some more checking, and came across this similar question on SO MySQL: How to find all IDs of children recursively?, and the highest rated answer points to this article Managing Hierarchical Data in MySQL. That article points out the type of queries with LEFT JOINS that you need to use to select data, but doesn't explicitly cover how to delete that data. The recommended solution would be to use the queries related to adjacent sets from the article to select all the id information you need, and then in your code (php I think?) loop over those ids and construct a new query to delete them.
For example, if you are trying to delete Category 1 (id=1), your goal by looping over the ids from the LEFT JOIN query from the article would be to create another query that looks like:
DELETE FROM categories
WHERE id IN (1,3,4,5,6);
The code in this forum post also may help you as a means of doing it recursively in php: Adjacency List Model recursive deletion
I know that isn't a neat and tidy answer, but perhaps this will point you in the right direction.
demonstration of the mysql "cascade on delete" feature. if you run this in your console, then you can just run all the queries at once, and the output will make sense. if you run it in some graphical tool, then i suppose you'll have to run the queries one by one.
CREATE DATABASE `recursivedemo`;
USE `recursivedemo`;
CREATE TABLE `categories` (
`id` INT AUTO_INCREMENT,
`catName` VARCHAR(50),
`parentId` INT,
PRIMARY KEY (`id`),
KEY `parentId` (`parentId`),
CONSTRAINT `categories_fk_self` FOREIGN KEY (`parentId`) REFERENCES `categories`(`id`) ON DELETE CASCADE
) Engine=InnoDB;
SELECT * FROM `categories`;
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Category 1', NULL);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Category 2', NULL);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Sub Cat 1.1', 1);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Sub Cat 1.2', 1);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Sub sub cat 1.2.1', 4);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Sub sub cat 1.2.2', 4);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Sub Cat 2.1', 2);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Sub Cat 2.2', 2);
INSERT INTO `categories`(`catName`, `parentId`) VALUES('Category 3', NULL);
SELECT * FROM `categories`;
DELETE FROM `categories` WHERE `id`=1;
SELECT * FROM `categories`;
DROP DATABASE `recursivedemo`;
You can use following Function in model for deleted nested categories:
public function delete_by_id($cat_id)
{
$this->db->delete('Categories', ['cat_id' => $cat_id]);
$q = $this->db->where('parent_id', $cat_id)->get('Categories');
foreach( $q->result() as $Child ) {
$this->delete_by_id($Child->cat_id);
}
}

Categories