MySQL logic count operation - mysql

I ran three SQL queries in MySQL, but there is a logic problem.
select count(*) from keeper where code!=''; -- result1=2893193
select count(*) from keeper where code=''; -- result2=66
select count(*) from keeper; -- result3=3481069
I expected that result1 + result2 = result3, but in fact, result1 + result2 < result3. Why is this?

Using IS NOT NULL AND IS NULL in addition to ='' will make sure you get all rows that are both just empty like you are looking for already or have the column set as NULL
SELECT count(*) FROM keeper WHERE code!='' OR code IS NOT NULL;
SELECT count(*) FROM keeper WHERE code = '' OR code IS NULL

Three-valued logic attacks!
NULL and "" are two different things. NULL is considered to be neither equal nor not equal to "" and so neither of your queries will ever return it. I'd guess that the extra 500,000 records returned by your third query have code set to NULL. You can test for null fields using IS NULL or IS NOT NULL. If you do:
SELECT count(*) from keeper where code!='';
SELECT count(*) from keeper where code='';
SELECT count(*) from keeper where code IS NULL;
Those three results should add up to the total number of rows in your table.

1. select count(*) from keeper where code!=''
2. select count(*) from keeper where code=''
2.5. select count(*) from keeper where code is null
3. select count(*) from keeper
Note the one inserted before 3. NULL is considered a separate case from any other value, being neither equal to, nor not equal to, any other value (including another NULL).

Always use IS NuLL ans IS NOT NULL to get exact empty and non empty records respectively. it checks both empty and null values.
Try below:
select count(*) from keeper where code is NULL;
AND
select count(*) from keeper where code is NOT NULL
Alternatively you can use :
select count(*) from keeper where LENGTH(COALESCE(code ,'')) = 0
will give you all records with an 'empty' value for code , treating NULL as empty.

Related

MySQL How to find Null data in a table

Scenario: I have a table with duplicate data. One of the columns of this table is ddate, if it is empty/null I want to select that row (and remove it). But for some reason, I cannot find the null rows with a direct query.
Issue: When I run the following query (1):
select
`ddate`,
count(1) as `nb`
from instrument_nt
group by `ddate`;
I get the number of rows where ddate is NULL and where it has other values. But when I run query (2):
select count(*) from instrument_nt where `ddate` = Null;
or
select * from instrument_nt where `ddate` = NULL;
My query result is either 0 or empty.
Question: What is the difference between those two queries (1 and 2)? How can I properly delete the data that has null/missing dates?
NULL mean unknow it's a value.
If you want to get NULL row you need to use IS NULL instead of eqaul NULL
select count(*) from instrument_nt where `ddate` IS Null;
What is the difference between those two queries (1 and 2)? How can I properly delete the data that has null/missing dates?
(1)
select count(*) from instrument_nt where `ddate` IS Null;
you will get the amount ddate is NULL from instrument_nt table.
(2)
select * from instrument_nt where `ddate` IS NULL;
you will get a result set which ddate is NULL;
Every null is defined to be different from every other null. Thus, equality to null is always false. See, for example, here, which describes this so-called "three value problem".
For this third class of value, you want to use IS, as in IS NULL or IS NOT NULL.
use the keyword IS NULL to check the null values in tables
For example:
select * from instrument_nt where `ddate` IS NULL;
MySQL null checks use the IS operator instead of =.
Your query should look like this: select * from instrument_nt whereddateIS NULL;

Mysql Not In (null) doesn't show records

select * from items where id is not null;
This query returns all correct records, but this one :
select * from items where id not in (null);
shows nothing. Can somebody explain why this happens?
null is not value, that is why we use is not null or is null expression.
in your second case
select * from items where id not in (null);
is equal to
select * from items where id != null;
which evaluates nothing because id is neither satisfies = null nor satisfies != null
Your second query will not work because null is not a value, it is undefined, that's why you can't use it with any sql operator. Instead you can re-write your second query like this :
select * from items where coalesce(id, '') not in ('');
But this will also exclude the result for id = '' So use of the first query is the best solution in this case which is :
select * from items where id is not null;
Get more information about NULL in mysql from Here

MySQL Alias and Field have same name - Which is evaluated in Having clause?

