SELECT * FROM WHERE does not find all records - mysql

When I type:
select * from 'saleslog' where 'Status' = 'Pending';
or
select * from 'saleslog' where 'Status' = "Pending";
or
select * from saleslog where Status = 'Pending';
despite the fact that there are hundreds of rows with "Pending" value in Status column I get only 3 records displayed. The same happens when I look for value other than "Pending".
If however, I type:
select * from saleslog where status like "%Pending%";
then most if not all records are displayed. There are absolutely no spaces or any other characters in front and behind Pending value.
I am wondering if table "saleslog" needs to be repaired and if so, how? I'm kind of new to SQL.

It's possible there are hidden characters in the field that you just can't see such as tab, carriage return or line feed. Have you tried doing an update on the field to try and correct it? Maybe try running the update query below and then run your SELECT query again:
UPDATE saleslog SET status = 'Pending' WHERE status LIKE '%Pending%'

Try the following:
UPDATE `saleslog` SET `status` = TRIM(`status`);
SELECT * FROM `saleslog` WHERE `status` = 'Pending';

Related

Select records that don't exist in another DB table

I'm trying to tackle what I thought was a simple query.
I have two databases each with one table in the DB.
What I would like to do is find all of the emails from DB1.Table that don't exist in DB2.Table
I'm using this query, but the result is incorrect because I know DB1.Table contains emails that don't exist in DB2.Table (result always comes back as 0)
SELECT DB1.20180320.email
FROM DB1.20180320
WHERE DB1.20180319.email NOT IN
(SELECT DB2.20180319.email FROM DB2.20180319 WHERE Status = 'active')
Any ideas on what I'm doing wrong here? I'm working with about 80k rows in each table.
Thanks.
without seeing your data, try something like this.
SELECT DB1.20180320.email
FROM DB1.20180320
left join DB2.20180319 on DB1.20180320.email = DB2.20180319.email
AND DB2.20180319.Status = 'active'
WHERE DB2.20180319.email IS null;
This should show all the emails in DB1.20180320 that don't exist in DB2.20180319
NOT EXISTS query should do it. It returns email that exist in DB1, but not DB2.
SELECT DB1.20180320.email
FROM DB1.20180320
WHERE NOT EXISTS(
SELECT 1
FROM DB2.20180319
WHERE DB1.20180320.email = DB2.20180319.email
AND DB2.20180319.Status = 'active'
)

MySQL query to get fields from a table where the ID exists in another query

This must be fairly straight forward, as I tend to use ORMs I don't have to get my hands dirty often and am therefore struggling!
I have a database and want to get several fields from a table, that bit is easy..
SELECT main_table.registration_number, main_table.registered_name FROM main_table;
I want to filter the results based on another table, which is also easy..
SELECT second_table.registration_number FROM second_table WHERE this_field = '' AND that_field = '0';
Now the problem is I want to run the first query based on the second queries result set, I was thinking something like this:
SELECT main_table.registration_number, main_table.registered_name FROM main_table WHERE main_table.registration_number IN (SELECT * FROM second_table WHERE this_field = '' AND that_field = '0');
This gives me: Error Code: 1241. Operand should contain 1 column(s)
Am I handling this completely wrong?
Your subquery should do something like below,
(select * from table) in subquery is not what you really need to do your
so the subquery should return one column
(SELECT registration_number FROM second_table WHERE this_field = '' AND that_field = '0');
You cannot have multiple columns being returned in a subquery like
that, doing so it will result in such error
You have to select a column
SELECT main_table.registration_number, main_table.registered_name FROM
main_table WHERE main_table.registration_number IN (SELECT
registration_number FROM second_table WHERE this_field = '' AND
that_field = '0');

MySQL- Select and Update at the same time

