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;
Related
I run a SQL query like below in MySQL:
select *
from (
select 2 as o,1 as t from dual
union
select 1 as o,2 as t from dual
) x
order by if((select 1),o,t);
It works well, but when I use column relative position in if statement, it doesn't work.
How can I use column relative position in if in ORDER BY statement?
select *
from (
select 2 as o,1 as t from dual
union
select 1 as o,2 as t from dual
) x
order by if((select 0),1,2);
I'm not sure what your real confusion is. When an integer appears in an order by, then this is treated as a column number. Any other use of an integer is interpreted as an expression.
The use of column numbers has been removed from the SQL standard. Hence, its use in any particular database is not guaranteed in future releases. It is really better to use the column names.
I think you want to sort your query based on a criteria over two columns, if I'm correct, you can use something like this:
...
order by
case when (your criteria)
then column1
else column2
end;
Note: use union all instead union when you don't want to remove duplicate values as performance issue ;).
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
I am trying to perform a MySql select with many conditions, but want to perform a string comparison on a column that is an integer datatype. Is there a way to do this without having to cast the column to a varchar on every single condition within the where clause?
SELECT COUNT(*)
FROM tablename
WHERE CAST(col1 AS VARCHAR(10)) NOT LIKE '558%'
AND CAST(col1 AS VARCHAR(10)) NOT LIKE '566%'
AND CAST(col1 AS VARCHAR(10)) NOT LIKE '567%'
AND CAST(col1 AS VARCHAR(10)) NOT LIKE '568%'
AND CAST(col1 AS VARCHAR(10)) NOT LIKE '569%'
AND CAST(col1 AS VARCHAR(10)) NOT LIKE '579%';
Before you ask why I'm not doing integer comparison: Instead of casting to a varchar, I could also just use plain integer comparison, but then I still would have to perform a math operation, i.e. col1/100000, for every item in the where clause, which leads to the same problem as to how can I simplify the statement?
You can use subquery:
SELECT COUNT(*)
FROM
(
SELECT CAST(col1 AS VARCHAR(10)) AS col1
FROM tablename
) AS t
WHERE t.col1 NOT LIKE '558%'
...
The direct answer to your question is that casts are implicit in MySQL, so col1 NOT LIKE '556%' is equivalent to what you're doing.
It's always best to avoid using functions that reference column names in the WHERE clause, because that disables the use of indexes and requires every row in the table to be evaluated. I assume that you are aware of that, since you mentioned you would still "have to do a math operation."
If you actually know the scale of the number then a more correct query would be...
WHERE (col1 < 556 * 100000 OR col1 > 556 * 100000)
AND ...
If that's logically correct based on what you are doing, then it's a better solution, because the optimizer will do that math only once, converting those into constants, rather than doing it once per row.
Also note that if you do know the scale of the numbers, then LIKE '556______' is also more logically valid than using % since _ matches exactly one character, where % matches zero or more.
In a MySQL table i have a field, containing this value for a given record : "1908,2315,2316"
Here is my sql Query :
SELECT * FROM mytable WHERE 2316 IN (myfield)
I got 0 results!
I tried this :
SELECT * FROM mytable WHERE 2315 IN (myfield)
Still 0 results
And then i tried this :
SELECT * FROM mytable WHERE 1908 IN (myfield)
Surprisingly i obtained the record when searching with 1908! What should i do to also obtain the record when searching with 2315 and 2316 ? What am i missing ?
Thanks
You appear to be storing comma delimited values in a field. This is bad, bad, bad. You should be using a junction table, with one row per value.
But, sometimes you are stuck with data in a particular structure. If so, MySQL provides the find_in_set() functions.
SELECT *
FROM mytable
WHERE find_in_set(2316, myfield) > 0;
You can't use IN() over comma separated list of no.s its better to normalize your structure first for now you can use find_in_set to find results matching with comma separated string
SELECT * FROM mytable WHERE find_in_set('1908',myfield) > 0
This question has been asked and answered before, but I don't want to hunt for it; this question should be closed as a duplicate. But, to answer your question:
The commas in the string, the column value, are just characters. Those are part of the string. They aren't seen as "separators" between values in the SQL text. The way SQL sees it, the column contains a single value, not a "list" of values.
So, in your query, the IN (field) is equivalent to an equals comparison. It's equivalent to comparing to a string. For example:
... WHERE 2316 = '1908,2315,2316'
And those aren't equal, so the row isn't returned. The "surprisingly" finding of a match, in the case of:
... WHERE 1908 IN ('1908,2315,2316')
that's explained because that string is being evaluated in a numeric context. That is, the comparison returns true, because all of these also true:
... WHERE 1908 = '1908,2315,2316' + 0
... WHERE 1908 = '1908xyz' + 0
... WHERE 1908 = '1907qrs' + 1
(When evaluated in a numeric context, a string gets converted to numeric. It just happens that the string evaluates to a numeric value that equals the integer value it's being comparing to.)
You may be able to make use of the MySQL FIND_IN_SET function. For example:
... WHERE FIND_IN_SET(2316,'1908,2315,2316')
But, please seriously reconsider the design of storing comma separated list. I recommend Bill Karwin's "SQL Antipatterns" book...
http://www.amazon.com/SQL-Antipatterns-Programming-Pragmatic-Programmers/dp/1934356557
In mysql IN clause is utilized as
SELECT * FROM mytable WHERE column_name IN (set_of_values) ;
Mention column name instead of values
Please try
SELECT * FROM mytable WHERE LOCATE(CONCAT (',', 2316 ','), CONCAT (',',myfield,',' ) ) <>0
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.