Codeigniter 3 query builder auto quote wrongly - php

I'm am trying to get the sql format below
SELECT * FROM `ci_nest` WHERE `lft` > 9 AND `rgt` < 28 AND `rgt` = `lft` + 1 ORDER BY `lft`
However Codeigniter 3 is inserting the quotes at the wrong place.
My Code as follows
$this->db->where($leftcol . ' > ' . $leftval . ' AND ' . $rightcol . ' < ' . $rightval);
$this->db->where($rightcol . " = " . $leftcol . " +1");
$this->db->order_by($leftcol);
$query = $this->db->get($this->table_name);
What codeigniter query output is
SELECT *
FROM `ci_nest`
WHERE `lft` > 9 AND `rgt` < 28
AND `rgt` = `lft` `+1`
ORDER BY `lft`
As you can see at the line and rgt = lft + 1 is being formatted wrongly by codeigniter 3 query builder.
Any workaround for this issue would be appreciated.

Disable the backticks by the optional 3rd parameter and create them by your own.
$this->db->where($rightcol, '`'.$leftcol.'`+1', FALSE);
Or with double quotes, seems better.
$this->db->where($rightcol, "`$leftcol`+1", FALSE);

For now a quick fix I found is to use Codeigniter 3 query method instead of the query builder.
$query = $this->db->query("SELECT * FROM `{$this->table_name}` WHERE
`{$leftcol}` > {$leftval} AND `{$rightcol}` < {$rightval} AND
`{$rightcol}` = `{$leftcol}` + 1 ORDER BY `{$leftcol}`");

Try this :
$this->db->where($leftcol . ' > ' . $leftval . ' AND ' . $rightcol . ' < ' . $rightval);
$this->db->where($rightcol . " = " . $leftcol + 1);
$this->db->order_by($leftcol);
$query = $this->db->get($this->table_name);

Related

Merge returns empty

There was a problem with the request. Any ideas?
The situation is as follows, there is a request
MERGE ore as T_Base USING ( SELECT
date
,sec
,shift
,id_ore
FROM ore
WHERE date = '2022-9-20'
AND sec = '2'
AND shift = '1') AS T_Source
ON T_Base.date = T_Source.date
AND T_Base.sec = T_Source.sec
AND T_Base.shift = T_Source.shift
AND T_Base.id_ore = T_Source.id_ore
WHEN MATCHED
THEN UPDATE
SET date = T_Source.date
,sec = T_Source.sec
,shift = T_Source.shift
,id_ore = '1'
WHEN NOT MATCHED
THEN INSERT (date, sec, shift, id_ore)
VALUES (T_Source.date, T_Source.sec, T_Source.shift, '1');
But for some reason it returns "0 rows affected".
Table structure:
[id] [int] IDENTITY(1,1) NOT NULL,
[date] [datetime] NULL,
[sec] [int] NULL,
[shift] [int] NULL,
[id_ore] [int] NULL
Values in the table:
id date sec shift id_ore
11637 2022-09-10 00:00:00.000 1 1 13
11636 2022-09-09 00:00:00.000 1 2 13
etc
Expected Result
When updated, no change
id date sec shift id_ore
11637 2022-09-10 00:00:00.000 1 1 13
1.1) When update, with changes (shift and id_ore updated )
id date sec shift id_ore
11637 2022-09-10 00:00:00.000 1 2(change) 27(change)
When new values are inserted:
id date sec shift id_ore
11638 2022-09-20 00:00:00.000 1 1 1
Sorry for this post. I misunderstood the MERGE construction. If there is no data in any of the tables, the operation will not be performed, since there will be nothing to match
If suddenly, someone encountered a similar, came to the following solution:
IF EXISTS (SELECT
date
,sec
,shift
FROM ore
WHERE date = '" . $y . "-" . $m . "-" . $d . "'
AND sec = '" . $sec . "'
AND shift = '" . $shift. "')
UPDATE ore
SET id_ore = '" . $nam_ryd . "'
WHERE date = '" . $y . "-" . $m . "-" . $d . "'
AND sec = '" . $sec . "'
AND shift = '" . $shift. "'
ELSE
INSERT ore (date, sec, shift, id_ore)
VALUES ('" . $y . "-" . $m . "-" . $d . "', '" . $sec . "', '" . $shift. "', '" . $nam_ryd . "')

Subquery calculation error?