I have a mysql query that is joining phone numbers from multiple tables that I can not edit and I need to create an output with the same field name as one of the tables. I'm using a CASE statement to do this. Here is a simple version of my query:
SELECT t1.`id` as id,
CASE
WHEN t1.`has_company_phone` = 1 THEN t1.`company_phone`
ELSE t2.`phone`
END AS `phone`
FROM `input_table1` t1,
LEFT OUTER JOIN `input_table2` t2
ON (t2.`id` = t1.`matched_company_id`)
HAVING phone IS NOT NULL;
EDIT:
In this query, in the HAVING clause is t2.phone being evaluated, the alias phone, or both? My goal is to have the alias evaluated in this having clause.
EG: t1.company_phone exists, but t2.phone IS NULL. I want to include this record using the t1.company_phone and have the alias name be phone. If I change the HAVING to a WHERE clause, this record will not show up.
In MySQL, HAVING clause will always search the needed item from the select list.
Once found in the select list, the found item will be used.
If Not found, error is thrown.
Update:
Actually, in ur SQL, you should replace HAVING with WHERE, since it is the same as WHERE.
Using WHERE, the confusion will be gone. WHERE clause will always use real table column, not the alias.
replace you having by the following one:
group by t1.`has_company_phone`, t2.`phone`
HAVING CASE
WHEN t1.`has_company_phone` = 1 THEN t1.`company_phone`
ELSE t2.`phone`
END is not null
and be careful to not miss the group by.
or, you can use the condition in the where without group by.
where CASE
WHEN t1.`has_company_phone` = 1 THEN t1.`company_phone`
ELSE t2.`phone`
END is not null
In this case, I took Shadow's advice and constructed a test to see what would happen. I filled t2 with a NULL phone and put a phone in t1.
The alias is evaluated because the record from t1 was included in my results.
I then reversed the values so t1.company_phone was NULL and t2.phone had a value, and reran query. The t2.phone field name was not evaluated as no results showed up after reversing the data.
Boody's advice is probably a more explicit way of getting the functionality desired, but in my case I have about 20fields that will be merged over multiple cases and 4 tables, so the query would get really messy being that explicit.
with union, you will simply do the following:
select distinct id, case when phone1 = '' then phone2 else phone1 end as phone from
(select matched_company_id as id, company_phone as phone1, '' as phone2 from `input_table1`
union
select id as id, '' as phone1, phone as phone2 from `input_table2`) as t
where phone <> ''
then you can add any other table or field similarly.

Why don't counts using 'LIKE' in SQL match?

I have one table ABC with EMPLID, GRADE, SALARY and DATE as its fields.
I am executing the following 3 statements:
select count(*) from ABC;
Result :- 458
select count(*) from ABC where GRADE LIKE '%def%';
Result :- 0
select count(*) from ABC where GRADE NOT LIKE '%def%';
Result :- 428
My point here is: the result of second query plus the result of third query should be equal to the result of first query, shouldn't it?
Looks like you have 30 records where the GRADE is null.
null values are unknown, so do not match either condition.
Sql uses a three-valued logic: true, false &unknown. If you compare a NULL to any other value the result is unknown. NOT(unknown) is still unknown.
A WHERE clause only returns rows that evaluate to true. So the missing 30 rows in your example have a NULL in the Grade column.
Note that apart from the obvious case where you can have NULL values in your table (as others have mentioned), you could also have empty strings.
In Oracle:
-- Returns nothing
select 1 from dual where '' like '%'
In MySQL:
-- Returns 1
select 1 from dual where '' like '%'
Since you tagged your question with both oracle and mysql, you might be running into an incompatibility here, as in oracle '' IS NULL holds true!

mySQL/SQlite subtractive query

I need a query in which it starts off by selecting the entire table, then there would be a few more querys that would remove entries from the first query. Ive accomplished this by using several querys and then comparing the results in my application. I was wondering if I can accomplish this in a single query.
Algorithm
Select All AccountIDs from table
Select AccountIDs from table where parameter1 = true
Remove those matches from the original query result
Select AccountIDs from table where parameter2 = true
Remove those matches from the remaining query result
and so on up to N parameters.
This would need to also be compatible with both mySQL and SQLite
I think you are looking for this:
SELECT AccountID FROM the_table
LEFT JOIN (
SELECT AccountID FROM the_table
WHERE
parameter1 = true OR
... OR
parameterN = true ;
) AS not_included USING (AccountID)
WHERE not_included.AccountID IS NULL -- only items with no match in the "not_included" sub-query
The not_included subquery returns all items for which any parameter is set to TRUE. You actually want to exclude these records from your final result set.
Then LEFT-JOIN the_table (i.e. all items) to this sub-result. The WHERE...IS NULL clause excludes items present in the_table but not present in not_included.
Therefore only items which you do not want to exclude remain in the final result set.
The most direct way to implement your algorithm is to use a compound SELECT statement:
SELECT AccountID FROM MyTable
EXCEPT
SELECT AccountID FROM MyTable WHERE parameter1 = 1
EXCEPT
SELECT AccountID FROM MyTable WHERE parameter2 = 1
However, this is also possible with a single WHERE expression:
SELECT AccountID
FROM MyTable
WHERE NOT (parameter1 = 1 OR
parameter2 = 1 OR
...)