PHP SQL left join fetch all - php

I have 3 mysql tables from where I am trying to fetch data
Table: list
list_id | name | description
-------------------------------------
1234 | name1 | sample description1
1235 | name2 | sample description2
Table: list_to_category
id | list_id | category_id
--------------------------------
1 | 1234 | 1
2 | 1234 | 2
3 | 1234 | 3
4 | 1235 | 2
5 | 1235 | 3
And table: category
id | title | parent_id
--------------------------------
1 | Category 1 | 0
2 | Category 2 | 0
3 | Category 3 | 0
And from PHP SQL query I want to fetch data like below
1. name1 - category 1, category 2, category 3
2. name2 - category 2, category 3
I tried below query
SELECT list.name, category.title FROM list
LEFT JOIN list_to_category
ON list.id = list_to_category.list_id
LEFT JOIN category
ON list_to_category.id = category.id
This gives me only single category name assigned to a list like this
1. name1 - category 1
2. name2 - category 2
Is it possible in single query?

You can use GROUP_CONCAT for this:
select
l.list_id,
l.name,
group_concat(distinct c.title) categories
from list l
left join list_to_category lc
on l.list_id = lc.list_id
left join category c
on lc.category_id = c.id
group by l.list_id

You can try this solution.
select l.list_id, l.name, (select group_concat(c.title) from list_to_category ltc JOIN category c ON c.id=ltc.category_id where ltc.list_id=l.id) from list l
Hope this will help you!!!

Use GROUP_CONCAT for group by "name" to fetch result :
SELECT L.name, GROUP_CONCAT(C.title) as title FROM list L
LEFT outer JOIN list_to_category LC ON L.list_id = LC.list_id
LEFT outer JOIN category C ON LC.category_id = C.id
group by L.name
Use GROUP_CONCAT for group by "list_id" for same name of list to fetch result :
SELECT L.name, GROUP_CONCAT(C.title) as title FROM list L
LEFT outer JOIN list_to_category LC ON L.list_id = LC.list_id
LEFT outer JOIN category C ON LC.category_id = C.id
group by L.list_id

It should be apparent from the code below that I'm no PHP coder. However, this should get the idea across. You can also use javascript/css to handle the transformation, which means things can be even more dynamic...
Oh, and I changed some table/column names - because I like it better that way...
<?php
require('path/to/connection/statements'); // $con
$query = "
SELECT l.list_id
, l.name
, l.description
, c.category_id
, c.title
, c.parent_id
FROM list l
JOIN list_category lc
ON lc.list_id = l.list_id
JOIN category c
ON c.category_id = lc.category_id
ORDER
BY l.list_id
, c.category_id;
";
$result = mysqli_query($con,$query);
$my_array = array();
while($row = mysqli_fetch_assoc($result)){
$my_array[] = $row;
}
$new_array = array();
foreach ($my_array as $row)
{
$new_array[$row['list_id']][$row['name']][$row['description']][] = $row['title'];
}
print_r($new_array);
?>
This will turn an array like this:
Array
(
[0] => Array
(
[list_id] => 1234
[name] => name1
[description] => sample description1
[category_id] => 1
[title] => Category 1
[parent_id] => 0
)
[1] => Array
(
[list_id] => 1234
[name] => name1
[description] => sample description1
[category_id] => 2
[title] => Category 2
[parent_id] => 0
)
[2] => Array
(
[list_id] => 1234
[name] => name1
[description] => sample description1
[category_id] => 3
[title] => Category 3
[parent_id] => 0
)
[3] => Array
(
[list_id] => 1235
[name] => name2
[description] => sample description2
[category_id] => 2
[title] => Category 2
[parent_id] => 0
)
[4] => Array
(
[list_id] => 1235
[name] => name2
[description] => sample description2
[category_id] => 3
[title] => Category 3
[parent_id] => 0
)
)
...into an array like this...
Array
(
[1234] => Array
(
[name1] => Array
(
[sample description1] => Array
(
[0] => Category 1
[1] => Category 2
[2] => Category 3
)
)
)
[1235] => Array
(
[name2] => Array
(
[sample description2] => Array
(
[0] => Category 2
[1] => Category 3
)
)
)
)

try this code
select l.name,c.title
from list_to_category lc join list l on lc.list_id=l.id
join category c on lc.catg_id=c.id

Related

Consolidate Query Results into Single Index