Why is this query not working?
$query = ("SELECT * FROM
(SELECT *, (
(((endingLatitude - " . $h . ")(endingLatitude - " . $h . "))
/" . pow($r1, 2) . ")
+
((endingLongitude - " . $k . ")(endingLongitude - " . $k . "))
/" . pow($r2, 2) . "
) AS point2
FROM (SELECT *, ((
(
((startingLatitude - " . $h . ")(startingLatitude - " . $h . "))
/" . pow($r1, 2) . ")
+
((startingLongitude - " . $k . ")(startingLongitude - " . $k . "))
/" . pow($r2, 2) . "))
AS point1
FROM (SELECT * FROM trips WHERE distance >='" . ($distance * .25) . "') as query1)
as query2) as query3 WHERE point1 <= 1 AND point2 <= 1 LIMIT 0 , 10;");
$result = mysqli_query($con, $query);
$h and $k is the ellipses x and y coordinates respectively. I am using a formula found here to calculate whether or not the two points, (startingLat,startingLong) and (endingLat,endingLong) are within an ellipse with vertical height $r1 and horizontal height $r2. I am also limiting the rows that I search to rows that have a distance cell value of greater than $distance * .25.
I think it might have something to do with a parenthesis error or something to do with the way I am sub querying/performing my calculations.
Using
die(mysqli_error($con));
returns an error of You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(endingLatitude - 36.9564753)) /796.842964388) + ((endingLongitud' at line 3
I believe you have to use Mysql multiplication arithmetic operator, *.
https://dev.mysql.com/doc/refman/5.0/en/arithmetic-functions.html#operator_times
Instead of:
(endingLatitude - " . $h . ")(endingLatitude - " . $h . ")
Do this...
(endingLatitude - " . $h . ") * (endingLatitude - " . $h . ")

PHP/Mysql: optimize query

I have the following script that retrieve numbers from 2 tables, make a sum, and the value is updated into a 3th table.
$query = "SELECT (SELECT SUM(net_amount) FROM fin_costos WHERE month='1' AND group_of_costos='general' AND year_analysis='2014' ) +
(SELECT SUM(net_amount) FROM em2_fin_costs WHERE month='1' AND group_of_costos='general' AND year_analysis='2014') AS total";
$result = mysqli_query($mysqli,$query);
while($row = mysqli_fetch_array($result)){$valor_final = $row['total']; }
$query_update="UPDATE fusion_analysis SET jan='$valor_final' WHERE year_for_analysis='2014' AND item_for_analysis='general' AND category='general'";
$result = mysqli_query($mysqli,$query_update);
I need to run the same script for each month of the year. Everything is exaclty the same except the variable 'month' that changes from 1 to 12 and the SET in UPDATE where the value is uploaded for each month ('jan','feb', 'mar'...etc)
I'm currently just copying and pasting the same script changing this few parameters but I believe there is a smarter way to do this in less lines of code I have
See date function of PHP:
$query = "SELECT (SELECT SUM(net_amount)"
. " FROM fin_costos"
. " WHERE month='".date('n')."'"
." AND group_of_costos='general' AND year_analysis='".date("Y")."' ) +"
."(SELECT SUM(net_amount) FROM em2_fin_costs WHERE month='".date('n')."'"
. " AND group_of_costos='general' AND year_analysis='".date("Y")."') AS total";
$query_update="UPDATE fusion_analysis"
. " SET `". strtolower(date('M'))."`='$valor_final'"
. " WHERE year_for_analysis='".date("Y")."'"
. " AND item_for_analysis='general'"
. " AND category='general'";
NOTE:
Y - A full numeric representation of a year, 4 digits like 2014
n - Numeric representation of a month, without leading zeros 1 - 12
M - A short textual representation of a month, three letters Jan through Dec
For month as short textual I've used the strtolower function to make it lowercase.
UPDATE
Based on OP comment:
for ($i = 1; $i <= 12; $i++) {
$query = "SELECT (SELECT SUM(net_amount)"
. " FROM fin_costos"
. " WHERE month='" . $i . "'"
. " AND group_of_costos='general' AND year_analysis='" . date("Y") . "' ) +"
. "(SELECT SUM(net_amount) FROM em2_fin_costs WHERE month='" . $i . "'"
. " AND group_of_costos='general' AND year_analysis='" . date("Y") . "') AS total";
$result = mysqli_query($mysqli, $query);
$row = mysqli_fetch_assoc($result);
$valor_final = $row['total'];
$monthName = strtolower(date('M', strtotime(date("Y") . "-" . str_pad($month,2, "0", STR_PAD_LEFT) . "-" . date("01") )));
$query_update = "UPDATE fusion_analysis"
. " SET `" . $monthName . "`=' " . $valor_final . "'"
. " WHERE year_for_analysis='" . date("Y") . "'"
. " AND item_for_analysis='general'"
. " AND category='general'";
mysqli_query($mysqli, $query_update);
}

Update field Error in MySQL statement

I am trying to update a MySQL database field (decrease the value by 1) in a specific row (ID) of the "places" column, as long as the number in the field is greater than 0.
(see the example statement below)
UPDATE table SET places = places - 1 WHERE id = $id AND places > 0
The statement below fails apart from changing the value of the field to zero.
I would be grateful if anyone can help with the syntax error.
if($id){
global $modx;
$table = "`database_name`.`table_name`";
$update_seats = "`places` - 1";
$result = $modx->db->update( '`places` = "' . $update_seats . '"', $table, '`id` = "' . $id . '" AND `places` > 0' );
return $result; // Returns 'true' on success, 'false' on failure.
}
You have enclosed new value of field in double quotes
$result = $modx->db->update( '`places` = "' . $update_seats . '"', $table, '`id` = "' . $id . '" AND `places` > 0' );
what is evaluated as string in MySQL query. Remove double quotes here
'`places` = "' . $update_seats . '"'
so that it looks like this
$result = $modx->db->update( '`places` = ' . $update_seats, $table, '`id` = "' . $id . '" AND `places` > 0' );
The query looks ok, if you need to set minimum value of 1 to places you should simply change the query accordingly:
UPDATE table SET places = places - 1 WHERE id = $id AND places > 1

Moving the mysql query out of the loop

i have the following code
function cron_day_counts()
{
$subids = get_subids();
array_push($subids, '');
$from = '2011-10-19';
$to = '2011-10-20';
$days = days_interval($from, $to);
$result_array = array();
foreach ($subids as $subid)
{
for ($i = 0; $i < $days; $i++)
{
$date = date('Y-m-d', strtotime($from . '+ ' . $i . ' day'));
$date_prev = date('Y-m-d', strtotime($date . '- 1 day'));
$unique_id_query = mysql_query('SELECT (SELECT COUNT(DISTINCT `id`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . $date . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') - (SELECT COUNT(DISTINCT `id`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . mysql_real_escape_string($date_prev) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') AS `unique_ids`');
$unique_id_result = mysql_fetch_assoc($unique_id_query);
$total_id_query = mysql_query('SELECT COUNT(DISTINCT `id`,`subid`) AS `total_ids` FROM `tb_stats` WHERE `date` = \'' . mysql_real_escape_string($date) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : ''));
$total_id_result = mysql_fetch_assoc($total_id_query);
$unique_ip_query = mysql_query('SELECT (SELECT COUNT(DISTINCT `ip`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . $date . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') - (SELECT COUNT(DISTINCT `ip`,`subid`) FROM `tb_stats` WHERE `date` <= \'' . mysql_real_escape_string($date_prev) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : '') . ') AS `unique_ips`');
$unique_ip_result = mysql_fetch_assoc($unique_ip_query);
$total_ip_query = mysql_query('SELECT COUNT(DISTINCT `ip`,`subid`) AS `total_ips` FROM `tb_stats` WHERE `date` = \'' . mysql_real_escape_string($date) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : ''));
$total_ip_result = mysql_fetch_assoc($total_ip_query);
$global_query = mysql_query('SELECT COUNT(`id`) AS `global` FROM `tb_stats` WHERE `date` = \'' . mysql_real_escape_string($date) . '\'' . (!empty($subid) && is_numeric($subid) ? ' AND `subid` = \'' . mysql_real_escape_string($subid) . '\'' : ''));
$global_result = mysql_fetch_assoc($global_query);
$result = array();
$result['subid'] = $subid;
$result['date'] = $date;
$result['unique_ids'] = $unique_id_result['unique_ids'];
$result['total_ids'] = $total_id_result['total_ids'];
$result['unique_ips'] = $unique_ip_result['unique_ips'];
$result['total_ips'] = $total_ip_result['total_ips'];
$result['global'] = $global_result['global'];
$result_array[] = $result;
}
}
//db insert
return $result_array;
}
I want to move all the query out of the foreach and for loops, I believe it would work faster. I'm stuck o this, having no idea how to do this. Any help would be appreciated.
I would say at the very least you should combine the queries in the loop to just one for each day. So for a 5 day range you would have 5 queries.
Or you could have a single query for the whole date range and move it outside the loop (as described by ajreal). Then use PHP to sort it all out.
For large databases I would rather split up queries a little to balance out the load and risk of timeouts. Also helps keep the code maintainable.
You should also look at how your database is structured and indexed.
Is it noticeably slow?
and is the array_push function necessary? (not that it would save much, just wondered cause it looks redundant)
If its really slow then maybe think about restructuring the process completely depending on how you use it.
You could, for example, at 00:01 each day do something like this:
query the days log and count the unique/total IP/ID amounts
insert just the count numbers and date in to a separate table
archive the days log in to a separate archive table or even a separate db like mongoDB
This way you can perform simple querys to view the data and manipulate the numbers to your hearts content with good performance. And by archiving you're keeping the query table small by removing unecessary rows but maintaining a log if needed later.
Of course, this may not fit in with how your db is setup.
get all the subid
for each table,
build a single query to filter between the smallest date, and largest date,
and group by the date
select subid, `date`, count(*) ...
where subid IN($subids) and `date` between $smallest and $largest
group by subid, `date`
iterate the result, and stored the result into array, with subid, date as key
$mysql_results = array[$subid][$date] ...
lastly, iterate the $subids and date, like
foreach ($subids as $subid)
{
for ($i = 0; $i < $days; $i++)
{
// set $date
// check $mysql_results[$subid][$date] exists
}
}
with something like above, you only required 5 queries instead of
5 x total days x size of the subids
Take all of your subids, and do a fetch with an IN predicate to get all of the values at once. Stuff that in to an array, then loop the array.
Use the PDO::MySQL extension instead of the MySQL or MySQLi extensions. This way, you can prepare the queries which will speed up considerably the execution time of the mysql calls.

Categories