Zend Db Sql Where - mysql

Hi how can I do a query like this in zf2 with zend\db\sql?
Query:
SELECT * FROM table WHERE field = $field AND data > SUBDATE(NOW(), INTERVAL 1 DAY)
In ZF2
$select = $this->sql->select();
$select->from(self::MYTABLE)
->where(array('fiels' => $field))
->where(array('data > ' => 'SUBDATE(NOW(), INTERVAL '.$lifetime.' SECOND'));
$statement = $this->sql->prepareStatementForSqlObject($select);
return $statement->execute()->current();

change the line
->where(array('data > ' => 'SUBDATE(NOW(), INTERVAL '.$lifetime.' SECOND'));
to
->where(array('data > ?' => 'SUBDATE(NOW(), INTERVAL '.$lifetime.' SECOND'));
From the code snippet, it's seen you had missed the place holder for the parameter(?), include a question mark, I had mentioned the existing line of code and the modified code for quick reference

There's no parameter there so it doesn't need to be an array. Assuming you know $lifetime is a safe, integer value, try:
->where('data > SUBDATE(NOW(), INTERVAL '.$lifetime.' SECOND)');

Related

Yii2 DB Expression in ActiveQuery::andFilterWhere()

I have the following code which filters an ActiveQuery
// Start date condition
if ($this->start_date) {
$query->andWhere('event_datetime >= :start_date', [
'start_date' => $this->start_date,
]);
}
// End date condition
if ($this->end_date) {
$query->andWhere('event_datetime < :end_date + INTERVAL 1 DAY', [
'end_date' => $this->end_date,
]);
}
where $this->start_date and $this->end_date are either null, '', or in the form Y-m-d, and event_datetime is an indexed DATETIME column
Provided that both date properties are true, this code produces the following SQL
WHERE event_datetime >= :start_date
AND event_datetime < :end_date + INTERVAL 1 DAY
I can rewrite the start date condition as
$query->andFilterWhere(['>=', 'event_datetime', $this->start_date);
Is it possible to rewrite the end date condition simlarly, perhaps using some kind of DB expression?
I'd rather keep the '+ INTERVAL 1 DAY' in SQL, if possible, and still be able to use an index on event_datetime
Apart from your date is null or empty '', what I am trying to understand is that why are you not using DateTime class along with DateInterval to set the $this->end_date to the final date after adding the interval and compare it with your column event_datetime rather than getting confused about it.
$endDate = $this->end_date;
if ($this->end_date !==null && $this->end_date!=='') {
$endDateObj = new \DateTime($this->end_date);
$endDateObj->add(new \DateInterval('P1D'));
$endDate = $endDateObj->format('Y-m-d');
}
$query->andFilterWhere(['<','event_datetime', $endDate]);
BUT, if you are still feeling sleepy head and dizzy and not feel like doing it in PHP for having personal reasons like increase in Blood Pressure, insomnia or your body start shivering thinking of PHP :P you can do it via \yii\db\Expression() in the following way which will produce the query like WHERE created_at < '2019-10-22' + INTERVAL 1 DAY, i have tested it but not sure how accurate it will be so test it before you go for it.
$query->andFilterWhere(
[
'<',
'event_datetime',
new \yii\db\Expression("'$this->end_date' + INTERVAL 1 DAY")
]
);
EDIT
You have to check manually the value for null and empty before you use any of the methods above and that is the only way you can do that. A little addition is needed to control the blank or null value which wont be controlled in the Expression automatically and will give incorrect results so change to the following
$expression = null;
$isValidDate = null !== $this->end_date && $this->end_date !== '';
//prepare the expression if the date is not null or empty
if ($isValidDate) {
$expression = new Expression(
":my_date + INTERVAL 1 DAY",
[
':my_date' => $this->end_date,
]
);
}
$query->andFilterWhere(
[
'>',
'end_date',
$expression,
]
);
A supplemental answer to #Muhammad's, and supported by #Michal's comment on my original question
The ActiveQuery::andFilterWhere() function ignores empty operands, so we can set up our expression or manipulated value, $endDate, to remain empty when the original value is empty
either using PHP's DateTime
$endDate = $this->end_date ?
(new DateTime($this->end_date . ' + 1 day'))->format('Y-m-d') :
null;
or using Yii's Expression
$endDate = $this->end_date ?
new Expression(':end_date + INTERVAL 1 DAY', ['end_date' => $this->end_date]) :
null;
Then ActiveQuery::andFilterWhere() can be used as follows
$query->andFilterWhere(['<','end_date', $endDate]);

Search data between two dates

I want to select the data between two dates and I wrote the query as follows:
SELECT *
FROM hospital_details
WHERE expirydate BETWEEN '03/13/2015' AND '03/18/2015'
But it also displays the results of 03/17/2016
How can I solve it?
You could write single syntax.
SELECT * FROM hospital_details WHERE ExpiryDate BETWEEN '$Date' AND '$b';
The active record where function will take an associative array;
$array = array('expirydate >= ' => $Date, 'expirydate <= ' => $b);
$this->db->where($array);
or a custome string;
$where = "expirydate > ='$Date' AND expirydate < ='$b'";
$this->db->where($where);
Obviously, make sure your variables are in the right format.
Active record docs here

Illuminate database query with date_sub

I'm struggling with a query using the Illuminate database query builder.
When I use the query the result is not as I expected.
When using the query from the querylog directly with mysql cli, I get the expected result.
With query builder:
->table('CompanyTools')
->select(
'CompanyTools.toolId',
$db->raw('COUNT(CompanyTools.toolId) as count')
)
->whereYear('CompanyTools.date', '>', 'YEAR(DATE_SUB(CURDATE(), INTERVAL 1 YEAR))')
->groupBy('CompanyTools.toolId')
->orderBy('count', 'DESC')
->take(1)
->get();
Result:
Array ( [toolId] => 88 [count] => 55 )
With mysql cli:
select `CompanyTools`.`toolId`, COUNT(CompanyTools.toolId) as count from `CompanyTools`
where year(`CompanyTools`.`date`) > YEAR(DATE_SUB(CURDATE(), INTERVAL 1 YEAR))
group by `CompanyTools`.`toolId`
order by `count` desc
limit 1
Result:
ToolId: 88
count: 17
If I (in the query builder) replace 'YEAR(DATE_SUB(CURDATE(), INTERVAL 1 YEAR))'with 2013 I get:
Array ( [toolId] => 88 [count] => 17 )
Somehow the date_sub get ignored so the result includes all years
I tried with ->whereYear('CompanyTools.date', '>', $db->raw('YEAR(DATE_SUB(CURDATE(), INTERVAL 1 YEAR))')) without any luck.
I guess I could use php to calculate the desired year, but I would rather get the query right.
Thx in advance
/ j
UPDATE
Replacing
->whereYear('CompanyTools.date', '>', 'YEAR(DATE_SUB(CURDATE(), INTERVAL 1 YEAR))')
with
->where($db->raw('YEAR(CompanyTools.date)'), '>', $db->raw('YEAR(DATE_SUB(CURDATE(), INTERVAL 1 YEAR))'))
solves it. Not clever enough to figure out why, but perhaps the whereYear function is supposed to be used diffently
As you already found out using
->where($db->raw('YEAR(CompanyTools.date)'), '>', $db->raw('YEAR(DATE_SUB(CURDATE(), INTERVAL 1 YEAR))'))
Or alternatively
->whereRaw('YEAR(CompanyTools.date) > YEAR(DATE_SUB(CURDATE(), INTERVAL 1 YEAR))')
solves the problem.
But why is that?
For every "normal" query, Laravel uses bindings. Obviously SQL functions like YEAR(DATE_SUB(CURDATE(), INTERVAL 1 YEAR)) don't work with bindings.
Normally, you can use DB::raw('YEAR(DATE_SUB(CURDATE(), INTERVAL 1 YEAR))') and the Laravel won't use bindings. For example in where() (Expression is the class DB::raw() returns)
if ( ! $value instanceof Expression)
{
$this->addBinding($value, 'where');
}
But the whereYear() function doesn't do such a thing. It uses addDateBasedWhere() and just adds a binding without checking if the value is an instance of Expression
protected function addDateBasedWhere($type, $column, $operator, $value, $boolean = 'and')
{
$this->wheres[] = compact('column', 'type', 'boolean', 'operator', 'value');
$this->addBinding($value, 'where');
return $this;
}
This means the query will use bindings and therefore NOT execute the date calculation at all.

How can I update TIMESTAMP with Codeigniter and MySQL?

How can I update TIMESTAMP with Codeigniter and MySQL? I want to update with INTERVAL 1 MINUTE
I've tried the next code:
$data = array('is_active' => $state,
'timestamp_demo' => "DATE_ADD(NOW(), INTERVAL 1 MINUTE)");
$this->db->where('demo_session_id', 'web');
$this->db->update('demo_session', $data);
But not work. How can I do?
Try your query like this
$this->db->query("UPDATE demo_session
SET
is_active = 1,
timestamp_demo = DATE_ADD(NOW(), INTERVAL 1 MINUTE)
WHERE demo_session_id = 'web'");
You can do this with Active Records, which you're using:
$this->db->where('demo_session_id', 'web');
$this->db->set('is_active', $state);
$this->db->set('timestamp_demo', 'DATE_ADD(NOW(), INTERVAL 1 MINUTE)', FALSE);
$this->db->update('demo_session');
The third parameter in $this->db->set() prevents CodeIgniter from escaping the data so it'll use the MySQL function.
It'll end up something like this:
UPDATE 'demo_session' SET 'is_active' = $state, 'timestamp_demo' = DATE_ADD(NOW(), INTERVAL 1 MINUTE) WHERE 'demo_session_id' = 'web'

Convert MySQL fetch array query to redbean PHP

I have 2 buttons which execute a post operations and set a hidden variable which is used to set the MySQL query to filter the database according to date
if result = today
$query = "SELECT id,customer_name,CAST( `register_date` AS DATE ) AS dateonly,status,
DATE_FORMAT(book_date, '%m/%d/%y') FROM table WHERE book_date
BETWEEN (CURDATE() - INTERVAL 1 DAY) AND CURDATE()";
if result = week
$query = "SELECT id,customer_name,CAST( `register_date` AS DATE ) AS dateonly,status,
DATE_FORMAT(book_date, '%m/%d/%y') FROM table
WHERE book_date BETWEEN (CURDATE() - INTERVAL 7 DAY) AND CURDATE()";
I then want to use something like
$result=mysql_query($query);
while ($mytable=mysql_fetch_array($result))
{
loop and display all the information in array in a table
}
But I need the red bean equivalent of this.
The easiest way is to just paste the $query inside the sql function:
$results=R::getAll($query);
foreach($results as $row){
echo $row['id'];
}
The next way is to manually build the query.... which may just make it look sloppier in my opinion:
$results=R::$f->begin()->select('id, customer_name, CAST( register_date AS DATE ) AS dateonly,status, DATE_FORMAT(book_date, '%m/%d/%y')')->from('table')->where('book_date BETWEEN (CURDATE() - INTERVAL 1 DAY) AND CURDATE())->get();
The final way is to grab results via redbean and handle them manually:
$results=R::find('table','book_date BETWEEN (CURDATE() - INTERVAL 7 DAY) AND CURDATE()');
Then loop through the results, configuring data along the way in php.
I always use this when I have to access a lot of data from mysql:
while ($row = mysqli_fetch_array($query)) { #converts query into array
$array[] = $row;
}
$array will be a multidimensional array. $array[x][column_name] will get you your data, x being the row which you want to access it from. Hope this helped.