MySQLi BETWEEN query to get data from text fileds in database - php

I have a query :
$sql = "SELECT * FROM table WHERE CONCAT(Prod, Serial) BETWEEN '$start' AND '$end'";
Where Prod and Serial are stored in MySQLi database as a string. I need to update details of items between say AA1000 and AA1005. When I run this query it updates details of units between AA1000 and AA1005 and, "as a bonus", all between AA10000 and AA10050.
Is there a way to get exact match for the text type fields using BETWEEN query?
Thanks!
P.S. I know that I need update query to update details. I'm using SELECT for testing purposes.

You are abusing the BETWEEN syntax in a very bad way. You're comparing strings, so
'AA1000' <= 'AA10000' <= 'AA1005'
is actually TRUE, because you're not comparing numbers, just strings. String comparisons go on a per-character basis, without consideration for length, so
'A' <= 'AZ' <= 'B'
is also true, even though a human would consider "AZ" to come AFTER 'B'.

This query should do it:
SELECT *
FROM TABLE
WHERE Prod = LEFT('$start', 2)
AND CAST(Serial AS DECIMAL) BETWEEN SUBSTRING('$start', 3) AND SUBSTRING('$end', 3);
You could also split the start and end strings apart in PHP:
$prod = substr($start, 0, 2);
$start_code = substr($start, 2);
$end_code = substr($end, 2);
$sql = "SELECT *
FROM TABLE
WHERE Prod = '$prod'
AND CAST(Serial AS DECIMAL) BETWEEN $start_code AND $end_code";

I have never personally encountered a situation where I have needed this, but I believe you can do this with Regular Expressions. This may help you.

Following worked so far:
CONVERT(SUBSTRING('$startunit', 3),UNSIGNED INTEGER)
Thanks everyone!

Related

How to use "IN" operator in prepared statement in php

i will use "IN" operator with using parameter in prepare statement
but i can't do that
$hotel_list = "SELECT DISTINCT h.hotel_id, h.hotel_name, h.hotel_address, h.hotel_image
FROM type_feture tf
JOIN type t ON t.type_id = tf.type_id
JOIN hotel h ON h.hotel_id=t.hotel_id
WHERE tf.feture_id IN ?
AND h.hotel_city_id=?
GROUP BY tf.type_id, h.hotel_id, h.hotel_name, h.hotel_address HAVING COUNT(tf.type_id)>=?";
$result = $dbca->prepare($hotel_list);
$result->bind_param("sii", $feture,$city_ide,$cnt_type);
$feture=(string)$finish;
$city_ide = (int)$hotel_city_id;
$cnt_type=(int)$cn;
$result->execute();
$res = $result->get_result();
while ($obj = $res->fetch_object()) {
$hotels[] = $obj;
}
Because it is a design requirement that you must use the IN operator and prepared statements, you need a way to convert the PHP array of (value 1, value 2, value 3, ... value n) into an SQL array (value 1, value 2, value 3, ... value n). You'll need an intermediate step, as PHP objects cannot be directly translated into SQL without the aid of functions or loops of some sort.
Your thought process should be: what do the two variables have in common? Answer: they're both lists and they can both be represented by strings. To solve your problem, then, you want to transform the PHP list into a comma-separated string, into an SQL array, and then check in the SQL query if the specified column has a value in that array.
There are only two changes you need to make to your code to accomplish this:
1) Create a variable $feature_ids_str and make it the comma-separated string version of whatever array holds your feature IDs (as per the comments on your question, it really would be helpful if you gave us some more code to explain where some of these variables were coming from). An example of the value of $feature_ids_str would be "1,5,3,7,82,4".
2) Amend your query as follows: ... WHERE tf.feture_id IN STRING_SPLIT(?, ',') ... [feture_id sic] and of course update the $result->bind_param() function accordingly.
Also, I think you're misspelling "feature".

PHP MySQL - Update 6.5m rows performance issues

I am working with a MySQL table and I need to increment a value in one column for each row, of which there are over 6.5m.
The col type is varchar and can contain an integer or a string (i.e. +1). The table type is MyISAM.
I have attempted this with PHP:
$adjust_by = 1;
foreach ($options as $option) {
$original_turnaround = $option['turnaround'];
$adjusted_turnaround = $option['turnaround'];
if (preg_match('/\+/i', $original_turnaround)) {
$tmp = intval($original_turnaround);
$tmp += $adjust_by;
$adjusted_turnaround = '+'.$tmp;
} else {
$adjusted_turnaround += $adjust_by;
}
if (!array_key_exists($option['optionid'], $adjusted)) {
$adjusted[$option['optionid']] = array();
}
$adjusted[$option['optionid']][] = array(
'original_turn' => $original_turnaround,
'adjusted_turn' => $adjusted_turnaround
);
}//end fe options
//update turnarounds:
if (!empty($adjusted)) {
foreach ($adjusted as $opt_id => $turnarounds) {
foreach ($turnarounds as $turn) {
$update = "UPDATE options SET turnaround = '".$turn['adjusted_turn']."' WHERE optionid = '".$opt_id."' and turnaround = '".$turn['original_turn']."'";
run_query($update);
}
}
}
For obvious reasons there are serious performance issues with this approach. Running this in my local dev environment leads to numerous errors and eventually the server crashing.
Another thing I need to consider is when this is run in a production environment. This is for an ecommerce store, and I cannot have a huge update like this lock the database or cause any other issues.
One possible solution I have found is this: Fastest way to update 120 Million records
But creating another table comes with it's own issues. The codebase is not in a good state, similar queries are run on this table in loads of places so I would have to modify a large number of queries and files to make this approach work.
What are my options (if there are any)?
You can do this task with SQL.
With CAST you can convert a string into integer.
With IF and SUBSTR you can check if string contains +.
With CONCAT you will add (merge a two values into one string) + to your calculated result (if it will be necessary).
Just try this SQL:
"UPDATE `options` SET `turnaround` = CONCAT(IF(SUBSTR(`turnaround`, 1, 1) = '+', '+', ''), CAST(`turnaround` AS SIGNED) + " + $adjust_by + ") WHERE 1";
can't you just say
UPDATE whatevertable SET whatever = whatever + 1?
Try it and see, I'm pretty sure it will work!
EDIT: You have strings OR integers? Your DB design is flawed, this probably won't work, but would have been the correct answer had your DB design been more strict.
You probably don't have, but need, this 'composite' index (in either order):
INDEX(optionid, turnaround)
Please provide SHOW CREATE TABLE.
Another, slight, performance boost is to explicitly LOCK TABLE WRITE before that update loop. And UNLOCK afterwards. Caution: This only applies to MyISAM.
You would be much better off with InnoDB.

