aphextwix
aphextwix

Reputation: 1858

MYSQL Conditional Insert with Multiple Conditions

I'm trying to create an INSERT statement with multiple conditions as part of a PHP function - here's my code so far :

public function insertData($data)
    {
        try
        {
            $stmt = $this->con->prepare('
            INSERT IGNORE INTO tblProductData(
            strProductCode, 
            strProductName, 
            strProductDesc,  
            smintStockLevel, 
            dblPrice, 
            dtmDiscontinued, 
            dtmAdded)
           SELECT :strProductCode, 
                  :strProductName, 
                  :strProductDesc, 
                  :smintStockLevel, 
                  :dblPrice,
           (CASE WHEN :dtmDiscontinued  = "yes" then NOW();
           ELSE SET dtmlDiscontinued = "NULL";
           END CASE),
            NOW()
            FROM dual
            WHERE not (:dblPrice < 5.0 and :smintStockLevel < 10) 
            and not (:dblPrice > 1000.0) ');

            $length = count($data);
            for ($x=0; $x < $length; $x++) {
            $params = array(':strProductCode' => $data[$x][0], 
                            ':strProductName' => $data[$x][1], 
                            ':strProductDesc' => $data[$x][2],
                            ':smintStockLevel' => $data[$x][3], 
                            ':dblPrice' => $data[$x][4] );

            $stmt->execute($params);
            }

            return $stmt;
            } catch(PDOException $e) {
                echo 'ERROR: ' . $e->getMessage();
            }
        }
    }

The conditions are as follows

This query is being executed as part of a PHP prepared statement, iterating over a multi-dimensional array which contains all of the values.

Will I need to create multiple CASE(s) ? Can somebody please provide advice on the best way to approach this problem.

Any further info required, let me know.

UPDATE

The code above has been entered to show the full context and included Gordon's suggestion. However, I'm currently receiving the error ERROR: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens on execution.

Can anybody see the cause? Thanks

SOLUTION

:dtmlDiscontinued needed to be added to the $params to solve the error :

Example

 $params = array(':strProductCode' => $data[$x][0], ':strProductName' => $data[$x][1], ':strProductDesc' => $data[$x][2],
                            ':smintStockLevel' => $data[$x][3], ':dblPrice' => $data[$x][4], ':dtmDiscontinued' => $data[$x][5] );  

Upvotes: 0

Views: 175

Answers (2)

Gervs
Gervs

Reputation: 1397

Mysql doesn't have check constraint so you'll have to implement them in a trigger. To give ypu a headstart:

DELIMITER $$
CREATE TRIGGER product_cond BEFORE INSERT ON tblProductData
FOR EACH ROW
BEGIN
    declare message VARCHAR(255);
    declare hasError BIT;
    IF new.dblPrice < 5 AND new.smintStockLevel < 10 THEN
        SET hasError := 1;
        SET message := 'If price is less then 5 stock has to be more then 10';
    END IF;
    IF new.dblPrice > 1000 THEN
        SET hasError := 1;
        SET message := 'Price can not be over 1000';
    END IF;
    /* create the other ckecks in the same way
    If check failed signal an error */
    IF hasError = 1 THEN
        SIGNAL SQLSTATE '45000'
            SET MESSAGE_TEXT = message;
    END IF;
END$$

DELIMITER ;

Note that MYSQL 5.5+ is required to use SIGNAL

Of course you can do these checks also in the application layer

Upvotes: 0

Gordon Linoff
Gordon Linoff

Reputation: 1269803

You cannot use where clause with values. You can implement your logic in SQL, with something like this:

INSERT INTO tblProductData(strProductCode, strProductName, strProductDesc,  smintStockLevel,
                           dblPrice, dtmDiscontinued, dtmAdded
                          )
    SELECT :strProductCode, :strProductName, :strProductDesc, :smintStockLevel, 
           :dblPrice,
           (case when :dtmDiscontinued  = 'Yes' then NOW() end),
           NOW()
    FROM dual
    WHERE not (:dblPrice < 5.0 and :smintStockLevel < 10) and
          not (:dblPrice > 1000.0);

(Note the from dual doesn't actually do anything but some databases require a from clause when using where.)

I don't know what dtmDiscontinued = 'yes' means. But something like the above should work.

That said, you might find it easier to put the logic in the application layer rather than in the database. If you always want to check these conditions, then consider a trigger.

Upvotes: 1

Related Questions