MySQL LIKE with range doesn't work - mysql

I've got a database table mytable with a column name in Varchar format, and column date with Datetime values. I'd like to count names with certain parameters grouped by date. Here is what I do:
SELECT
CAST(t.date AS DATE) AS 'date',
COUNT(*) AS total,
SUM(LENGTH(LTRIM(RTRIM(t.name))) > 4
AND (LOWER(t.name) LIKE '%[a-z]%')) AS 'n'
FROM
mytable t
GROUP BY
CAST(t.date AS DATE)
It seems that there's something wrong with range syntax here, if I just do LIKE 'a%' it does count properly all the fields starting with 'a'. However, the query above returns 0 for n, although should count all the fields containing at least one letter.

You write:
It seems that there's something wrong with range syntax here
Indeed so. MySQL's LIKE operator (and SQL generally) does not support range notation, merely simple wildcards.
Try MySQL's nonstandard RLIKE (a.k.a. REGEXP), for fuller-featured pattern matching.

I believe LIKE is just for searching for parts of a string, but it sounds like you want to implement a regular expression to search for a range.
In that case, use REGEXP instead. For example (simplified):
SELECT * FROM mytable WHERE name REGEXP "[a-z]"
Your current query is looking for a string of literally "[a-z]".
Updated:
SELECT
CAST(t.date AS DATE) AS 'date',
COUNT(*) AS total,
SUM(LENGTH(LTRIM(RTRIM(t.name))) > 4
AND (LOWER(t.name) REGEXP '%[a-z]%')) AS 'n'
FROM
mytable t
GROUP BY
CAST(t.date AS DATE)

I believe you want to use WHERE REGEXP '^[a-z]$' instead of LIKE.

