How to generate a query using an array of delimited columns & values - php

I have this array:
$filter=['color*black','color*blue','color*red','paint*apex','paint*dalton'];
Each value in $filter has two substrings separated by *. The first substring represents a database table column and the second represents a desired value for that column.
My products table looks like this:
id name color paint
1 p1 black compo
2 p2 red dalton
3 p3 pink apex
4 p4 blue apex
5 p5 cream compo
Using $filter, I need to search the products table and return all rows with a paint value of apex or dalton AND a color value of black, blue, or red.
The desired output is a mysql query that will only return these rows:
id name color paint
2 p2 red dalton
4 p4 blue apex

If You need to construct a query like this SELECT * FROM products WHERE (color IN ('black', 'blue', 'red')) AND (paint IN ('apex', 'dalton')), then the code below might be useful (please, check it here):
$filter = array(
0 => "color*black",
1 => "color*blue",
2 => "color*red",
3 => "paint*apex",
4 => "paint*dalton"
);
$elements = [];
foreach ($filter as $value) {
list($before, $after) = explode('*', $value);
$elements[$before][] = $after;
}
$parts = [];
foreach ($elements as $column => $values) {
$parts[] = "(`$column` IN ('" . implode("', '", $values) . "'))";
}
$query = 'SELECT * FROM `products` WHERE ' . implode(' AND ', $parts);
Running this query against the given table data structure:
id name color paint
1 p1 black compo
2 p2 red dalton
3 p3 pink apex
4 p4 blue apex
5 p5 cream compo
will match the following rows:
2 p2 red dalton
4 p4 blue apex

Here we are using explode, foreach and array_values to achieve desired output.
Try this code snippet here
<?php
$filter = array(
0 => "color*black",
1 => "color*blue",
2 => "color*red",
3 => "paint*apex",
4 => "paint*dalton");
$result=array();
foreach($filter as $value)
{
list($before,$after)=explode("*",$value);
$result["before"][$before]=$before;
$result["after"][$after]=$after;
}
$result["before"]= array_values($result["before"]);
$result["after"]= array_values($result["after"]);
print_r($result);
Output:
Array
(
[before] => Array
(
[0] => color
[1] => paint
)
[after] => Array
(
[0] => black
[1] => blue
[2] => red
[3] => apex
[4] => dalton
)
)

Related

How to create a three dimensional array from sql query PHP

I have 2 tables in a database, 1 of them are linked with a foreign key to the first one. Each row on table 1 is linked to multiple rows in table 2. I am trying to make a query that looks at a WHERE from table 2 and returns multiple rows from table 2 which are sorted into the rows they linked with in table 1 and then put this all into one big multi dimensional array, so it should work something like this:
$array[0][column_name][0] this would use row 1 from table 1 and give me a the first result in the column called column_name
$array[1][column_name][0] this would use row 2 from table 1 and give me a the first result in the column called column_name
$array[1][column_name][3] this would use row 2 from table 1 and give me a the 4th result in the column called column_name
etc
How can I query this and store it in a 3 dimensional array using PHP.
I have tried to word this in as clear manner as possible, if you are unsure what I am asking, please comment and I will update my question to make it clearer.
Assume that we have two tables, Company and Employee:
Company
------------------
ID Company_Name
1 Walmart
2 Amazon.com
3 Apple
Employee
---------------------------------
ID Company_Id Employee_Name
1 1 Sam Walton
2 1 Rob Walton
3 1 Jim Walton
4 1 Alice Walton
5 2 Jeff Bezos
6 2 Brian T. Olsavsky
7 3 Steve Jobs
8 3 Tim Cook
The easiest way to envision a multi-dimensional (nested) array is to mimic the looping required to get it: outer loop is the company, inner loop is the employees:
// ignoring database access, this is just pseudo code
$outer = [];
// select id, company_name from company
foreach $companyResult as $companyRow {
// select * from employee where company_id = ? {$companyRow['id']}
$inner= [];
foreach $employee_result as $employeeRow {
$inner[] = $employeeRow; // ie, ['id'=>'1','Company_Id'=>'1','Employee_Name'=>'Sam Walton']
}
$outer[] = $inner;
}
print_r($outer);
// yields ====>
Array
(
[0] => Array
(
[0] => Array
(
[id] => 1
[Company_Id] => 1
[Employee_Name] => Sam Walton
)
[1] => Array
(
[id] => 2
[Company_Id] => 1
[Employee_Name] => Rob Walton
)
[2] => Array
(
[id] => 3
[Company_Id] => 1
[Employee_Name] => Jim Walton
)
[3] => Array
(
[id] => 4
[Company_Id] => 1
[Employee_Name] => Alice Walton
)
)
[1] => Array
(
[0] => Array
(
[id] => 5
[Company_Id] => 2
[Employee_Name] => Jeff Bezos
)
[1] => Array
(
[id] => 6
[Company_Id] => 2
[Employee_Name] => Brian T. Olsavsky
)
)
[2] => Array
(
[0] => Array
(
[id] => 7
[Company_Id] => 3
[Employee_Name] => Steve Jobs
)
[1] => Array
(
[id] => 8
[Company_Id] => 3
[Employee_Name] => Tim Cook
)
)
)
It is also possible to do if you use associative arrays. Consider the flat file that this query produces:
select company.id company_id, company.name company_name,
emp.id employee_id, emp.employee_name
from company
inner join employee on company.id = employee.company_id
-----
company_id company_name employee_id employee_name
1 Walmart 1 Sam Walton
1 Walmart 2 Rob Walton
1 Walmart 3 Jim Walton
1 Walmart 4 Alice Walton
2 Amazon.com 5 Jeff Bezos
2 Amazon.com 6 Brian T. Olsavsky
3 Apple 7 Steve Jobs
3 Apple 8 Tim Cook
Just use the primary IDs as the keys for your arrays:
$employeeList = [];
foreach($result as $row) {
$cid = $row['company_name'];
$eid = $row['employee_name'];
// avoid uninitialized variable
// $employeeList[$row['company_name']] = $employeeList[$row['company_name']] ?? [];
// easier to read version of above
$employeeList[$cid] = $employeeList[$cid] ?? [];
// assign it...
$employeeList[$cid][$eid] = $row;
}
Or, if you simply want each company row to hold an array of employee names,
$employeeList[$cid][] = $row['employee_name'];
The way that I've shown you is useful if you know the company_id and want to find the associated rows:
foreach($employeeList[2] as $amazon_guys) { ... }
But it's not at all useful if you're trying to group by employee, or some other field in the employee table. You'd have to organize the order of your indexes by your desired search order.
In the end, it's almost always better to simply do another query and let the database give you the specific results you want.

