i faced a unique problem by accident
But before that i want to show you a table structure
td_category
|---------------------------------------------------------------------|
| category_id | category_title | category_slug | p_cid |
|---------------------------------------------------------------------|
| 1 | Shirts | 1-Shirts | 0 |
|---------------------------------------------------------------------|
| 2 | Jeans | 2-Jeans | 0 |
|---------------------------------------------------------------------|
Now,
category_id is INT and auto-increment value
category_title is VARCHAR
category_slug is VARCHAR
Now what i amdoing is that, by mistake i wrote a query
SELECT * FROM td_category WHERE category_id = '2-Jeans'
and instead of giving me any error it displayed the 2nd tuple
Isn't it supposed to throw an error??
please can anybody clarify?
mysql performs implicit conversion for int datatype due to which '2-Jeans' is treated as 2-0 (since Jeans is not an int type and is defaulted to 0 for compatibility as described in the docs here)
Hence the final query as the parser interprets is as below:
SELECT * FROM td_category WHERE category_id = 2;
The following query will take id as 2 which is your first character and display second record
SELECT * FROM td_category WHERE category_id = '2-Jeans'
Try this query which will return first record
SELECT * FROM td_category WHERE category_id = '1-Jeans'
2-jeans is treated as 2 so return second record and 1-jeans is treated as 1 so return first record.
Check Manual for auto casting in mysql.
Related
Using MySQL 5.5.60.
I'm running into some peculiar behavior when running select queries in Mysql. I have a table list whose schema looks like this:
+-----------------------+--------------+------+-----+-----------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+--------------+------+-----+-----------------+----------------+
| list_id | int(11) | NO | PRI | NULL | auto_increment |
| vendor_id | int(11) | NO | MUL | NULL | |
| referrer_id | int(11) | NO | | 0 | |
...
If I run this query
mysql> select * from list where list_id = "1946"\G
Everything works as it should and the list with id 1946 is returned. Here is where it gets weird. If I change my query to look like this:
mysql> select * from list where list_id = "1946dhkdf"\G
It still returns list 1946! Clearly MySQL somehow cast off the dhkdf part and uses the 1946 portion only. So does it try to cast that value to an Integer that way? Why then does this query return and empty set?
mysql> select * from list where list_id = "xq1946dhkdf"\G
I can't seem to find any documentation explaining this behavior. Can someone shed some light on it?
You are seeing MySQL's somewhat complex casting rules at work here. When trying to compare an integer column against a string literal, either one has to be cast to integer, or the other to string. In this case, MySQL will try to cast the string literal to an integer, to match the type of the column. But, in this case, it can't cast the entire string literal to an integer, since it contains characters. Therefore, the casting rules kick in, which state that if the first N characters of the string be numeric, then use only that leading number. So, as a result the following query:
select * from list where list_id = "1946dhkdf";
will return the same result set as:
select * from list where list_id = "1946";
I have the following query and result:
mysql> SELECT item_id FROM phppos_items WHERE item_id = '5CG4500RRL';
+---------+
| item_id |
+---------+
| 5 |
+---------+
item_id is an int(11) primary key
How do I prevent this from matching? It looks like it is somehow becoming 5 when matching.
I still want to run this code so I don't have to change a lot of logic so I would prefer to keep it in mysql to do a strict comparison if possible.
I can be done by several methods. For example:
SELECT item_id
FROM phppos_items
WHERE '5CG4500RRL' REGEXP '^[0-9]+$' AND item_id = '5CG4500RRL';
Here we check is input value digits only and it equal to item_id.
Here you can find more options to check input value.
i'm not an mysqlologist but i have to deal with the following problem:
given a following table:
+-------+-----------+-------------+------+
| id | articleID | img | main |
+-------+-----------+-------------+------+
| 48350 | 4325 | scr426872xa | 1 |
| 48351 | 4325 | scr426872ih | 2 |
| 48352 | 4325 | scr426872jk | 2 |
| 48353 | 4326 | scr426882vs | 1 |
| 48354 | 4326 | scr426882ss | 2 |
| 48355 | 4326 | scr426882nf | 2 |
+-------+-----------+-------------+------+
each set of images of one distinct articleID should have one image set as main=1 and an unspecified number of images with main value of 2
Due to processing issues it can happen that there is no main=1 set for an image and i need to find the articleID where images with main=2 exist, but not with main=1.
By explaining it backwards it is easier to fomulate what my thinking process for the query is. My idea was to create a result set (subquery) by querying the table for articleID where main is "1". Then use that result to check which distinct articleID of a query where main=2 is not in the results of aforementioned (sub-)query. Basically "substracting" all matching articleID lines.
This should give basically the leftover of all main=2 lines which have no line with the same articleID where main=1
SELECT DISTINCT articleID
FROM img_table WHERE main = 2
AND articleID
NOT IN (SELECT articleID FROM img_table WHERE main = 1 );
I get no result when I know for a fact that there are some. There is surely something I'm doing wrong. I hope my problem is explained in a way that not only me know what I want :)
Given your problem description, it looks like you're actually looking for NOT EXISTS to check for rows that don't have a matching row in the subselect. Note that you do have to add the article id to the where clause in the subselect:
SELECT DISTINCT articleID
FROM img_table t1
WHERE main = 2
AND NOT EXISTS
(SELECT articleID
FROM img_table t2
WHERE main = 1
AND t2.articleID = t1.articleID);
I think your current solution should work too, but maybe you didn't show all the data. For the data you specified, the query would indeed return 0 rows, because all articleIDs have at least one main=1 and a main=2 image.
One important thing to remember: the subquery must not return any NULL value, otherwise NOT IN won't work properly. So if articleID is nullable, make sure your subselect looks like this:
(SELECT articleID FROM img_table WHERE main = 1 and articleID IS NOT NULL)
I didn't find any issue in your query, Please add some data where article id having only main 2. Your query checking both article ID contains main 1,2. ie why you not getting any result.
I have a field for comments used to store the title of the item sold on the site as well as the bid number (bid_id). Unfortunately, the bid_id is not stored on its own in that table.
I want to query items that have a number (the bid_id) greater than 4,000 for example.
So, what I have is:
select * from mysql_table_name where comment like '< 4000'
I know this won't work, but I need something similar that works.
Thanks a lot!
Just get your bid_id column cleaned up. Then index is.
create table `prior`
( id int auto_increment primary key,
comments text not null
);
insert `prior` (comments) values ('asdfasdf adfas d d 93827363'),('mouse cat 12345678');
alter table `prior` add column bid_id int; -- add a nullable int column
select * from `prior`; -- bid_id is null atm btw
update `prior` set bid_id=right(comments,8); -- this will auto-cast to an int
select * from `prior`;
+----+-----------------------------+----------+
| id | comments | bid_id |
+----+-----------------------------+----------+
| 1 | asdfasdf adfas d d 93827363 | 93827363 |
| 2 | mouse cat 12345678 | 12345678 |
+----+-----------------------------+----------+
Create the index:
CREATE INDEX `idxBidId` ON `prior` (bid_id); -- or unique index
select * from mysql_table_name where substring(comment,start,length, signed integer) < 4000
This will work, but I suggest create new column and put the bid value in it then compare.
To update value in new column you can use
update table set newcol = substring(comment,start,length)
Hope this will help
There is nothing ready that works like that.
You could write a custom function or loadable UDF, but it would be a significant work, with significant impact on the database. Then you could run WHERE GET_BID_ID(comment) < 4000.
What you can do more easily is devise some way of extracting the bid_id using available string functions.
For example if the bid_id is always in the last ten characters, you can extract those, and replace all characters that are not digits with nil. What is left is the bid_id, and that you can compare.
Of course you need a complex expression with LENGTH(), SUBSTRING(), and REPLACE(). If the bid_id is between easily recognizable delimiters, then perhaps SUBSTRING_INDEX() is more your friend.
But better still... add an INTEGER column, initialize it to null, then store there the extracted bid_id. Or zero if you're positive there's no bid_id. Having data stored in mixed contexts is evil (and a known SQL antipattern to boot). Once you have the column available, you can select every few seconds a small number of items with new_bid_id still NULL and subject those to extraction, thereby gradually amending the database without overloading the system.
In practice
This is the same approach one would use with more complicated cases. We start by checking what we have (this is a test table)
SELECT commento FROM arti LIMIT 3;
+-----------------------------------------+
| commento |
+-----------------------------------------+
| This is the first comment 100 200 42500 |
| Another 7 Q 32768 |
| And yet another 200 15 55332 |
+-----------------------------------------+
So we need the last characters:
SELECT SUBSTRING(commento, LENGTH(commento)-5) FROM arti LIMIT 3;
+-----------------------------------------+
| SUBSTRING(commento, LENGTH(commento)-5) |
+-----------------------------------------+
| 42500 |
| 32768 |
| 55332 |
+-----------------------------------------+
This looks good but it is not; there's an extra space left before the ID. So 5 doesn't work, SUBSTRING is 1-based. No matter; we just use 4.
...and we're done.
mysql> SELECT commento FROM arti WHERE SUBSTRING(commento, LENGTH(commento)-4) < 40000;
+-------------------+
| commento |
+-------------------+
| Another 7 Q 32768 |
+-------------------+
mysql> SELECT commento FROM arti WHERE SUBSTRING(commento, LENGTH(commento)-4) BETWEEN 35000 AND 55000;
+-----------------------------------------+
| commento |
+-----------------------------------------+
| This is the first comment 100 200 42500 |
+-----------------------------------------+
The problem is if you have a number not of the same length (e.g. 300 and 131072). Then you need to take a slice large enough for the larger number, and if the number is short, you will get maybe "1 5 300" in your slice. That's where SUBSTRING_INDEX comes to the rescue: by capturing seven characters, from " 131072" to "1 5 300", the ID will always be in the last space separated token of the slice.
IN THIS LAST CASE, when numbers are not of the same length, you will find a problem. The extracted IDs are not numbers at all - to MySQL, they are strings. Which means that they are compared in lexicographic, not numerical, order; and "17534" is considered smaller than "202", just like "Alice" comes before "Bob". To overcome this you need to cast the string as unsigned integer, which further slows down the operations.
WHERE CAST( SUBSTRING(...) AS UNSIGNED) < 4000
I'm creating a PHP script to insert rows into a database called orders based on a shopping cart that is stored in an associative array using a sessional array $_SESSION['cart']. The database looks something like this:
orders
----------+--------------+-------------+-------------+-------------+
Id | Username | Item1Id | Item2Id | Item3Id |
----------+--------------+-------------+-------------+-------------+
1 | a#aa.com | 8000001 | 8000002 | 800003 |
----------+--------------+-------------+-------------+-------------+
5 | a#aa.com | 7000001 | 6000002 | 700003 |
----------+--------------+-------------+-------------+-------------+
7 | b#bb.com | 8000001 | 8000002 | NULL |
----------+--------------+-------------+-------------+-------------+
10 | a#aa.com | 3000001 | 1000002 | 800009 |
----------+--------------+-------------+-------------+-------------+
Id column type is CHAR(20) as I may choose to use letters later on.
As part of inserting the row, I need to assign an Id (Primary Key) to the order row which will be set to 1 higher than the current highest Id number found.
The whole script works perfectly; query finds highest Id in the table and I increment that by 1 and assign it to a variable to use as part of the insert query. The only problem is that "SELECT MAX(Id) FROM orders" can't seem to find anything higher than 9. Is there a condition which prevents the SELECT MAX(Id) from identifying anything in double digits?
I've got it written like:
$highestID = mysqli_query($conn, "SELECT MAX(Id) FROM orders");
$orderID = $highestID +1;
I've emptied the database except for Id numbers1 and 2. Running the PHP script inserts new rows with Id numbers 3, 4, 5 except when it gets to 10, the script is unable to as it produces an error of having duplicate primary key of '10' (from $orderID's value). Even when manually entering a row into the database with Id of '25', $orderID still only returns '10' when I echo out its result.
I have not set any specific limits to the amount of rows that can be entered or anything like that.
Id is char(20) so order by Id using string sort. You could use cast or convert function to sort numbers.
Like:
select max(cast(Id as unsigned)) from orders
You really do not need to go through ALL that trouble for an auto-incremental PK. Here's how you can go about it.
Step 1 : In your phpmyadmin, edit your table, and check the A_I checkbox for your PK column.
Step 2 : While inserting from PHP, leave the field blank. It will automatically assign a value of the current max + 1 to your PK.
Eg,
$query = "Insert into mytable (id, name) values ('', 'Name1'), ('', 'Name2')";
Edit : You really cannot have a CHAR(20) PK and then expect the increment to work btw.