Sql string query not working

I'm building some Sql queries in Yii framework.
So far all is working fine up until I need to compare a variable to a string.
Here is my function with the query:
public function countCanceled()
{
$week = Person_Event::model()->weekByDate();
$week_id = $week->id;
$datalogin = mysqli_connect( /*connect is working fine*/);
$sql = "SELECT id FROM tbl_event WHERE week_id=$week_id AND status_id='canceled'";
$query = mysqli_query($datalogin, $sql);
$numrows = mysqli_num_rows($query);
return $numrows;
}
Now , I clearly have one event with canceled status, and I ran the same query in MySql server and the result of 1 was given, so why in Yii it doesn't work?
(tried to switch "=" with "like" , made no difference)
p.s Yes , in this particular case I could use the built in Yii's queries , but I have other, much more complicated queries where I need to compare string.
Thanks,
Mark.
What is type of status_id if is char then data is space padded to full length. You can change it to varchar and then compare. And for like you can use LIKE 'canceled%'
ps. sorry I not have enough reputation to comment...:(
Best regards,
Nebojsa

PHP automatically removes the zeros that i need in an identification string

In a table, the primary field is a Char(12) field called ribiid, whose format is RB##########,
It needs to auto-increment it self, and for that i have prepared the following code:
function getid() {
global $connection;
$idquery = "SELECT ribiid FROM systems ORDER BY ribiid DESC LIMIT 1";
$idsave = mysqli_query($connection, $idquery);
$idresult = mysqli_fetch_assoc($idsave);
$idalpha = substr($idresult['ribiid'], 0, 2);
$idnumeric = substr($idresult, 2);
$newidnumeric = $idnumeric + 1;
$newid = $idalpha . $newidnumeric;
return $newid;
}
Now for testing I manually entered a row in cmd with id = RB0000000000, the next entry that I submit through my webpage using php, should have been RB0000000001, but it is coming RB1.
How can I fix this, this is my first web database. Thanks
Your problem is that when adding 1 to $idnumeric PHP needs to treat it as a number. Leading zeroes in numbers do not make sense, so they are discarded.
To keep the zeroes you can use sprintf format the resulting (incremented) number:
$newid = sprintf("%s%010d", $idalpha, $newidnumeric);
However, using code like this is not a really good idea
There's an issue with this code though: it's subject to a race condition. Consider what could happen if two instances of the script run in parallel:
Instance A Instance B
T |
i | Reads ribiid RB..001 Reads ribiid RB..001
m | Generates next id RB..002 Generates next id RB..002
e v Writes RB..002 to DB
Writes RB..002 to DB => OOPS
As you see this situation will result in instance B failing to insert a record due to the use of a duplicate primary key. To solve this problem you need to eliminate the race condition, which you could do in one of several ways:
Use an AUTO_INCREMENT column for the PK instead of manually inserting values. Although this means you can no longer have the "RB" prefix as part of the key, you can move it to a different column and have the PK be a combination of these two columns.
LOCK TABLES ribiid while the insertion is taking place (note that the lock needs to cover all of the process, not just the getid function). Locking tables is something you normally want to avoid, but if inserts are not frequent it's a usable practical solution.
You could try something like this:
$newid = $idalpha . str_pad($newidnumeric, 10, '0', STR_PAD_LEFT);
This will add zeros to reach the ten chars.
You can padd the numeric string again using the following function:
function pad_number($number, $pad=10){
$pad_zero = $pad - strlen($number.'');
$nstr = '';
for($i =0; $i< $pad_zero; $i++){
$nstr .="0";
}
$nstr .= $number;
return $nstr;
}
You can use in your code this function as:
$newid = $idalpha . pad_number($newidnumeric);

Filtering MySQL query. "AND" operator

I'm getting excessive rows selected from the db. However, when i try to filter the data with AND lt_num it does not select anything at all. What could be the problem?
$w = $_POST['pal_num'];
$w = "'".implode("','",$_POST['pal_num'])."'";
$r = mysql_query("SELECT * FROM pl_tab WHERE pal_num AND lt_num in (".$weights.");");
My guess is you need to do two comparisons like this:
SELECT
*
FROM
pl_tab
WHERE
pal_num in (".$weights.")
AND lt_num in (".$weights.");
You can't say column1 and column2 = 3 for example. If you want rows where both are equal to 3, you would need to use column1=3 and column2=3 in your query.
Also, you might want to have a read of this Q&A that I wrote a while back which covers off a lot of basic SQL queries and expands from there.
Edit:
If you have $weights in the query, you do set it somewhere, or do you want it to be what is in your variables you show here:
$weights = $_POST['pal_num'];
$weights = "'".implode("','",$_POST['pal_num'])."'";
Is this what you meant?

Categories