How to retrieve every combination of numbers from 2 columns - mysql

I'm trying to find a way to retrieve every combination of values from two columns in a table, where each combination matches a value in a third column.
Say part of the table looks like this:
products_id options_id options_values_id
1487 2 1
1487 2 61
1487 3 60
1487 5 52
My desired output, when working with products_id 1487, would be the following two strings:
2-1, 3-60, 5-52
2-61, 3-60, 5-52
I've got the impression that those strings would need to be assembled recursively, but I ran into trouble trying it that way because not every products_id has the same options_ids, or the same number of them.
Edited to add: I've tried variations of a couple of the solutions below, but to no avail. I think I should have been more descriptive.
I'm trying to have it retrieve every combination of unique options_id and its corresponding options_values_id. (In other words, not every single possible combination of numbers from those two columns.) Options_id represents product options like "color" and "size," and options_values_id represents choices of those options, like "red" or "small." So I'm trying to come up with every possible combination of options for a given products_id. In the example above, there are two possible option combinations for that item-- "2-1, 3-60, 5-52" and "2-61, 3-60, 5-52".

Join the table against itself for each distinct option.
Do a select first to retrieve the number of options.
$tables = array();
$rs = mysql_query(
'SELECT DISTINCT options_id FROM table WHERE products_id = '.$id);
while ($row = mysql_fetch_row($rs)) {
$tables[$row['options_id']] =
'SELECT options_values_id FROM table WHERE products_id = '.$id.
' AND options_id = '.$row['options_id'];
}
mysql_free_result($rs);
Then, for each option, join it in as a separate table in your query. Do not include any joining clauses comparing values, just join every record against every other record.
$sql = 'SELECT ';
$count = 0;
foreach ($tables AS $id => $query) {
if ($count++) $sql .= ', ;
$sql .= 'table_'.$id.'.options_values_id AS value_'.$id;
}
$sql .= ' FROM ';
$count = 0;
foreach ($tables AS $id => $query) {
if ($count++) $sql .= ', ';
$sql .= '('.$query.') AS table_'.$id;
}
Finally, execute that query. Each row will contain one column per options_id. There will be one row per unique combination of values.

