Finding the null rate of the column device_id - mysql

I'm trying to write a code that will display the null count for a column in a table
I wrote the code below but i've been running into a syntax issue
SELECT device_id AS FIELD, COUNT (*)
FROM (SELECT *
FROM TABLE
WHERE TRIM(UPPER(device_id) IN ('','NULL',) OR device_id IS NULL OR SUBSTRING(TRIM(UPPER(device_id)), 1,1) = '-')
AND (event_date between '2019-05-20' AND '2019-05-27')
);
I've been experiencing a syntax error
cannot recognize input near ')' 'OR' 'device_id' in expression
specification:17:16,

In MySQL at least, subqueries require an alias. But you don't need a subquery. So I think you want:
SELECT COUNT(*)
FROM <TABLE> t
WHERE (TRIM(UPPER(device_id)) IN ('', 'NULL') OR
device_id IS NULL OR
TRIM(UPPER(device_id)) LIKE '-%')
) AND
event_date between '2019-05-20' AND '2019-05-27';
Notes:
You had a trailing comma in the `IN list.
I don't think you had the write parentheses before the event_date comparison.
You cannot include device_id in the SELECT unless you have GROUP BY, but I think you just want the count.
LIKE is much easier than SUBSTRING() for your third comparison.
All the TRIM()s and UPPER()s suggest that you should maintain better control of your data. These should not be necessary, particularly in an "id" column.

Related

Filtering by alphanumeric

I want to sort a table by a column named 'generic_location'.
generic location data is conformed by numbers, letters and then numbers like these:
'4A1', '5AW89', '7AA89', ETC
I trying to split the data using regexp_substr and order by CAST(generic_location AS UNSIGNED) ASC but it doesn't show as I want.
this is what I get.
4A14
4A15
4AW39
4AW70
4A75
4AW83
This is my current query:
SELECT gen_loc,
regexp_substr(generic_location, '^[0-9]*') AS `A`,
regexp_substr(generic_location, '[A-Z]+') AS `B`,
REGEXP_REPLACE(generic_location, '([0-9]+[A-Z]+)+', '') AS `C`
FROM boms ORDER BY CAST(A AS UNSIGNED) ASC, CAST(B AS UNSIGNED), CAST(C AS UNSIGNED);
I want the column order shows like:
4A14
4A15
4A75
4AW39
4AW70
4AW83
Is there any way to order the generic location column like this?
Thank you!
The problem you are facing is casting varchar to int perhaps hoping to obtain ASCII code sum.
The correct query is the following where MySQL is using inbuilt alphabetical sorting
SELECT gen_loc,
regexp_substr(generic_location, '^[0-9]*') AS `A`,
regexp_substr(generic_location, '[A-Z]+') AS `B`,
REGEXP_REPLACE(generic_location, '([0-9]+[A-Z]+)+', '') AS `C`
FROM boms ORDER BY CAST(A AS UNSIGNED) ASC, B, CAST(C AS UNSIGNED);
Notice B is not being cast.
Also, not sure why you had to use substrings, the following query achieves the same result
SELECT gen_loc, generic_location FROM boms ORDER BY generic_location ASC;

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

Use the result of the MySQL SELECT query as a WHERE condition in the same query

I'm trying to do this query:
SELECT MAX(`peg_num`)
AS "indicator"
FROM `list`
WHERE `list_id` = 1
AND "indicator" >= 1
But I'm getting the result of NULL. What I should be getting is 99, as the range of peg_num is 00 to 99.
The value checked against "indicator" should actually be a user input, so I want it to be versatile. But, it does give me the correct result if I flip the equality around:
SELECT MAX(`peg_num`)
AS "indicator"
FROM `list`
WHERE `list_id` = 1
AND "indicator" <= 1
Why would it do this?
Edit:
As suggested, I'm using the HAVING clause... but I just ditched the alias for now anyway:
SELECT MAX(`peg_num`) AS "indicator"
FROM `list`
GROUP BY `list_id`
HAVING MAX(`peg_num`) <= 40
Still very stubborn. It gives me 99 now no matter the value in the having clause, regardless of the inequality.
Edit2:
As a clarification:
What I want to happen is the query select the largest value in the range of peg_num, but only if it is larger than a user-given input. So, the max in this case is 99. If the user wants to select a number like 101, he/she can't because it's not in the range.
Because of double quotes, "indicator" in WHERE clause is interpreted as a string. Thus, it evaluates to 0, meaning it is always less than 1. Column names must be escaped in backticks.
Keep in mind that WHERE clause is executed before SELECT an hence aliases defined in SELECT can not be used in WHERE clause.
SELECT MAX(`peg_num`) AS `indicator`
FROM `list`
WHERE `list_id` = 1
HAVING `indicator` >= 1
You might want to check out the link on the answer to another Stack question about not being allowed to use alias in where clause:
Can you use an alias in the WHERE clause in mysql?
Paul Dixon cites:
It is not allowable to refer to a column alias in a WHERE clause,
because the column value might not yet be determined when the WHERE
clause is executed. See Section B.1.5.4, “Problems with Column
Aliases”.
Also:
Standard SQL disallows references to column aliases in a WHERE clause.
The behavior you're seeing in your query when you swap the '<=' and '>=' operators, results from the query comparing the string/varchar 'indicator' to the number 1.
That's why you see the correct answer..when ('indicator' >= 1) which is true, and null when ('indicator' <= 1) which is false.
I don't know, but I'm amazed either of them work at all. WHERE works serially on fields belonging to individual records and I wouldn't expect it to work on "indicator" since that's a group calculation.
Does this do what you want?
SELECT max(`peg_num` ) AS "indicator"
FROM actions
WHERE `peg_num` >=1
AND `list_id` <= 1
WHERE happens before SELECT, and don't know what's "indicator".
You should use HAVING (with GROUP BY) to use the SELECT fields
Here's the documentation for syntax
http://dev.mysql.com/doc/refman/5.5/en/select.html
Something like this is the idea
SELECT MAX(peg_num) AS indicator
FROM list
WHERE list_id = 1
HAVING indicator <= 1
I can't test it and i never met Mysql so just the idea,
You should use HAVING
No quotes in HAVING condition
This must work:
SELECT MAX(peg_num)
AS indicator
FROM list
WHERE list_id = 1
HAVING indicator >= 1
I completely re-invented my query and it worked. The thing is, I had to use a nested query (and I wanted to not do that as much as possible, my professor had always discouraged it).
Anyway, here it is:
SELECT IF(`key` < 900, `key`, null) `key`
FROM (
(
SELECT MAX( `peg_num` ) AS `key`
FROM `list`
WHERE `list_id` =1
) AS `derivedTable`
)

MySQL INSERT... SELECT column count and virtual/aliased columns

I'm trying to insert using a select statement. However, I need to order the sub-select results using a ranking equation. If I create an alias, it throws off the column count. Can I somehow order my results using an equation?
INSERT INTO draft
( fk_contrib_id , end_time )
SELECT pk_contrib_id, UNIX_TIMESTAMP(), (X+Y+Z) AS ranking
FROM contrib
ORDER BY ranking DESC
LIMIT 1
I need the 'ranking' column for sorting, but if I do, the column count is off for the insert. Do I have to use two queries for this?
You could simply change your query to directly use the expression in the ORDER BY clause, like so:
INSERT INTO draft
( fk_contrib_id , end_time )
SELECT pk_contrib_id, UNIX_TIMESTAMP()
FROM contrib
ORDER BY (X+Y+Z) DESC
LIMIT 1
Remove the expression from the SELECT list. And use the expression in the ORDER BY clause.
ORDER BY X+Y+Z
It's perfectly valid to ORDER BY expressions that are not in the SELECT list.

mysql NULL value in where in CLAUSE

how to deal with NULL value in mysql where in CLAUSE
i try like
SELECT * FROM mytable WHERE field IN(1,2,3,NULL)
it not working
only work like :
SELECT * FROM mytable WHERE field IN(1,2,3) OR field IS NULL
how can i get it work in WHERE IN ? it is possible ?
There is a MySQL function called COALESCE. It returns the first non-NULL value in the list, or NULL if there are no non-NULL values.
If you for example run SELECT COALESCE(NULL, NULL, -1); you will get -1 back because it's the first non-NULL value.
So the trick here is to wrap your expression in COALESCE, and add a value as the last parameter that you also add in your IN function.
SELECT * FROM mytable WHERE COALESCE(field,-1) IN (1,2,3,-1)
It will only match if field is 1,2 or 3, or if field is NULL.
As by my understanding you want to pull every record with 1,2,3 and null value.
I don't think its possible to put null in the IN operator. Its expects values and null is well.. not a value. So You really have to put the OR with the null to get the desired result.
Maybe this information from the MySQL Reference Manual helps:
To comply with the SQL standard, IN returns NULL not only if the expression on the left hand side is NULL, but also if no match is found in the list and one of the expressions in the list is NULL.
Using UNION as a subquery in IN operator can get tableIds as a list and from that can get results with the NULL value.
eg:
SELECT * FROM
mytable
WHERE mytable.id IN(
SELECT mytable.id
FROM mytable
where mytable.field IS NULL
UNION
SELECT mytable.id
FROM mytable
WHERE mytable.field IN(1,2,3)
)
Following statement should help:
SELECT * FROM mytable WHERE COALESCE(field,0) IN (1,2,3,0)