This SQL query:
select c1 from table where c1='';
returns rows that have c1=' ' (one empty space) in MySQL.
Is this intended or a bug?
EDIT: please check SQL Fiddle link here, and the number of spaces in SELECT query doesn't matter.
It's all stated there in the documentation. I've quoted the important points here. But I would suggest to go through the full documentation
VARCHAR values are not padded when they are stored. Trailing spaces
are retained when values are stored and retrieved, in conformance with
standard SQL.
On the other hand, CHAR values are padded when they are stored but
trailing spaces are ignored when retrieved.
All MySQL collations are of type PADSPACE. This means that all CHAR,
VARCHAR, and TEXT values in MySQL are compared without regard to any
trailing spaces. “Comparison” in this context does not include the
LIKE pattern-matching operator, for which trailing spaces are
significant.
Explanation: Trailing spaces are ignored while comparing strings using comparison operator ('='). But trailing spaces are significant for LIKE (pattern matching operator)
This is documented behaviour.
The MySQL documentation for LIKE mentions
trailing spaces are significant, which is not true for CHAR or
VARCHAR comparisons performed with the = operator:
SQL Server works the same way.
If your column is from type CHAR and not VARCHAR, than this is correct.
On CHAR-Fields will trailing blanks on comparing ignored!
So
field = ''
field = ' '
are the same.
This behavior is in accordance with ANSI SQL-92 standard. Any database conforming to this standard will exhibit same behavior. Quote:
3) The comparison of two character strings is determined as fol-
lows:
a) If the length in characters of X is not equal to the length
in characters of Y, then the shorter string is effectively
replaced, for the purposes of comparison, with a copy of
itself that has been extended to the length of the longer
string by concatenation on the right of one or more pad char-
acters, where the pad character is chosen based on CS. If
CS has the NO PAD attribute, then the pad character is an
implementation-dependent character different from any char-
acter in the character set of X and Y that collates less
than any string under CS. Otherwise, the pad character is a
<space>.
b) The result of the comparison of X and Y is given by the col-
lating sequence CS.
So, according to these specs 'abc' = 'abc ' and '' = ' ' evaluate to true (but '' = '\t' is false).
If c1 is CHAR(1), then this is correct, as CHAR columns are fixed width and will be filled with blanks if necessary.
So even if you put '' into a CHAR(1) field you will get ' ' upon SELECTing. Also, filtering for an empty string will yield ' '.
Please accept Martin Smith's answer, as he gave the correct hint before me.
Also, as per MySQL documentation, trailing whitespace is ignored when comparing strings with =, so if your c1 column contains only spaces (or one in your case), it will be returned even though you filter WHERE c1 = '':
In particular, trailing spaces are significant, which is not true for CHAR or VARCHAR comparisons performed with the = operator
mysql> SELECT 'a' = 'a ', 'a' LIKE 'a ';
+------------+---------------+
| 'a' = 'a ' | 'a' LIKE 'a ' |
+------------+---------------+
| 1 | 0 |
+------------+---------------+
1 row in set (0.00 sec)
select c1, length(c1) as l
from table t_name
group by l
(figur eht oot)
Try this -
Select case when c1 = '' then ' ' else c1 end from table ;
Related
I was watching this mysql course where it the following example was given:
SELECT Name, Continent, Population FROM Country WHERE Name LIKE '_%a' ORDER BY Name;
And they said that '_a%' would match all strings in the Name column whose second character is a. I'm using MariaDB server 10.0.34 on Ubuntu and in my case, the result is quite different. Instead, it shows all strings in the Name column who end in a. Any idea why that is and where the difference exists?
Thanks.
Ummm. A couple of points.
1) those are not regular expressions, those are LIKE comparisons. (Yeah, yeah, to-may-toh, tah-mah-toh, I know.) But we can be precise in our terminology, and avoid confusion and obfuscation.
2) '_%a' and '_a%' are significantly different, as your own observations have revealed
_ underscore matches any one character
% percent matches zero, one or more of any character
a matches the character 'a'
So
LIKE '_a%' matches any single character, followed by an 'a', followed by any number of (zero, one or more) characters
LIKE '_%a' matches any single character, followed by any number of (zero, one or more) any characters, and ending with an 'a'
As a demonstration:
SELECT 'name' LIKE '_a%' -- true - at least two chars, second char is a
, 'name' LIKE '_%a' -- false - at least two chars, last char is a
, 'name' LIKE '_e%' -- false - at least two chars, second char is e
, 'name' LIKE '_%e' -- true - at least two chars, last char is e
Those are LIKE comparisons. To do the equivalent using regular expression, something like this:
SELECT 'name' REGEXP '^.a' -- at least two chars, second char is a
, 'name' REGEXP '^..*a$' -- at least two chars, last char is a
, 'name' RLIKE '^.e' -- at least two chars, second char is e
, 'name' RLIKE '^..*e$' -- at least two chars, last char is e
I have a MySQL-Database with a column mystring varchar(255).
What I want to know is the occurences of standard latin uppercase letters ('A' to 'Z').
So for example "AbcDeF" countains 3 upperscase letters and "XYZZ" contains 4.
Basically I would like to calculate the value in the database, something in the form of:
SELECT count_characters(mystring, 'A', 'Z') FROM mytable;
Is it possible in MySQL?
This result can be returned from MySQL. It's not impossible, but it's downright ugly. To make this prettier, you need to hide the ugliness in a user defined function.
You can use the REPLACE function to do a case sensitive search, to replace a specific character with a zero length string. Repeat that for each specific character you want to count. Then get the character length of the resulting string, and subtract that from the character length of the original string. The difference is the number of characters that were replaced (which was the number of characters you wanted to count).
As an example, to get a count of the uppercase letters 'A' thru 'D' from a particular column, for each row in your table...
SELECT CHAR_LENGTH(t.mycol) -
CHAR_LENGTH(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
t.mycol
,'A','')
,'B','')
,'C','')
,'D','')
) AS count_characters
FROM mytable t
It's ugly, but it will return the specified result.
NOTE: The LENGTH function would work for the latin characters 'A' thru 'Z', but we use the CHAR_LENGTH function in anticipation of handling multi-byte UTF encodings.
From select statement, in a filed I want to remove last characters is character if its number. Is there string function available in MySQL?
for these two SQL I want
test
as output
select 'test1';
select 'test';
Another way is to use REGEXP,
SET #val = 'test12';
SELECT CONCAT(LEFT(#val, CHAR_LENGTH(#val) - 1),
IF(RIGHT(#val, 1) REGEXP '[0-9]' = 0, RIGHT(#val, 1), ''))
SQLFiddle Demo
SQLFiddle Demo (another example)
To remove the last character if it's numeric, one way to do this without using a regular expression is with LEFT, RIGHT and LENGTH :
select if( right(yourfield,1) = 0 && right(yourfield,1) != '0',
yourfield,
left(yourfield, length(yourfield) - 1))
from yourtable;
To replace all trailing numeric values, you can use REVERSE:
select if( cast(reverse(yourfield) as signed) = 0 && right(yourfield,1) != '0',
yourfield,
left(yourfield, length(yourfield) - length((reverse(yourfield) + 0))))
from yourtable;
SQL Fiddle Demo
When casting fields as integers/signed in MySQL, it will cast all the numeric characters up to the first non-numeric character -- thus making the REVERSE work. If the last character is not numeric, it results in 0.
Using the IF check above, if the last character isn't numeric, then it prints the original value, else it prints all but the last character.
here is a pointer:
use a union between two queries.
in the first - either use REGEX, or grab the substr of the field where another substr for the last char is a number,
then union the text field where the substr of the last char is not a number.
You might want to use Regular Expressions inside MySQL. This package might help you https://launchpad.net/mysql-udf-regexp. However, I do not recommend to do it inside MySQL statement as it might be slow. You would better to do it after grabbing the value inside your programming language.
I have read that after select we use column-names but I have found a statement that was like this:
SELECT 'A' FROM T WHERE A = NULL;
would you lease help me? thanks (A is a column- name here?)
my DBMS is MySQL
EDITED : the exact question is this that:
Will the above statement produce a row (select all that
apply)? Notice that ANSI_NULLS is OFF.
I want to know that the above statement will work? because some of you said that we should write IS NULL instead of =null
Based on that query, you would get a result set containing the character 'A' for each row where the column named A was equal to null.
If you actually want to see the value of the column A instead of the character 'A', you have to remove the single quotes:
SELECT A FROM T WHERE A IS NULL
Either way, you should not use = NULL. Certain RDMSs don't handle that the way you would think. The standard is to use IS NULL instead.
You should use
SELECT 'A' FROM T WHERE A IS NULL;
There are three types of quotes in SQL.
The single quote ' means that something is a string literal. 'A' in this instance means that it returns the character A for all rows where the column A is NULL.
The double quote " means that something is an identifier. This is useful if the identifier has the same name as a reserved word, like select. Example: SELECT "select" FROM T selects the column select from the table T.
The backtick quote ` works only in MySQL, and is the same as the double quote. The double quote can sometimes used for string literals in MySQL, although this is very much against the standard. MySQL has an option to conform to the standard, using SET SQL_MODE='ANSI'; where the backtick becomes invalid, and you need to use the single and double quotes instead.
An identifier without quotes is the same as an identifier with double quotes, unless it's a reserved word.
Hope this helps understand a bit more.
In answer to your question:
A = NULL is always false, so you will get no rows returned. To compare with NULL you must use A is NULL instead.
NULL is special in SQL, in that it is not equal to anything, even itself. Yep, (NULL = NULL) evaluates to false.
If you change it to IS NULL, then you will get a set of rows with one column, containing the character 'A' in each row. You will get one 'A' for each row in the table T where the A column is null.
You will get the letter A and not the value of the column because you have quotes around the 'A'. If you remove them, you'll get the value of A in each row (which will be null, because those are the rows you're selecting with your where clause).
If you wanted to see which rows in T had a null value for A, then you should change it to select * from T where A is null
Your SELECT statement has the following meaning:
"For every row of the table called T, return the string 'A' if the column A of the table T is NULL"
So, if you have 3 records where A is NULL, the output will be:
A
A
A
3 row(s) selected
The correct syntax is WHERE A IS NULL, and not WHERE A = NULL.
Have you tried running it on your test database to see what it does? Or was this just in reading?
Breaking down that statement, what is says is:
In the table T (FROM T), find the rows where the value of A is null (WHERE A = NULL).
For each of those rows, return an 'A'.
The result I would expect is
+--+
|T |
+--+
|A |
|A |
...
|A |
+--+
If the statement was instead:
SELECT A FROM T WHERE A = NULL;
Where the single quotes are removed, it would return a bunch of nulls, the value of the column A.
A is a column name, but you probably don't want single-quotes around it. I'd try...
SELECT A FROM T WHERE A IS NULL;
in mysql:
select 'a' = 'a ';
return 1
You're not the first to find this frustrating. In this case, use LIKE for literal string comparison:
SELECT 'a' LIKE 'a '; //returns 0
This behavior is specified in SQL-92 and SQL:2008. For the purposes of comparison, the shorter string is padded to the length of the longer string.
From the draft (8.2 <comparison predicate>):
If the length in characters of X is not equal to the length in characters of Y, then the shorter string is effectively replaced, for the purposes of comparison, with a copy of itself that has been extended to the length of the longer string by concatenation on the right of one or more pad characters, where the pad character is chosen based on CS. If CS has the NO PAD characteristic, then the pad character is an implementation-dependent character different from any character in the character set of X and Y that collates less than any string under CS. Otherwise, the pad character is a <space>.
In addition to the other excellent solutions:
select binary 'a' = 'a '
I googled for "mysql string" and found this:
In particular, trailing spaces [using LIKE] are significant, which is not true for CHAR or VARCHAR comparisons performed with the = operator
From the documentation:
All MySQL collations are of type PADSPACE. This means that all CHAR and VARCHAR values in MySQL are compared without regard to any trailing spaces
The trailing spaces are stored in VARCHAR in MySQL 5.0.3+:
CREATE TABLE t_character (cv1 CHAR(10), vv1 VARCHAR(10), cv2 CHAR(10), vv2 VARCHAR(10));
INSERT
INTO t_character
VALUES ('a', 'a', 'a ', 'a ');
SELECT CONCAT(cv1, cv1), CONCAT(vv2, vv1)
FROM t_character;
but not used in comparison.
Here's another workaround that might help:
select 'a' = 'a ' and length('a') = length('a ');
returns 0