You have regex in your LIKE statement, which doesn't work. You need to use RLIKE or REGEXP.
SELECT CAST(t.date AS DATE) AS date,
COUNT(*) AS total
FROM mytable AS t
WHERE t.name REGEXP '%[a-zA-Z]%'
GROUP BY CAST(t.date AS DATE)
HAVING SUM(LENGTH(LTRIM(RTRIM(t.name))) > 4
Also just FYI, MySQL is terrible with strings, so you really should trim before you insert into the database. That way you don't get all that crazy overhead everytime you want to select.

Related

mysql get max number from a string field

I need to get maximum number from a part of the value that generally start with year followed by slash(/). So I need a maximum number after the slash(/) but year should be 2016
2016/422
2016/423
2016/469
2016/0470
2014/777
2015/123
2015/989
I tried this query
SELECT columname FROM tablename WHERE columname LIKE '2016/%' ORDER BY id DESC
the above query always giving '2016/469' as first record, how to get '2016/0470' as the maximum number?
any help will be much appreciated.
Thank you.
If columname follows that pattern YEAR/0000, you can use SUBSTRING function from MySQL to remove the part of the string you don't want.
SELECT value FROM (
SELECT CAST(SUBSTRING(columname, 0, 4) AS UNSIGNED) as year, CAST(SUBSTRING(columname FROM 6) AS UNSIGNED) as value FROM tablename
) total
ORDER BY year DESC, value DESC
LIMIT 1;
You need to split the string into 2 parts and evaluate them as numbers, instead of strings. The following formula will return the number after the / in the fieldname. All functions used below are described in the string functions section of the MySQL documentation. This way you can get the number after the / character, even if it is not year before the /, but sg else. The + 0 converts the string to a number, eliminating any leading 0.
select right(columnname, char_length(columnname)-locate('/',columnname)) + 0
from tablename
Just take the max() of the above expression to get the expected results.
UPDATE:
If you need the original number and the result has to be restricted to a specific year, then you need to join back the results to the original table:
select columnname
from tablename t1
inner join (select max(right(t.columnname, char_length(t.columnname)-locate('/',t.columnname)) + 0) as max_num
from tablename t
where left(t.columnname,4)='2016'
) t2
on right(t1.columnname, char_length(1t.columnname)-locate('/',t1.columnname)) + 0 = t2.max_num
where left(t1.columnname,4)='2016'
There are lots of suggestions given as answers already. But some of those seem overkill to me.
Seems like the only change needed to the OP query is the expression in the ORDER BY clause.
Instead of:
ORDER BY id
We just need to order by the numeric value following the slash. And there are several approaches, several expressions, that will get that from the example data.
Since the query already includes a condition columname LIKE '2016/%'
We can get the characters after the first five characters, and then convert that string to a numeric value by adding zero.
ORDER BY SUBSTRING(columname,6) + 0 DESC
If we only want to return one row, add
LIMIT 1
http://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_substring
If we only want to return the numeric value, we could use the same expression in the SELECT list, in addition columnname.
This isn't the only approach. There are lots of other approaches that will work, and don't use SUBSTRING.
Try like this:
SELECT
MAX(CAST(SUBSTRING(t.name,
LOCATE('/', t.name) + 1)
AS UNSIGNED)) AS max_value
FROM
tablename AS t;
You can try with this little uggly approach:
SELECT t.id, t2.secondNumber FROM table AS t
JOIN (SELECT id,
CONCAT(SUBSTRING(field,1,5),
if(SUBSTRING(SUBSTRING(field, 6),1,1)='0',
SUBSTRING(field, 6),
SUBSTRING(field,7)
)
) as secondNumber FROM table ) AS t2 ON t2.id=t.id
ORDER BY t2.secondNumber DESC
Would be valid only if the 0 (zeroes) before the second number (after the slash) are no more than 1.
Or if the year doesn`t matter you can try to order them only by the second number if it is ok:
SELECT t.id, t2.secondNumber FROM table AS t
JOIN (SELECT id,
if(SUBSTRING(SUBSTRING(field, 6),1,1)='0',
SUBSTRING(field, 6),
SUBSTRING(field,7)
) as secondNumber FROM table ) AS t2 ON t2.id=t.id
ORDER BY t2.secondNumber DESC

how to check value is numeric or not a numeric in mysql select query as follow

value->{1,2,Yes,No,5,6}
select if((value is numeric),value,'not a numeric') as column_name
how to implement this if in my mysql select query
This should do it :)
select if(field REGEXP '^-?[0-9]+$' > 0, field, 'not a numeric') as column_name
Example:
SELECT '12345' REGEXP '^-?[0-9]+$'
Returns: 1 (its a number)
SELECT 'abcdef' REGEXP '^-?[0-9]+$'
Returns: 0 (its NOT a number)
This is an old question, but when I needed the same thing the fastest solution was
select if((value *1),value, 'not a number') as column_name;
Granted, this will not consider zero a number, but neither did the Romans and they did ok for thousands of years. For me, given the improved speed across the hundreds of millions of rows, this was the best solution.
You can try it-
SELECT IF(table_column*1>0,table_column,'Not a Numeric')
FROM your_table;
Note: If there is a value "9 hello" then it will be treat as numeric as 9 is numeric value, if you need to exclude it also then revert. But in your question there is no such value.

mysql aggregate function for varchar column

I need to calculate the sum of one column(col2) , but the column has both numbers and text. How do I exclude the text alone before I use sum()?
The table has around 1 million rows, so is there any way other than replacing the text first?
My query will be :
Select col1,sum(col2) from t1 group by col1,col2
Thanks in advance
You can use regexp to filter the column:
Select col1,sum(col2) from t1 WHERE col2 REGEXP '^[0-9]+$' group by col1,col2
You could use MySQL built in REGEXP function.
to learn more visit : https://dev.mysql.com/doc/refman/5.1/en/regexp.html
Or another way is using CAST or CONVERT function
to learn in detail : https://dev.mysql.com/doc/refman/5.0/en/cast-functions.html
Hope this is helpful
Assuming you mean the number is at the beginning of the tex, the easiest way is simply to use implicit conversion:
Select col1, sum(col2 + 0)
from t1
group by col1, col2;
If col2 starts with a non-numeric character, then MySQL will return 0. Otherwise, it will convert the leading numeric characters to a number.
Note that your query doesn't really make sense, because you are aggregating by col2 as well as including it in the group by. I suspect you really want:
Select col1, sum(col2 + 0)
from t1
group by col1;

SELECT * but also use CAST()

I'm trying to select all fields for a number of rows from my MySQL table. One of my fields is called publication_date and it stores a string that represents a day that specific row is to be published on our website. It's stored in mm/dd/yyyy format.
I know I can cast that field to a DATE data type using CAST, but I'm not sure how to also grab the other fields' data.
Just add that column to your SELECT clause in addition to the *. Make sure to give it an alias so you can differentiate it from the regular datetime field.
SELECT *
, CAST(datefield AS date) AS aliasname
FROM tablename
You can do :
Select *,cast(publication_date as char) as newPublicationdate from tableName
Or if your table do not have lots of column it is much better to type it all
Select column1,column2,cast(publication_date as char) as publication_date from tableName
Regards

MySQL trim and string to date in one query

I'm trying to make some vchar values searchable based on a date.
The strings I have to work with look like this:
1/7/2006 12:45:24 AM
1/7/2006 1:18:36 AM
1/7/2006 1:21:43 AM
1/7/2006 1:32:09 AM
3/30/2006 12:32:10 PM
3/30/2006 1:19:30 PM
3/30/2006 1:20:44 PM
So first off let's get rid of the AM.. PHPMyAdmin the sql query is:
SELECT trim('AM' FROM `orderdate`) FROM tblorders
This works to get rid of the AM now let's set the values as a variable and try to wrap a string to str_to_date() around the results:
SELECT trim('AM' FROM `orderdate`) AS `value`, STR_TO_DATE(`value`,'%d,%m,%Y') FROM tblorders
This yields value as an unknown column. How else do you string two function values together so as to then use them to be filtered such as WHERE value > 2/1/2006 ?
You can compose functions like this:
select str_to_date(trim('AM' from orderdate), '%m/%d/%Y')
Note that I also corrected your date format to match your data. You don't actually need to trim those values to use str_to_date on them, just this will work fine:
select str_to_date(orderdate, '%m/%d/%Y')
If you want to use that in your WHERE clause then put the function calls in there:
select trim('AM' from orderdate), str_to_date(orderdate, '%m/%d/%Y')
from your_table
where str_to_date(orderdate, '%m/%d/%Y') > '2006-01-02'
and let the optimizer recognize the repetition or use a derived table:
select value, the_date
from (
select trim('AM' from orderdate) as value, str_to_date(orderdate, '%m/%d/%Y') as the_date
from your_table
) dt
where the_date > '2006-01-02'
Note the use of ISO 8601 dates in the query, that format is unambiguous and any database worth using will understand it regardless of your locale settings.
I'd also recommend that you fix your schema to use real timestamps instead of those strings.