I have this query
SELECT * FROM outbox where Status=0 ;
then I need to update the selected records so Status should be equal 1
i.e (UPDATE outbox(selected records from SELECT query) SET Status =1 )
any help ?
This is a much harder problem than it sounds. Yes, in the simplistic case where you are only thinking of one user and a few records, it seems easy. But, databases are designed to be ACID-compliant, with multiple users and multiple concurrent transactions that can all be affecting the data at the same time. And there is no single statement in MySQL that does what you want (other databases support an OUTPUT clause, RETURNING or something similar).
One structure that will work in MySQL is to place the items in a temporary table, then do the update, then return them. The following shows the semantics using transactions:
start transaction;
create temporary table TempOutboxStatus0 as
select *
from outbox
where status = 0;
update outbox o
set status = 1
where status = 0;
select *
from TempOutboxStatus0;
commit;
For the update, I actually prefer:
where exists (select 1 from TempOutboxStatus0 t where t.outboxid = o.outboxid);
because its intention is clearer -- and the code is safer in case the conditions subtly change.
Note: you may want to use explicit table locks. Such considerations depend on the storage engine you are using.
BEGIN
Start transaction;
SELECT *
FROM
outbox
where
Status = 0 and
Is_Expired = 0 and
Service_ID=p_service_id
order by
Next_Try_Date asc FOR Update;
update outbox
set
Status=1
where
Status = 0 and
Is_Expired = 0 and
Service_ID=p_service_id;
commit;
END
is this possible .. it seems it works with me
You can do something like that, the outbox is your table:
update outbox set Status = 1 where Status = 0
you can do it like below
$sql=mysql_query("SELECT * FROM outbox where `Status`=0");
while($result=mysql_fetch_array($sql))
{
$update="UPDATE `outbox` SET `Status` =1 where
'your column name'='your previous fetched value');
}

MySQL - tell if column _all_ has same value

I'm trying to write a query like
if (select count(*) from Users where fkId=5000 and status='r') =
(select count(*) from Users where fkId=5000) then ..
in just one query.
What this means is, if all the rows that have fkId=5000 also have status=r, then do something.
There can be any number of rows with fkId=5000, and any fraction of those rows could have status=r, status=k, status=l, status=a etc. I'm interested in the case where ALL the rows that have fkId=5000 also have status=r (and not any other status).
The way I'm doing it now is
how many rows with id=5000 and status = 'r'?
how many rows with id=5000?
are those numbers equal? then ..
I'm trying to figure out how to rewrite this query using only 1 query, instead of 2. Keyword ALL didn't seem to be able to write such a query (<> ALL is equivalent to NOT IN). I tried a couple of GROUP BY formulations but could not get the correct result to appear.
The most efficient way to do this is:
if not exists (select 1
from users
where fkid = 5000 and (status <> 'r' or status is null)
)
This will stop the query at the first non-matching row.
I suggest you to check for any rows with status not equal to 'r'
SELECT count(*)>0 FROM Users WHERE fkId = 5000 AND status != 'r'
In the following case, if the number 1 is "true" (which it is) then you'll get Yes back, and if not you'll get No back:
SELECT IF(1, 'Yes', 'No') AS yesorno
(Go ahead -- try it!)
In your case however, the following would be more appropriate:
SELECT IF (
(SELECT COUNT(*) FROM Users WHERE fkId=5000 AND status IN('r') AND status NOT IN('1', 'a', 'k')) = (SELECT COUNT(*) FROM Users WHERE fkId=5000),
'They are equal.',
'They are not equal.'
)
AS are_they_equal
By adding AS, you can manipulate the name of the "column" that's returned to you.
Hope that helps... Also, see this page if you'd like more info.
:)
EASY!
Simply join back to the same table. Here is the complete code for testing:
CREATE TABLE Users(id int NOT NULL AUTO_INCREMENT, fkID int NOT NULL, status char(1), PRIMARY KEY (id));
INSERT Users (fkID, status) VALUES (5000, 'r');
INSERT Users (fkID, status) VALUES (5000, 'r');
INSERT Users (fkID, status) VALUES (5000, 'r');
-- The next query produces "0" to indicate no miss-matches
SELECT COUNT(*) FROM Users u1 LEFT JOIN Users u2 ON u1.id=u2.id AND u2.status='r' WHERE u1.fkID=5000 AND u2.id IS NULL;
-- now change one record to create a miss-match
UPDATE Users SET status='l' WHERE id=3 ;
-- The next query produces "1" to indicate 1 miss-match
SELECT COUNT(*) FROM Users u1 LEFT JOIN Users u2 ON u1.id=u2.id AND u2.status='r' WHERE u1.fkID=5000 AND u2.id IS NULL;
DROP TABLE Users;
So all you need to test for in the result is that it's 0 (zero) meaning everything has fkID=5000 also has status='r'
If you properly index your table then joining back to the same table is not an issue and certainly beats having to do a 2nd query.
Besides the NOT EXISTS version - which should be the most efficient as it does no counting at all and exits as soon as it finds a value that doesn't match the conditions, there is one more way, that will work if status is not nullable and will be efficient if there is an index on (fkId, status):
IF EXISTS
( SELECT 1
FROM Users
WHERE fkId = 5000
HAVING MIN(status) = 'r'
AND MAX(status) = 'r'
)
There is one difference though. The above will show false if there are no rows at all with fkId=5000, while the NOT EXISTS version will show true - which is probably what you want anyway.