I have a table (usermeta - 2nd below) that is causing my trouble. I need to get 2 values from this table in 1 query and return the results in a single array index.
One table (users) contains the following:
ID | user_email | display_name |
-----+------------------+---------------|
8 | bob#bobjones.com | bob jones |
9 | rob#robsmith.com | rob smith |
Another table (usermeta) contains:
user_id | meta_key | meta_value |
----------+--------------+--------------|
8 | phone_number | 4441234433 |
8 | rep_id | abc123 |
9 | phone_number | 5552323322 |
9 | rep_id | xyz456 |
My SQL query:
function get_this() {
global $db;
$get = $db->get_results("
SELECT
um.meta_key, um.meta_value, um.user_id, user.user_email, user.display_name
FROM
users as user
LEFT OUTER JOIN
usermeta as um
ON
user.ID = um.user_id
WHERE
um.meta_key='rep_id'
OR
um.meta_key='phone_number'
");
return $get;
}
Calling the function: $foo = get_this(); returns this array:
Array
(
[0] => stdClass Object
(
[meta_key] => phone_number
[meta_value] => 4441234433
[user_id] => 8
[user_email] => bob#bobjones.com
[display_name] => bob jones
)
[1] => stdClass Object
(
[meta_key] => rep_id
[meta_value] => abc123
[user_id] => 8
[user_email] => bob#bobjones.com
[display_name] => bob jones
)
[2] => stdClass Object
(
[meta_key] => phone_number
[meta_value] => 5552323322
[user_id] => 9
[user_email] => rob#robsmith.com
[display_name] => rob smith
)
[3] => stdClass Object
(
[meta_key] => rep_id
[meta_value] => xyz456
[user_id] => 9
[user_email] => rob#robsmith.com
[display_name] => rob smith
)
)
The problem I am having is in consolidating the data based on user_id. I'd like to return an array that includes both their phone number AND their rep id along with their user_id, user_email and display_name in one index so I can print something like: bob jones, bob#bobjones.com, 4441234433, abc123
I clearly do not know what question to ask as I've spent 3 days now researching this site and the Internet and trying various combinations of CASE, AND, OR, WHERE, UNION, GROUP etc. to no avail. I am happy to manage this on the PHP end but have failed in that department as well.
You could put two different meta values on the same row of result by joining twice to the meta table:
SELECT user.user_id, user.user_email, user.display_name,
um1.meta_value AS `rep_id`,
um2.meta_value AS `phone_number`
FROM users AS user
LEFT OUTER JOIN usermeta AS um1
ON user.ID = um1.user_id AND um1.meta_key = 'rep_id'
LEFT OUTER JOIN usermeta AS um2
ON user.ID = um2.user_id AND um2.meta_key = 'phone_number'

php list and select data using join tables

I have this database table structure for posts, categories and post_categories
posts:
| id | title | details
| 1 | test | test details
categories:
| id | name | parent_id
| 1 | cat one | 0
| 2 | cat two | 0
| 3 | cat three | 0
post_categories
| category_id | post_id
| 1 | 1
| 2 | 1
I insert multiple categories using input checkbox for each post in post_categories table. Now in update page(domain.com/admin/posts/1/edit) i need to show categories list and checked input checkbox.can i generate this output using join two table(categories and post_categories) Or I need to separate two query(first from post_category table and second from categories table) like this output?! (my choice is join method so how to generate use join method?)
<input type="checkbox" value="1" checked> cat one
<input type="checkbox" value="2" checked> cat two
<input type="checkbox" value="3"> cat three //unchecked (not in post_categories table)
update:
for list categories query:
$query = $this->db->table('categories')
->select('id, name, parent_id')
->get()
->getResultObject();
data in print_r:
Array
(
[0] => stdClass Object
(
[id] => 1
[name] => cat one
[parent_id] => 0
)
[1] => stdClass Object
(
[id] => 2
[name] => cat two
[parent_id] => 0
)
[2] => stdClass Object
(
[id] => 3
[name] => cat three
[parent_id] => 0
)
[3] => stdClass Object
(
[id] => 4
[name] => cat4
[parent_id] => 2
)
[4] => stdClass Object
(
[id] => 5
[name] => cat5
[parent_id] => 0
)
[5] => stdClass Object
(
[id] => 6
[name] => cat6
[parent_id] => 0
)
)
after join:
$query = $this->db->table('categories')
->select('id, name, parent_id')
->join('post_categories', 'post_categories.category_id = id','left outer')
->where('post_categories.post_id', $id)
->get()
->getResultObject();
and data is:
Array
(
[0] => stdClass Object
(
[id] => 1
[name] => cat one
[parent_id] => 0
)
[1] => stdClass Object
(
[id] => 4
[name] => cat two
[parent_id] => 2
)
)
result after join is false.
You can do this with one query but for this, you need one extra column in query for checking category is using or not.
SELECT id, name, if(pc.cat_id IS NULL,0,1) as `value` from categories as ct LEFT JOIN post_categories as pc on pc.cat_id = ct.id
demo link
I hope this query will fulfill your requirements.
If you need more detail about this you can visit this StackOverflow thread
MySQL Join and create new column value
You can run below query to get the categories selected:
select post_categories.category_id from posts
left join post_categories on post_categories.post_id=posts.id
left join categories on post_categories.category_id=categories.id;
get these ids to an array and within your category loop check if the ids are in array and make them checked.
quite easy !

Merge result after query with JOIN clause in Mysql

I have two table like this:
Product
id | title
-------------------------------
1 | Skirt
2 | Pants
Product_thumbnail
id | product_id | image
-------------------------------
1 | 1 | pant.jpg
2 | 1 | shoes.png
When I want to get product with the thumbnail, I query like this:
SELECT p.*, pt.image FROM product p
LEFT JOIN product_thumbnail pt ON pt.product_id = p.id;
The output I expected
[0]=> [
[id] => 1
[image] =>
[
[0] => pant.jpg
[1] => shoes.jpg
]
]
[1]=> [
[id] => 2
[image] => null
]
But the real output
[0]=> [
id => 1
image => pant.jpg
]
[1]=> [
id => 1
image => shoes.jpg
]
[2]=> [
id => 2
image => shoes.jpg
]
As you see, there is 2 element duplicate, so I need to merge it by hand, is there any way to achieve this more easy? Because my table have many tables relate together more than this, I'm using PHP, I use array_merge_recursive() to merge them but if do like that I get duplicate value in each field, like this:
[0]=> [
[id] =>
[
[0] => 1
[1] => 1
]
[image] =>
[
[0] => pant.jpg
[1] => shoes.jpg
]
]
It's not what I want, can anyone give me an idea?
Consider the following. The code could I'm sure be written more economically, but hopefully you get the idea...
<?php
/*
DROP TABLE IF EXISTS product;
CREATE TABLE product
(id SERIAL PRIMARY KEY
,title VARCHAR(12) NOT NULL UNIQUE
);
INSERT INTO product VALUES
(1,'Hat'),
(2,'Shoe');
DROP TABLE IF EXISTS product_thumbnail;
CREATE TABLE product_thumbnail
(id SERIAL PRIMARY KEY
,product_id INT NOT NULL
,image VARCHAR(12) NOT NULL UNIQUE
);
INSERT INTO product_thumbnail VALUES
(1,1,'sombrero.jpg'),
(2,1,'stetson.png');
SELECT p.id
, p.title
, t.image
FROM product p
LEFT
JOIN product_thumbnail t
ON t.product_id = p.id;
+----+-------+--------------+
| id | title | image |
+----+-------+--------------+
| 1 | Hat | sombrero.jpg |
| 1 | Hat | stetson.png |
| 2 | Shoe | NULL |
+----+-------+--------------+
*/
require('path/to/connection/stateme.nts');
$query = "
SELECT p.id
, p.title
, t.image
FROM product p
LEFT
JOIN product_thumbnail t
ON t.product_id = p.id;
";
$result = mysqli_query($db,$query);
$old_array = array();
while($row = mysqli_fetch_assoc($result)){
$old_array[] = $row;
}
$new_array = array();
foreach ($old_array as $row) {
$new_array[$row['id']]['title'] = $row['title'];
$new_array[$row['id']]['image'][] = $row['image'];
}
$new_array = array_values($new_array); // reindex
print_r($new_array);
?>
Outputs
Array
(
[0] => Array
(
[title] => Hat
[image] => Array
(
[0] => sombrero.jpg
[1] => stetson.png
)
)
[1] => Array
(
[title] => Shoe
[image] => Array
(
[0] =>
)
)
)
MySQL doesn't support arrays, but you can aggregate the data into a string:
SELECT p.*, GROUP_CONCAT(pt.image) as images
FROM product p LEFT JOIN
product_thumbnail pt
ON pt.product_id = p.id
GROUP BY p.id;
Note that aggregating only by the id and selecting p.* is allowed and even standard SQL -- assuming that id is a primary key or declared to be unique. This is the one situation when this syntax is permitted.

How to get all categories of a product in PHP/SQL

I have an sql request that retrieves all the products in the database with it's categories using mysqli_fetch_all, problem arises when a product has two categories I have twice the product coming back in the result or n times as many categories the product has and I cain't get it to output properly in the html template if someone explained to me in php or sql how to do what i wish thanks.
products
--------
id
name
etc ...
categories
----------
id
name
category_product
----------------
category_id
product_id
$sql = "SELECT
p.id,
p.name,
p.price,
categories.name as category_name
FROM products as p
JOIN category_product
ON p.id = category_product.product_id
JOIN categories
ON category_product.category_id = categories.id";
output => [0] => Array (
[id] => 3
[name] => product 3
[price] => 1.00
[category_name] => cat 4 )
[1] => Array (
[id] => 3
[name] => product 3
[price] => 1.00
[category_name] => cat 3 )
expected => [0] => Array (
[id] => 3
[name] => product 3
[price] => 1.00
[category_name] => Array(
[0] => cat 3
[1] => cat 4 ]))
Change your query to generate a GROUP_CONCAT of category names, then after fetching you can split that value using explode in PHP. For example (assuming you are using MySQLi with a connection $conn):
$sql = "SELECT
p.id,
p.name,
p.price,
GROUP_CONCAT(categories.name SEPARATOR '|') as category_name
FROM products as p
JOIN category_product ON p.id = category_product.product_id
JOIN categories ON category_product.category_id = categories.id
GROUP BY p.id, p.name, p.price";
$result = $conn->query($sql) or die($conn->error);
while ($row = $result->fetch_assoc()) {
// split the category names into an array
$row['category_name'] = explode('|', $row['category_name']);
// do something with the row value
}
Note that you need to specify a separator to GROUP_CONCAT (in this case I've used |) which will not occur in a category name.

Php, MySql join tables, limit records per category

I have two tables:
Items
ID Name Model_ID
---------------------------------
1 2010 Audi L1 1
2 2014 BMW X2 2
3 2015 Acura L3 3
4 2016 BMW X5 2
5 2012 BMW X3 2
6 2013 BMW X4 2
7 2015 Acura L1 3
8 2011 Acura L2 3
9 2011 Audi L5 1
10 2012 Audi L6 1
Brands
Model_ID Title
---------------------
1 Audi
2 BMW
3 Acura
And following query:
SELECT
b.name,
i.title,
FROM
items AS i
INNER JOIN brands AS b
ON b.Model_ID = i.Model_ID
WHERE i.status = 1
ORDER BY i.created DESC;
The above produces working array:
Array
(
[0] => stdClass Object
(
[name] => 2010 Audi L1
[title] => Audi
)
[1] => stdClass Object
(
[name] => 2014 MBW X5
[title] => BMW
)
...
)
Than I use custom function to loop through array and end up with
Array
(
[Acura] => Array
(
[0] => stdClass Object
(
[name] => 2015 Acura L1
[title] => Acura
)
...
)
[BWM] => Array
(
[0] => stdClass Object
(
[name] => 2016 BMW X5
[title] => BWM
)
...
)
[Audi] => Array
(
[0] => stdClass Object
(
[name] => 2010 Audi L1
[title] => Audi
)
...
)
)
Now I can use foreach loop and limit each Brand to show x number of items, but the idea is to do it within database, so instead of pulling all records, I would like to be able to limit to 5 items per each brand.
Note: I did not list the rest of the table fields, such as created, which is used to sort records.
get brands:
$q = 'SELECT Model_ID AS id FROM brands ORDER BY title ASC';
$r = mysql_query($q);
$model_ids = array();
while($brand = mysql_fetch_assoc($r)) { $model_ids[] = $brand['id']; }
then make generate select query like this using Model_ID-s collected from 1st step or somewhere else (ex: from search form):
$q = array();
foreach($mode_ids AS $model_id) {
$q[] = '(SELECT b.name, i.title FROM items AS i INNER JOIN brands AS b ON b.Model_ID = i.Model_ID WHERE b.Model_ID = '.(int)$model_id.' AND i.status = 1 ORDER BY i.created DESC LIMIT 5)';
}
if(!empty($q)) {
$q = implode(' UNION ALL ', $q);
$r = mysql_query($q);
while($record = mysql_fetch_object($r)) {
var_dump($record);
}
}
as result we'll get records of resulting query:
(SELECT
b.name,
i.title FROM
items AS i
INNER JOIN brands AS b
ON b.Model_ID = i.Model_ID WHERE b.Model_ID=1 AND i.status = 1 ORDER BY i.created DESC LIMIT 5)
UNION ALL
(SELECT
b.name,
i.title FROM
items AS i
INNER JOIN brands AS b
ON b.Model_ID = i.Model_ID WHERE b.Model_ID=2 AND i.status = 1 ORDER BY i.created DESC LIMIT 5)
UNION ALL
(SELECT
b.name,
i.title FROM
items AS i
INNER JOIN brands AS b
ON b.Model_ID = i.Model_ID WHERE b.Model_ID=3 AND i.status = 1 ORDER BY i.created DESC LIMIT 5)

Categories