Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

PHP

MySQL Query help

I have the following MySQL table: T_Product_Codes

with the following columns: id (autoincrement), productid, code1, code2, code3

1 productid can have several rows in the table, for example:

SELECT productid, code1, code2, code3
FROM T_Product_Codes
WHERE productid = '12345652'

Result:
productid     code1            code2                       code3
123456        FIXATION       PRODUCTTYPE       BANDAID       
123456        FIXATION       LENGTH                   33CM
123456        FIXATION       WIDTH                      5CM

Now, I need to know all the productid's that have those same characteristics as this one. So, I have the productid (123456 in this case). And I need to know which other productid's also have those three code1, code2 and code3 characteristics in this same table. Other products can have more than these three rows, but not less.

That way, I can see which other products could be used in stead of this one, like comparable products.

I can't seem to figure it out on my own ... any help would be greatly appreciated!

If I'm understanding your question correctly you want to return all rows where the productid is equal to 123456 and code1 equals FIXATION.

You should be able to add an AND to the WHERE statement. So WHERE productid = 123456 AND code1 = 'fixation';

Hello Michael,

No, I want to know all the product id's that have the same characteristics as this productid.

For example: I have this product 123456. What other products could I use in stead of this one?

then I would need the following

SELECT DISTINCT productid
FROM T_Product_Codes
WHERE code1, code2, code3 IN (
    SELECT code1, code2, code3
    FROM T_Product_Codes
    WHERE productid = '12345652'
)

only, with this query, it's an OR situation, and I need an AND situation. The comparable products that I want to find, need to have all the same code1, code2, code3 combinations. It can have more combinations, but they need to have at least the ones that this product has.

Ken Alger
Ken Alger
Treehouse Teacher

Heidi;

I've been working on and thinking about your issue, have you been able to come up with a solution? My other question is regarding how you have designed your T_Product_Codes table and why it is necessary to have multiple entries for the same productid? It doesn't seem to conform to most normalization rules I have seen and am just curious if there is a specific need for your particular table design.

Thanks,

Ken

Hello Ken,

Thanks for still thinking about it!

I first tried a PHP alternative, like this:

//PHP code
//get all different code combinations (code1 code2 code3)
$alternativeproducts = array();
$codecombinations = get_codes_for_id($productid);
if (!empty($codecombinations)) {
    //go through every one of the code combinations and see if there is a product that matches it, 
    //  it also has to be a product that was found in all previous code combination matches.
    foreach ($codecombinations as $codecombination) {
        $alternativeproducts = get_productids_for_codes(trim($codecombination["code1"]), trim($codecombination["code2"]), trim($codecombination["code3"]), $alternativeproducts);
    }
}

//PDO query like this
SELECT DISTINCT zi_id 
FROM T_Producteigenschappen
WHERE code1 = ?
AND code2 = ?
AND code3 = ?
AND productid IN //all of the previously found productids

But, as you can see, I need to query the database multiple times like this and I don't like that. It's not only extra database load, it's also that PHP will be slower at finding the alternative products than the database would be if I could query it with one query.

But this solutions inspired me today to find this next one. I do still need to query the database twice. Once for the code combinations of the current product and once for the alternative products. But, it feels better already ...

//PHP code:
$codecombinations = get_codes_for_id($productid);
$alternativeproducts = get_comparableproducts_for_codecombinations($codecombinations);

//PDO code
function get_codes_for_id($productid) {
    require("_inc/database.inc.php");
    $resultarray = array();
    try {
        $query = "SELECT DISTINCT code1, code2, code3 FROM T_Product_Codes WHERE productid = :productid";

        $results = $db_mnet->prepare($query);
        $results->bindParam(': productid',$productid,PDO::PARAM_STR);
        $results->execute();
    } catch (Exception $e) {
        //echo "Data could not be retrieved from the database.";
        //exit;
    }
    $resultarray = $results->fetchAll(PDO::FETCH_ASSOC);
    return $resultarray;
}

