Function inside a mysql query - php

I need to execute my function inside a query like this
$re = $bddp->prepare("SELECT * FROM `shop`, `hours` WHERE isOpen('`hours`.`day1`') = true";
$re->execute();
hours.day1 is a varchar with opening hours of monday like this "10:00-14:00"
Function isOpen test if its open or not and return true or false
The question is who i can send hours.day1 like a variable into isOpen function in WHERE isOpen('hours.day1') ?
Its not possible to use PDO prepare or execute for this ?

In the SQL query you can use only MySQL native functions, stored functions/procedures and User-Defined Functions (UDF).
I think that you would not have a problem if the table structure was right (start-end times were in the separate columns). Then you would able to achieve your goal only with a few conditions in the WHERE part.
If the data amount (rows count) is not big, then you can just select all rows and done the validation in the PHP side.

Related

Trying to understand php mysqli multi_query

I have a function that is designed to copy a product with all attributes with help of sql querys. My problem is to return new_product_id to php after completion.
If i run sql script in phpmyadmin all is working.
If i run sql script with php function all is working.
What i need help with is how to assign mysql-set-variable: #new_product_id from last query to php variable that I want to return.
----- sql query ------
CREATE TEMPORARY TABLE tmptable SELECT * FROM product WHERE id='19' AND site_id='1';
UPDATE tmptable SET id = 0,parent_id='19',status_id='1',name_internal=concat('NEW ',name_internal);
INSERT INTO product SELECT * FROM tmptable;
SET #new_product_id = LAST_INSERT_ID();
DROP TABLE tmptable;
CREATE TEMPORARY TABLE tmptable SELECT * FROM product_abcd WHERE product_id='19' AND site_id='1';
UPDATE tmptable SET product_id = #new_product_id,id=0;
INSERT INTO product_abcd SELECT * FROM tmptable;
DROP TABLE tmptable;
CREATE TEMPORARY TABLE tmptable SELECT * FROM product_efgh WHERE product_id='19' AND site_id='1';
UPDATE tmptable SET product_id = #new_product_id,id=0;
INSERT INTO product_efgh SELECT * FROM tmptable;
DROP TABLE tmptable;
(Here is more correct SQL insert statements)
SELECT #new_product_id AS new_product_id;
----- sql query ------
----- php function (not complete)------
This function is working making a new copy of product, code below is not complete but works so please only focus on multiquery part.
//return 0 for fail or new product_id (!=0) for success
public function copyProduct($data){
$res=0;
//if something, build sql-query as
$sql="sql from above";
//if we have a query to run
if(!empty($sql)){
//this is multi query, use correct function
if ($this->connect()->multi_query($sql) === TRUE) {
//loop it
while ($this->connect()->more_results()){
$result=$this->connect()->next_result();
}//while more results
}//if multiquery ok
return $res;
}//end function copy
----- php function (not complete)------
above code works, i get a nice copy of product with
result =0 for fail and
result 1 for success, (this works)
How i would like it to work is
result= 0 for fail and
result= new_product_id for success
so i can redirect user to the newly created product and therefore save user one click.
Results from query, same from phpmyadmin as from php (all good so far, no incorrect querys at this time)
Mysql returned empty results (no rows) (create temporary table)
1 row affected (update tmpt table)
1 row insert (insert into product)
mysql returned emtpy result (set $new_product_id)
mysql returened empty results (drop tmp table)
mysql returned empty result (create temporary table)
mysql x row affected (update tmp table)
mysql x row affected (insert into table)
mysql returned empty results (drop table tmptable)
mysql returned empty results (create temporary table)
.... N.....
last query "showing rows 0-0 ( 1 total) (select #new_product_id)
new_product_id=25
What have I tried?
I placed the select variable as my final query, i thought it was smart only check last query and assign variable there, but i failed due to php mysqli fetch_assoc is not possible on non object.
so next up was not so bright, i know i have 16 results from mysql and i only need the result from one of them, but anyway i places this inside multiquery
----- php function (not complete)------
This function is working making a new copy of product, NOT WORKING assigning new_product_id
//return 0 for fail or new product_id (!=0) for success
public function copyProduct($data){
$res=0;
//if something, build sql-query as
$sql="sql from above";
//if we have a query to run
if(!empty($sql)){
//this is multi query, use correct function
if ($this->connect()->multi_query($sql) === TRUE) {
//loop it
while ($this->connect()->more_results()){
//insert,update,drop will return false even if sql is ok, this would be sufficient for us now
if ($result = $this->connect()->store_result()) {
$row = $result->fetch_assoc();
if(isset($row["new_product_id"])){
//new return value of newly copied product
$res=$row["new_product_id"];
$result->free();
}
}
$result=$this->connect()->next_result();
}//while more results
}//if multiquery ok
return $res;
}//end function copy
----- php function (not complete)------
Checking other questions on stackoverflow recommended sending multiple normal querys, this seems like a bad solution when multi_query exists.
checking php library for multiquery did me no good, i cant understand how it works, as many others pointed out the documentation seems like a copy from another function.
Remember that multi_query() sends a clump of SQL queries to MySQL server but waits for the execution of only the first one. If you want to execute SQL using multi_query() and get only the result of the last query ignoring the previous ones then you need to perform a blocking loop and buffer the results into PHP array. Iterate over all results waiting for MySQL to process each query and once MySQL responds there are no more results you can keep the last fetched result.
For example, consider this function. It sends a bunch of concatenated SQL queries to the MySQL server and then waits for MySQL to process each query one by one. Every result is fetched into PHP array and the last available array is returned from the function.
function executeMultiQueryAndGetOnlyLastResult(mysqli $mysqli):array {
$mysqli->multi_query('
SELECT "a";
SELECT 2;
SELECT "val";
');
$values = [];
do {
$result = $mysqli->use_result();
if ($result) {
// process the results here
$values = $result->fetch_all();
$result->free();
}
} while ($mysqli->next_result()); // next_result will block and wait for next query to finish on MySQL server
$mysqli->store_result(); // Needed to fetch the error as exception
return $values;
}
Obviously it would be much easier to send each query separately to MySQL instead. multi_query() is very complicated and has very limited use. It can be useful if you have a number of SQL queries which you cannot execute separately via PHP, but most of the time you should be using prepared statements and send each query separately.
Another one bites the dust, I gave up and defined an array of sql querys from 0 to 14 and run it as mysqli->query() instead. Thank you all for comments and your time.
You could try using .multi_query() for all the queries in your operation except the last one, the SELECT that returns the id you want. Then run that SELECT as a single query.
This is a robust solution to your problem: #-variables belong to MySql connections and persist for the lifetimes of those connections.
And, it makes for clean and predictable operation of your software. When you need a result set returned to your program, use a single query.

MySqli multiple queries how to handle result faster way

I have to INSERT thousand of records.
I use msqli::multi_query() in a loop and want to 'multi_query' block of n query (where 'n' is a parameter).
first INSERT goes ok, the second goes wrong because I have to manage result like this :
while($mysqli->more_results())
{
$mysqli->next_result();
if($res = $mysqli->store_result()) // added closing bracket
{
$res->free();
}
}
The problem is that this chek is slow.
Question is : how can I optimize this bulk INSERT makeing faster the manage of result ?
If you are inserting in a one table just use batch mod in INSERT.
Example:
INSERT INTO TABLE (field1,field2,field3) VALUES (value1,value2,value3),(value4,value5,value6)
Use for or foreach in php to make query and then simply use mysqli_query. Judging by errors you mentioned in comment section, you violating ket restrictions meaning you are trying to insert the same value twice.
If you are inserting in a different tables, you can use multi_query interface.
Prepare one query Insert1;Insert2;
And use multi_query like this
$con->multi_query($query);
while (mysqli_more_results($con)) {
mysqli_use_result($con);
mysqli_next_result($con);
}

ZF2 where expression

In mu ZF2 project I have Model using TableGateway.
Inside function responsible for fetching objects based on search criteria (city, postal_code, range, type).
Generally I fetch rows of data by simple
$rowset = $this->tableGateway->select($where);
In my MySQL database I have procedure GetObjectsInCityRange(city, range) which returns all object_id in range of geocoded city coordinates
I intend to add in the where clause condition:
WHERE object_id IN (call GetObjectsInCityRange(city, range))
Is it possible with MySQL? How write correctly $where array element to make it work?
You can call a where() method in your select object and call in() on the return value or create a where statement.
E.g.
$select = new Select();
$select->from($this->tableName)->columns(array($expression));
$where = new Where();
$where->in($identifier, $valueSet);
// or
$where->addPredicate(
new Predicate\In($identifier, $valueSet)
);
// and then
$select->where($where);
and append it to the select object.
The link below is exactly what you need I believe :)
http://framework.zend.com/manual/2.1/en/modules/zend.db.sql.html#in-identifier-array-valueset-array
Hope this helps :)
For MySQL it is suggested that you should use function instead of procedure as function can be used in any sql query while procedure is itself a query like statement. Ex.
call MyPrcedure();
SET var = MyFunction();
So you can call function in your query most of the time. However as per my knowledge function will return valid mysql data-type like varchar, int float etc. So query rows may not be available in your In query. Then only way to execute your query to convert your procedure logic to a subquery and pass inside IN statement.
WHERE object_id IN (SUB_QUERY)

MySQL: Get only count of result set

I am using MVC with PHP/MySQL.
Suppose I am using 10 functions with different queries for fetching details from the database.
But at other times I may want to get only the count of the result that will be returned by the query.
What is the standard way to handle such situation.
Should I write 10 more functions which duplicate almost whole query and return only the count.
Or
Should I always return the count also with the result set
Or
I can pass a flag to indicate that the function should return count only, and then based on the flag I will dynamically generate the (select part of) query.
Or
Is there a better way?
Now that mysql supports sub-queries, you can get counts for any query using:
$count_query="SELECT COUNT(*) FROM ($query)";
How hard was that?
However this approach always means that you are running two queries instead of just the one (I'm not sure if MySQL would necessarily be able to use a cached result set for the count - try it out and see).
If you've already fetched the entire result set it'll probably be faster counting the rows in PHP than issuing another query.
There are 2 functions in MySQL which would return the number of matched rows prior to application of a limit statement:
SQL_CALC_FOUND_ROWS and FOUND_ROWS()
see
http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_found-rows
C.
If you want only number of rows matched certain criteria, you shouldn't use a count of the result, but another query that select only count(*) instead.
If you need both data and it's count, why don't you just use count() on the resulting array?
another way is to use some class that can return both data and it;s count, but not different classes for the each 10 queries but one single database access class.
I'd go with the flag idea.
Writing 10 more functions and copy/pasting code does not help readability at all. If you always also return the count, that means that whenever you're only interested in the count, the database still has to generate and transmit the full result set which might be grossly inefficient.
With the flag, you'd have something like
function getData($countOnly=false) {
// ...generate FROM and WHERE clause
if ($countOnly) {
$query = 'SELECT COUNT(*) '.$query;
} else {
$query = 'SELECT field1, field2, ...'.$query.' ORDER BY ...';
}
...
}
I would generally try to have as much code as possible shared between methods. A possibility would be to :
have one select() and one count() functions
each one building the specific part of the query
and one buildFromAndWhere() function to build the parts of the query that are common.
and have select() and count() use that one
Written in pseudo-code, it could look a bit like this :
function select($params) {
return "select * "
. from()
. where($params)
. "limit 0, 10";
}
function count() {
return "count(*) as nbr "
. from()
. where();
}
function from() {
return "from table1 inner join table1 on ... ";
}
function where($params) {
// Use $params to build the where clause
return "where X=Y and Z=blah";
}
This way, you have as much common code as possible in the from() and where() functions -- considering the hard part of the queries is often there, it's for the best.
I prefer having two separate functions to select and count ; I think it make code easier to read and understand.
I don't like the ideas of one method returning two distinct data (list of results and the total count) ; and i don't really like the idea of passing a flag either : looking at the function's call, you'll never know what that parameter means.

searching between dates in MYSQL in this format 03/17/10.11:22:45

I have a script that automatically populates a mysql database with data every hour. It populates the date field like 03/17/10.12:34:11 and so on.
I'm working on pulling data based on 1 day at a time from a search script.
If i use
SELECT *
FROM call_logs
WHERE call_initiated between '03/17/10.12:00:00' and '03/17/10.13:00:00'
it works, but when I try to add the rest of the search params, it ignores the call_initiated field.
SELECT *
FROM call_logs
WHERE caller_dn = '2x9xxx0000' OR called_dn = '2x9xxx0000'
AND call_initiated between '03/17/10.12:00:00' and '03/17/10.13:00:00'
^-- I x'd out a couple of the numbers. I've also tried without the between function, and used >= <= to pull the records, but have the same results. Im sure its an oversight, thanks in advance.
try using parentheses around your OR statement
... where (caller_dn='2x9xxx0000' OR called_dn='2x9xxx0000') AND call_initiated between '03/17/10.12:00:00' and '03/17/10.13:00:00'
use the IN operator instead of OR
... where caller_dn IN('2x9xxx0000','2y9yyyy000') AND call_initiated between '03/17/10.12:00:00' and '03/17/10.13:00:00'
The OR statement is more than likely the issue, since OR evaluates the left side, sees that its true, it doesn't care what is on the right site, because as long as one of the statements is true, it considiers the entire statement to be true.
Read up on the OR operator at the MYSQL page
Your Statement should look like
SELECT * FROM `call_logs` WHERE (caller_dn='2x9xxx0000' OR called_dn='2x9xxx0000') AND call_initiated BETWEEN '03/17/10.12:00:00' and '03/17/10.13:00:00';

Categories