Update with SELECT and group without GROUP BY

I have a table like this (MySQL 5.0.x, MyISAM):
response{id, title, status, ...} (status: 1 new, 3 multi)
I would like to update the status from new (status=1) to multi (status=3) of all the responses if at least 20 have the same title.
I have this one, but it does not work :
UPDATE response SET status = 3 WHERE status = 1 AND title IN (
SELECT title FROM (
SELECT DISTINCT(r.title) FROM response r WHERE EXISTS (
SELECT 1 FROM response spam WHERE spam.title = r.title LIMIT 20, 1)
)
as u)
Please note:
I do the nested select to avoid the famous You can't specify target table 'response' for update in FROM clause
I cannot use GROUP BY for performance reasons. The query cost with a solution using LIMIT is way better (but it is less readable).
EDIT:
It is possible to do SELECT FROM an UPDATE target in MySQL. See solution here
The issue is on the data selected which is totaly wrong.
The only solution I found which works is with a GROUP BY:
UPDATE response SET status = 3
WHERE status = 1 AND title IN (SELECT title
FROM (SELECT title
FROM response
GROUP BY title
HAVING COUNT(1) >= 20)
as derived_response)
Thanks for your help! :)
MySQL doesn't like it when you try to UPDATE and SELECT from the same table in one query. It has to do with locking priorities, etc.
Here's how I would solve this problem:
SELECT CONCAT('UPDATE response SET status = 3 ',
'WHERE status = 1 AND title = ', QUOTE(title), ';') AS sql
FROM response
GROUP BY title
HAVING COUNT(*) >= 20;
This query produces a series of UPDATE statements, with the quoted titles that deserve to be updated embedded. Capture the result and run it as an SQL script.
I understand that GROUP BY in MySQL often incurs a temporary table, and this can be costly. But is that a deal-breaker? How frequently do you need to run this query? Besides, any other solutions are likely to require a temporary table too.
I can think of one way to solve this problem without using GROUP BY:
CREATE TEMPORARY TABLE titlecount (c INTEGER, title VARCHAR(100) PRIMARY KEY);
INSERT INTO titlecount (c, title)
SELECT 1, title FROM response
ON DUPLICATE KEY UPDATE c = c+1;
UPDATE response JOIN titlecount USING (title)
SET response.status = 3
WHERE response.status = 1 AND titlecount.c >= 20;
But this also uses a temporary table, which is why you try to avoid using GROUP BY in the first place.
I would write something straightforward like below
UPDATE `response`, (
SELECT title, count(title) as count from `response`
WHERE status = 1
GROUP BY title
) AS tmp
SET response.status = 3
WHERE status = 1 AND response.title = tmp.title AND count >= 20;
Is using GROUP BY really that slow ? The solution you tried to implement looks like requesting again and again on the same table and should be way slower than using GROUP BY if it worked.
This is a funny peculiarity with MySQL - I can't think of a way to do it in a single statement (GROUP BY or no GROUP BY).
You could select the appropriate response rows into a temporary table first then do the update by selecting from that temp table.
you'll have to use a temporary table:
create temporary table r_update (title varchar(10));
insert r_update
select title
from response
group
by title
having count(*) < 20;
update response r
left outer
join r_update ru
on ru.title = r.title
set status = case when ru.title is null then 3 else 1;