How to create parent child relation in php

two tables Location and Routes. Location table contains following fields and values
id | name
1 | bangalore
2 | mumbai
3 | kolkatta
4 | delhi
Routes table contains following fields and values
id | source | desination
1 | 1 | 4
2 | 1 | 2
3 | 1 | 3
4 | 2 | 4
5 | 2 | 3
6 | 3 | 4
want to find all possible routes from source to destination like
bangalore-delhi
bangalore-mumbai-delhi
bangalore-mumbai-kolkatta-delhi
bangalore-kolkatta-delhi
please help me to achieve this result
Using your existing data from your two tables, you could LEFT JOIN columns source and destination from Routes meaning your INT values will match up to the Location.name column. Then make sure you order the data by source column for so it's easier to sort with PHP later on.
MySQL:
SELECT locStart.name as start, locFinish.name as finish FROM `routes`
LEFT JOIN location as locStart
ON routes.source = locStart.id
LEFT JOIN location as locFinish
ON routes.destination = locFinish.id
ORDER BY routes.source
Output:
array (
0 =>
array (
'start' => ' bangalore',
'finish' => 'delhi',
),
1 =>
array (
'start' => ' bangalore',
'finish' => 'mumbai',
),
2 =>
array (
'start' => ' bangalore',
'finish' => 'kolkatta',
),
//Etc....
Then add your DB results into multidimensional array using the Source name as the key.
$stmt = $pdo->query($query);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
$newArr;
foreach ($result as $v) {
$newArr[$v['start']][] = $v['finish'];
}
Output:
array (
' bangalore' =>
array (
0 => 'delhi',
1 => 'mumbai',
2 => 'kolkatta',
),
'mumbai' =>
array (
0 => 'delhi',
1 => 'kolkatta',
),
'kolkatta' =>
array (
0 => 'delhi',
),
)
For outputting the new array, you can use a recursive function:
function recurse($newArr, $key=NULL) {
if($key !== NULL) {
foreach ($newArr[$key] as $k=>$v) {
echo '<li>Destination: ' . $v . '</li>';
}
echo '</ul>';
} else {
foreach ($newArr as $k=>$v) {
echo 'Source: ' . $k . '<br><ul>';
recurse($newArr, $k);
}
}
}
Output:
Source: bangalore
Destination: delhi
Destination: mumbai
Destination: kolkatta
Source: mumbai
Destination: delhi
Destination: kolkatta
Source: kolkatta
Destination: delhi

How to execute that in 1 query?

I have 2 tables customer and orders:
customers:
| custID | Name | Age |
|--------|-------|-----|
| 1 | Peter | 23 |
| 2 | Julie | 34 |
| 3 | Tom | 45 |
orders:
| custID | product | color |
|--------|---------|-------|
| 1 | shirt | blue |
| 1 | jacket | black |
| 2 | jacket | green |
| 3 | hat | grey |
| 3 | shirt | white |
I now want to get all customers and their orders, ordered as a list. So something like that:
Array
(
[0] => Array
(
[ID] => 1
[name] => Peter
[age] => 23
[orders] => Array
(
[0] => Array
(
[product] => shirt
[color] => blue
)
[1] => Array
(
[product] => jacket
[color] => black
)
)
)
[1] => Array
(
[ID] => 2
[name] => Julie
[age] => 34
[orders] => Array
(
[0] => Array
(
[product] => jacket
[color] => green
)
)
)
[2] => Array
(
[ID] => 3
[name] => Tom
[age] => 45
[orders] => Array
(
[0] => Array
(
[product] => hat
[color] => grey
)
[1] => Array
(
[product] => shirt
[color] => white
)
)
)
)
When I do:
SELECT name, age, product, color
FROM `customers`, `orders`
where `customers`.`id` = `orders`.id
group by name
I get:
| name | age | product | color |
|-------|-----|---------|-------|
| Peter | 23 | jacket | green |
| Julie | 34 | shirt | blue |
| Tom | 45 | hat | grey |
Is this even possible with only one query?
You could simply make the query below:
SELECT *
FROM customers
JOIN orders
USING custID
GROUP BY Name
ORDER BY custID ASC;
A couple of steps here...
First, you should run the following query:
SELECT
`customers`.`id`,
`customers`.`name`,
`customers`.`age`,
`orders`.`product`,
`orders`.`color`
FROM `customers`, `orders`
where `customers`.`id` = `orders`.`id`
order by `customers`.`id`
Which should give you de-normalized tabular data that looks something like this:
$array = array(
array("id" => 1, "name" => "Peter", "age" => 23, "product" => "shirt", "color" => "blue"),
array("id" => 1, "name" => "Peter", "age" => 23, "product" => "jacket", "color" => "black"),
array("id" => 2, "name" => "Julie", "age" => 34, "product" => "jacket", "color" => "green"),
array("id" => 3, "name" => "Tom", "age" => 45, "product" => "hat", "color" => "grey"),
array("id" => 3, "name" => "Tom", "age" => 45, "product" => "shirt", "color" => "white")
);
You can then transform the that data into your desired format as follows:
$transformed = array();
$i = 0;
while ($i < count($array)) {
$id = $array[$i]["id"];
$name = $array[$i]["name"];
$age = $array[$i]["age"];
$products = array();
while ($i < count($array) && $id == $array[$i]["id"]) {
array_push($products, array("product" => $array[$i]["product"], "color" => $array[$i]["color"]));
$i++;
}
array_push($transformed, array("id" => $id, "name" => $name, "age" => $age, "products" => $products));
}
http://sandbox.onlinephpfunctions.com/code/6fe856e1f71f699e84215b6f66d25589f71e255e
i think you should user INNER JOIN:
SELECT * FROM customers AS c INNER JOIN orders AS o ON c.custID = o.custID GROUP BY c.custID ORDER BY c.custID ASC;
There is no point in trying to achieve the desired outcome with single query. With the first query get the list of customers. Then perform a second query, which will load all the orders for the customers from the first query. And in a loop match orders to respective customers.
EDIT: something like this
$result = [];
$customers = $pdo->query("SELECT * FROM `customers`")->fetchAll();
foreach ($customers as $c) {
$result[$c['id']] = $c;
}
$orders = $pdo->query("SELECT * FROM `orders` WHERE `custID` IN (".implode(', ', array_keys($result).")");
foreach ($orders as $o) {
if (!isset($result[$o['custId']]['orders']))
$result[$o['custId']]['orders'] = [];
$result[$o['custId']]['orders'][] = $o;
}
Your sql SELECT name, age, product, color FROMcustomers,orderswherecustomers.id=orders.id group by name is fine, just add the customer id and order id also in the sql. Then, in PHP, as you iterate the result set, populate the customer info first (id, name, age) with customer id as the key and name, age as value as an array. Likewise, populate the order for that customer in the key 'orders' with the order id as key and value as an array (product, color).
Once you have the array populated, iterate over that array and keep putting things into a new array since the output you want is an array with sequential keys (0, 1, 2 etc) instead of customer id.
$initialList = array();
while($row = $result->fetch_assoc()) {
if(!array_key_exists($row['customer_id'], $initialList)) {
$initialList[$row['customer_id']] = array(
'name' => $row['name'],
'age' => $row['age'],
'orders' => array()
);
}
$initialList[$row['customer_id']]['orders'][] = array(
'product' => $row['product'],
'color' => $row['color']
);
}
$finalList = array();
foreach($initialList as $customerId => $customer) {
$customer['ID'] = $customerId;
$finalList[] = $customer;
}
//to print and check the array
print_r($finalList);
try this:
SELECT c.custID,c.name, c.age, group_concat(CONCAT_WS(':',o.product,o.color)SEPARATOR ',') as productos
FROM customers AS c
INNER JOIN orders AS o ON c.custID = o.custID
GROUP BY c.custID;
You just have to parse the products.
$array=array();
while($r = $res->fetch_assoc()) {
$id=$row['custID'];
$name=$row['name'];
$age=$row['age'];
$productos=$row['productos'];
$productsSeparats = explode(',',$productos);
$orders=array();
foreach ($productsSeparats as $value) {
$ar=explode(':',$value);
array_push($orders, array("product" => $ar[0], "color" => $ar[1]));
}
array_push($array, array("id" => $id, "name" => $name, "age" => $age, "orders" => $orders));
}

How to output product variations

I would like some advice on how best to approach outputting multiple products and their variations from a database.
I am building an eCommerce application and need to output a series of products and their product variations (colour, size).
My database has:
Table 1: ProductID, ProductTitle, ProductImg, ProductCat
Table 2: ProductID, ProductSize, ProductColour
Foreign key on ProductID
My current code is this:
<?php
$q = $_GET['cat']; // this pulls the category from URL param
include 'db_connect.php';
$result = mysqli_query($con, "SELECT DISTINCT a.ProductTitle, a.ProductImg, b.ProductColour
FROM product_info AS a
JOIN product_options AS b ON a.ProductID=b.ProductID
WHERE a.ProductCat = '".$q."'");
while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
echo "<div class='product-display'>";
echo "<img id='prodImage' src='Images/" . $row['ProductImg'] . ".jpg' alt='product photo'>";
echo "<h3>" . $row['ProductTitle'] . "</h3>";
echo "<h3>" . $row['ProductColour'] . "</h3>";
echo "</div>";
}
?>
This outputs:
Product 1, Colour 1
Product 1, Colour 2
Product 2, Colour 1
Product 2, Colour 2
Product 3, Colour 1
Product 3, Colour 2
I want it to output:
Product 1, Colour 1, Colour 2
Product 2, Colour 1, Colour 2
Product 3, Colour 1, Colour 2
What is the best way to achieve this?
FYI - my array output is this:
Array ( [ProductTitle] => Puffer Jacket [ProductImg] => 444 [ProductColour] => Aubern )
Array ( [ProductTitle] => Puffer Jacket [ProductImg] => 444 [ProductColour] => Black )
Array ( [ProductTitle] => The Bander [ProductImg] => 111 [ProductColour] => Aubern )
Array ( [ProductTitle] => The Bander [ProductImg] => 111 [ProductColour] => Black )
Array ( [ProductTitle] => The comfy one [ProductImg] => 222 [ProductColour] => Aubern )
Array ( [ProductTitle] => The comfy one [ProductImg] => 222 [ProductColour] => Black )
SOLUTION:
Please refer to:
Parsing one col of multiple rows php
and
SQL JOIN - Need to return one product id but all variations of it (e.g. Size, colour)
These answer it nicely... problem solved.

Count values in array and calculate top 4

I have CSV list with team names in it (this is one row):
Teams
Red
Green | Red | Yellow
Red
Yellow | Green | Yellow
Red
Green
Yellow | Yellow | Red
Red
Green
Red
Yellow
I need to be able to count each individual color and count top 4
and number of times they appear.
How can I do that? For example if i try using:
$teams = file('count.csv');
$count[] = (array_count_values($colors));
print_r($count);
I get:
Array ( [0] => Array ( [Teams ] => 1
[Red ] => 5 [Green | Red | Yellow ] => 1 [Yellow | Green | Yellow ] => 1 [Green ] => 2 [Yellow | Yellow | Red ] => 1 [Yellow] => 1 ) )
Which is not very useful. And afrewards how could I compare the valies to one another to get top 4?
Any tricks known how to make this happen? Thank you in advance!
OK another try:
$inputfile = 'count.csv';
$inputHandle = fopen($inputfile, "r");
while (($data = fgetcsv($inputHandle, 1024, ",")) !== FALSE) {
$teams = $data[0];
$teams = explode('|', $teams);
}
$count[] = (array_count_values($teams));
print("<pre>".print_r($count, true)."</pre>");
I get
Array
(
[0] => Array
(
[Yellow] => 1
)
)
What am I doing wrong?
If I understand correctly, you've got one row of data, with | as the delimiter.
Here's a very crude quick'n'dirty solution.
What I would do is first use strpos() and substr() to get the colors, and use a switch-case to increment counters for each color. To get the top 4, create an array to hold four strings, insert the first four colors, and then compare the remaining colors to each value in the array, overwriting values in the array if the color you're comparing has a higher count than any value in the array.
This sounds a bit confusing, so let me know if you'd like me to write some sample code demonstrating this.

Categories