or for a mixed, php/sql approach, try using that SQL query:
SELECT products_id, options_id, options_values_id WHERE products_id = '$var_with_product_id';
fetch the results into an array, say $results:
$pairs = array();
foreach($results as $result) {
// build array with pairs (array_push to avoid overwriting)
array_push($pairs, array( $result['options_id'] => $result['options_values_id'];
}
// a bit extra complication, as array_push adds e.g. [0] => array( options_id => options_values_id ) :)
$pairs = array_values($pairs);
// check for double options_id
$found_double_options_id = false;
do {
// check for duplicates... use a lot of array functions
} while (count($pairs) && $found_double_options_id);

"Every combination" is the Cartesian product:
SELECT DISTINCT e1.options_id, e2.options_values_id
FROM Entity e1, Entity e2
WHERE e1.products_id = 1487 AND e2.products_id=1487

Related

MySql - Inserting array values (matching and unmatching) into db matching columns

So I have a list of optional clothing items as checkboxes, there may be a greater number than the 5 below.
shoes, pants, skirt, socks, jacket //list of possible choices
A comma separated array is created in jquery of the chosen item. Let's say the following are chosen:
shoes, socks, jacket //array posted as $_POST['clothes']
In the db, each customer has these options in the clothes table with 'yes' or 'no' under the clothing items. However, the clothing item are named a bit differently but map out to the same options:
'clothes' table before insert
customer_id dress_shoes elegant_pants long_skirt ankle_socks biker_jacket
1 no yes no no no
With the $_POST['clothes'], I'm trying to loop through the array, updating the corresponding fields to 'yes', and the non corresponding fields to 'no' in the db. I have a hard time doing that.
'clothes' table after insert
customer_id dress_shoes elegant_pants long_skirt ankle_socks biker_jacket
1 yes no no yes yes
I did an array_intersect to get the items to mark as 'yes':
$clothesArray = array("shoes", "socks", "jacket"); // Posted clothes
$clothesArrayAll = array("shoes", "pants", "skirt", "socks", "jacket"); // All clothes
$common = array_intersect($clothesArrayAll,$clothesArray);
print_r($common);
Array ( [0] => shoes [3] => socks [4] => jacket )
I'm trying to somehow loop through the $clothesArrayAll, give a 'yes' to common clothes, and a 'no' to all others in the array. Then, I'm trying to update the 'clothes' table via PDO, setting each corresponding field to a 'yes' or 'no' in the most efficient way. I'm stuck after getting the common clothes array above and not sure how to proceed.
Can someone help me please?
Thank you!
I think you are on the right track. I would just add one additional array that contains the mappings of your fields, e.g.
$mappingArray = array('shoes' => 'dress_shoes', 'socks' => 'ankle_socks', ...);
With this array and the previous you can loop through and set your SQL accordingly based on the value of the $common field with the key in the $mappingArray
Edit with example (probably not the most optimized):
$finalArray = array();
foreach ($mappingArray as $key => $value) {
$finalArray[$value] = in_array($key, $common) ? 'yes' : 'no';
}
$finalArray will now have an yes/no statement for each value that matches your db table.
Edit to include PDO: I would actually update the above loop as follows:
$finalArray = array();
$sql = "INSERT INTO cloths (" . implode(",", array_values($mappingArray)) . ") VALUES (:" . implode(",:", array_values($mappingArray)) . ")";;
foreach ($mappingArray as $key => $value) {
$finalArray[":" . $value] = in_array($key, $common) ? 'yes' : 'no';
}
$q = $conn->prepare($sql);
$q->execute($finalArray);
Going on the fly with this one, so something like that...
Why not change your HTML field names to match your database names, set a default of 'no' in the atabase then...
$cols='INSERT INTO clothes ';
$values=' VALUES ';
$join='(';
foreach ($_POST as $key=>$val) {
$cols.=$join . $key;
$values=$join . ':' . $key;
$join=',';
}
$qry=$cols . ')' . $values . ')';
$stmt = $dbh->prepare($qry);
foreach ($_POST as $key=>$val) {
$stmt->bindParam(':' . $key, $_POST[$key]);
}
But you might want to check the posted names are valid column names - you can get the column names and types from the table using
DESC clothes;

MySQL query involving multiple rows, access one based on max value

So I am trying to have a single script that accesses all values of a table based on a particular id. The script returns the values in an array using PHP:
Example:
// Select data from DB
$query = 'SELECT * FROM experiences WHERE user_id = ' . $id;
$result = mysqli_query($link, $query) or die (mysqli_error($link));
// Not sure this actually creates a 2D array...
$array = mysqli_fetch_array($result);
However, I realize that I need modified results for particular tasks, such as the row where a particular value is the highest.
How would I go about doing this, and does $array actually hold all the rows and respective fields?
TRY
'SELECT * FROM experiences WHERE user_id ='.$id.' HAVING MAX(column_name)
OR
"SELECT max(column_name), other column...
FROM experiences
WHERE user_id =".(int)$id
Assuming you have cleaned $id properly you can do this
// Select data from DB
$query = 'SELECT * FROM experiences WHERE user_id = ' . $id;
$result = mysqli_query($link, $query) or die (mysqli_error($link));
$data = array();
while($row = mysqli_fetch_array($result)) {
$data[] = $row;
}
and $data will contain the 2D array you're looking for.
If you want the row where a particular value is highest I suggest either looking into ORDER BY or MAX() depending on your needs.

Order by clause in MySQL is not working inside a foreach loop

I'm trying to get the profiles names which are assigned to a specific subcategory
with id=9. When I run the code below, I get the profiles that I want but for some
reason the ORDER BY clause in the foreach loop doesn't sort them by their name
alphabetically. Instead they are ordered in the same way they are ordered inside the
'profiles' field in 'subcategories' table (the IDs for the profiles are comma separated).
For example if in subcategories['profiles'] I have ',5,1,2' the profiles names will be displayed
in the following order:
Profile with ID=5
Profile with ID=1
Profile with ID=2
I'm using the explode() function to get the ID for each profile inside the 'subcategory'
table and then use that ID to retrieve their information from the 'profile' table using
a query inside the foreach loop.
Am I missing anything here? Thanks for your help.
Here's my code:
<?php
$subcategories=mysql_query("select * from subcategories where id='9'");
while ($subcategories = mysql_fetch_array($subcategories))
{
$profiles = $subcategories['profiles'];
$profiles = explode(',', $profiles);
foreach ($profiles as $p)
{
$all_places = mysql_query("select * from profile where id='$p' and active='1' order by name asc");
while ($profile = mysql_fetch_array($all_places))
{
echo $profile['name'];
}
}
}
?>
Well the reason why your results do not order by name is because you are retrieving every profile with a new SQL query in your foreach loop for $profiles. So effectively in your scenario, you will end up with 3 SQL queries that returns 1 profile each. Hence, when the "order by" clause is declared, it orders by name within each query, which only contains 1 result each.
does using an IN statement work for you? Eg.
<?php
$subcategories=mysql_query("select * from subcategories where id='9'");
while ($subcategories = mysql_fetch_array($subcategories))
{
//i assume $subcategories['profiles'] are integers separated by comma as mentioned
$profiles = $subcategories['profiles'];
$all_places = mysql_query("select * from profile where id IN ($profiles) and active='1' order by name asc");
while ($profile = mysql_fetch_array($all_places))
{
echo $profile['name'];
}
}
?>

Zend_Db: How to get the number of rows from a table?

I want to find out how many rows are in a table. The database that I am using is a MySQL database. I already have a Db_Table class that I am using for calls like fetchAll(). But I don't need any information from the table, just the row count. How can I get a count of all the rows in the table without calling fetchAll()?
$count = $db->fetchOne( 'SELECT COUNT(*) AS count FROM yourTable' );
Counting rows with fetchAll considered harmful.
Here's how to do it the Zend_Db_Select way:
$habits_table = new Habits(); /* #var $habits_table Zend_Db_Table_Abstract */
$select = $habits_table->select();
$select->from($habits_table->info(Habits::NAME), 'count(*) as COUNT');
$result = $habits_table->fetchRow($select);
print_r($result['COUNT']);die;
Proper Zend-Way is to use Zend_Db_Select like this:
$sql = $table->select()->columns(array('name', 'email', 'status'))->where('status = 1')->order('name');
$data = $table->fetchAll($sql);
$sql->reset('columns')->columns(new Zend_Db_Expr('COUNT(*)'));
$count = $table->getAdapter()->fetchOne($sql);
This is how it's done in Zend_Paginator. Other option is to add SQL_CALC_FOUND_ROWS before your column list and then get the number of found rows with this query:
$count = $this->getAdapter()->fetchOne('SELECT FOUND_ROWS()');
You could do a
SELECT COUNT(*)
FROM your_table
$dbo->setFetchMode( Zend_Db::FETCH_OBJ );
$sql = 'SELECT COUNT(*) AS count FROM #table';
$res = $dbo->fetchAll( $sql );
// $res[0]->count contains the number of rows
I'm kind of a minimalist:
public function count()
{
$rows = $db->select()->from($db, 'count(*) as amt')->query()->fetchAll();
return($rows[0]['amt']);
}
Can be used generically on all tables.
Add count capability to your Zend_DB Object To count all table rows
public function count()
{
return (int) $this->_table->getAdapter()->fetchOne(
$this->_table->select()->from($this->_table, 'COUNT(id)')
);
}

How to select multiple records (row) from a column in mysql?

I want to display four (4) items'name from these id:
Can I do like this?
SELECT item_name from items WHERE item_id IN ('001', '012', '103', '500')
or
SELECT item_name from items WHERE item_id = '001' or item_id = '012' or item_id = '103' or item_id = '500'
IN RESPONSE TO ALL ANSWERS
Well, most of the answers said it works, but it does not really work. Here is my code:
$query = "SELECT `item_name` from items WHERE item_id IN('s001','a012','t103','p500')";
$result = mysql_query($query, $conn) or die (mysql_error());
$fetch = mysql_fetch_assoc($result) or die (mysql_error());
$itemsCollected = $fetch['item_name'];
echo $itemsCollected;
The item_id is alphanumeric.
You can do either one, but the IN query is much more efficient for this purpose for any large queries. I did some simple testing long ago that revealed it's about 10 times faster to use the IN construct for this. If you're asking if the syntax is correct then yes, it looks fine, other than missing semi-colons to complete the statement.
EDIT: It looks like the actual question you were asking was "why do these queries only return one value". Well, looking at the sample code you posted, the problem is here:
$fetch = mysql_fetch_assoc($result) or die (mysql_error());
$itemsCollected = $fetch['item_name'];
echo $itemsCollected;
You need to loop through and iterate until there are no more results to be fetched, as Pax pointed out. See the PHP manual page for mysql_fetch_assoc:
$sql = "SELECT item_name from items WHERE item_id IN('s001','a012')";
$result = mysql_query($sql);
if (!$result) {
echo "Could not successfully run query ($sql) from DB: " . mysql_error();
exit;
}
if (mysql_num_rows($result) == 0) {
echo "No rows found, nothing to print so am exiting";
exit;
}
// While a row of data exists, put that row in $row as an associative array
// Note: If you're expecting just one row, no need to use a loop
// Note: If you put extract($row); inside the following loop, you'll
// then create $userid, $fullname, and $userstatus
while ($row = mysql_fetch_assoc($result)) {
echo $row["userid"];
echo $row["fullname"];
echo $row["userstatus"];
}
mysql_free_result($result);
Yes, both those should work fine. What's the actual problem you're seeing?
If, as you say, only one record is being returned, try:
select item_name from items order by item_id
and check the full output to ensure you have entries for 001, 012, 103 and 500.
If both those queries only return one row, I would suspect not.
If they all do exist, check the table definitions, it may be that the column is CHAR(4) and contains spaces for the others. You may have genuinely found a bug in MySQL but I doubt it.
After EDIT:
This is a perl/mysql problem, not an SQL one: mysql_fetch_array() returns only one row of the dataset at a time and advances a pointer to the next.
You need to do something like:
$query = "SELECT item_name from items WHERE item_id IN('s001','a012')";
$result = mysql_query($query, $conn) or die (mysql_error());
if (mysql_num_rows($result) == 0) {
echo "No rows found, nothing to print so am exiting";
exit;
}
while ($row = mysql_fetch_assoc($result)) {
echo $row["item_name"];
}
Your ID field must be set to auto increment, i guess. i had problems with that once and i changed the auto increment to int. in the IN field if you pass the parameters to match against the auto increment variable you get back only the first parameter, the remaining generates an error.
Use mysql_fetch_assoc to get the query and assign the values from mysql_fetch_assoc query into a an array. Simple as that
$i=0;
$fullArray = array();
$query = mysql_query("SELECT name FROM users WHERE id='111' OR id='112' OR id='113' ")or die(mysql_error());
while($row = mysql_fetch_assoc($query)){
foreach ($row as $value) {
$fullArray[$i] = $value;
}
$i++;
}
var_dump($fullArray);
echo $fullArray[0]."<br/>".$fullArray[1]."<br/>".$fullArray[2];`
You could also use the mysql_num_rows function to tell you how many rows your query retrieved and then use that result to increment a for loop. An example.
$num_rows=mysql_num_rows($query_results);
for ($i=0; $i <$num_rows ; $i++) {
$query_array[]=mysql_fetch_assoc($query_results);
}