function get_comparableproducts_for_codecombinations ($codecombinations) {
    require("_inc/database.inc.php");
    $resultarray = array();
    try {
        if (!empty($codecombinations)) {
                        $unionallquery = "";
            foreach ($codecombinations as $codecombination) {
                if ($unionallquery != "") { $unionallquery .= " UNION ALL "; }
                $unionallquery .= "SELECT DISTINCT a.productid
                            FROM T_Product_Codes a
                                    INNER JOIN T_Product_Codes b
                                    USING (code1, code2, code3)
                                    WHERE a.code1 = ? and a.code2 = ? and a.code3 = ?";
            }
            $query = "SELECT t1.productid
                    FROM ($unionallquery) t1
                        GROUP BY productid
                    HAVING COUNT(t1.productid) = ?";

            $results = $db_mnet->prepare($query);
            $paramid = 1;
            foreach ($codecombinations as $codecombination) {
                $results->bindValue($paramid,$codecombination["code1"],PDO::PARAM_STR);
                $paramid++;
                $results->bindValue($paramid,$codecombination["code2"],PDO::PARAM_STR);
                $paramid++;
                $results->bindValue($paramid,$codecombination["code3"],PDO::PARAM_STR);
                $paramid++;
            }
            $results->bindParam($paramid,count($codecombinations),PDO::PARAM_INT);
            $results->execute();
        }
    } catch (Exception $e) {
        //echo "Data could not be retrieved from the database.";
        //exit;
    }
    $resultarray = $results->fetchAll(PDO::FETCH_ASSOC);
    return $resultarray;
}

With UNION ALL, I get all of the products that have one of these code combinations and then in the end, I only want to keep the ones that appear exactly the number of code combinations that my original product had.

What do you think about this solution?

About the design of the table itself. I designed the entire database myself, except for 2 tables. T_Product and T_Product_Codes. T_Product contains all the unique products that are available on the market and T_Product_Codes contains all of their characteristics. We get the contents of these tables every month from a third party. The table looks like this, because that is how we get the content delivered.

In what other way would you design this table to make this query easier? See, I understand that, in an ideal world, all the unique characteristics would be in a separate table. But you would still need that one table that links the unique products with the unique characteristics. And that would be an N to N relationship. So that table with multiple entries of the same productid would still exist ... and my question would still be the same ... Or am I missing something?

Thanks for brainstorming with me!

Regards Heidi

1 Answer

Ken Alger
STAFF
Ken Alger
Treehouse Teacher

Heidi;

Is this essentially what you are looking for?

SELECT productId, code1, code2, code3
FROM T_Product_Codes
GROUP BY productId
HAVING code1 = 'a' AND code2 = 'b' AND code3 = 'c';

Where 'a', 'b', and 'c' are the values for which you are looking?

Ken

Hello Ken,

Essentially, yes ... only there are more than one code1, code2, code3 combinations that it should have. And I only need the productId's, but that's a minor thing.

For example, if this is data in the T_Product_Codes:

productid     code1            code2                       code3
123456        FIXATION       PRODUCTTYPE       BANDAID       
123456        FIXATION       LENGTH                   33CM
123456        FIXATION       WIDTH                      5CM
654321        FIXATION       PRODUCTTYPE       BANDAID       
654321        FIXATION       LENGTH                   33CM
654321        FIXATION       WIDTH                      5CM
654321        FIXATION       FIBERS                     COTTON
777777        FIXATION       PRODUCTTYPE       BANDAID       
777777        FIXATION       LENGTH                   33CM

And the product 123456 is chosen. Then I would like to see all the products that have the same characteristics as this productid.

Since product 123456 has:

code1            code2                       code3
FIXATION       PRODUCTTYPE       BANDAID       
FIXATION       LENGTH                   33CM
FIXATION       WIDTH                      5CM

that would mean that the comparable products for this product would be 654321. Because it has those same 3 code combinations as the given product (123456). It has one more, but that's ok.

Product 777777 does not have all 3 code combinations, so I don't want that productid in this case.

In another example, when product 777777 is chosen, then the comparable products, the ones that I want to get back, will be both 123456 and 654321.

When product 654321 is chosen, there will be no comparable products, because none of the other 2 have the 4 code combinations (code1, code2, code3) that this one has.