NOT LIKE on mysql query - mysql

I have a big problem understanding why a query works when using LIKE in query and not working when using NOT LIKE.
I will post query below:
select DISTINCT (mails), name
from disposable
JOIN (
SELECT DISTINCT (mail) as mails,
CONCAT(toys.firstname, ' ' , toys.lastname) as name
FROM toys2
join toys ON toys.userid = toys2.id
where ( (toyid = '27' or toyid = '29')
and status != 'Sold'
and toys.regdate >= '2017-01-01'
)
) as tab
WHERE tab.mails LIKE CONCAT('%#', disposable.email)

I think what you want is something more like the following. Note that I simplified the schema a bit so as to do a bit less work for the SQL Fiddle.
SELECT c.email, c.name
FROM customer c LEFT JOIN disposable d
ON SUBSTR(c.email, INSTR(c.email, '#')+1, LENGTH(c.email)-INSTR(c.email, '#')) = d.email
WHERE d.email IS NULL;
Basically, here you're getting the domain of the customer and matching it to the entry in the disposable table. The final WHERE clause uses IS NULL to determine the customer email addresses that are not disposable - use IS NOT NULL to find the ones that are.
Hope this helps.

Related

select last record in sub query

have read all similar qs but cant apply to my sql
Would like to select all customers AND the last action record inserted.
The sql below first selects the max actionid then uses that on another sub query - this takes 5+secs to run ;(
Please advise TQ
SELECT cus.cusid,cus.FirstName,cus.Surname,
lastact.actionid, lastact.actiondate, lastact.siteid
FROM cus
LEFT JOIN(
SELECT MAX(actionid) AS maxactionid, cusid
FROM `action`
INNER JOIN `event` ON event.eventid = action.`eventid`
GROUP BY cusid
) AS maxactionid ON maxactionid.cusid = cus.cusid
LEFT JOIN (
SELECT
action.actionid,
action.actiondate,
event.cusid,
event.siteid
FROM
`action`
INNER JOIN `event`
ON event.eventid = action.eventid
ORDER BY actionid DESC
) AS lastact ON lastact.actionid = maxactionid
WHERE UCASE(CONCAT(firstname, surname)) LIKE '%JIM%HEMM%'
TQ for ideas - please see following:
1) the limit idea, provides null results for lastact.actionid, lastact.actiondate, lastact.siteid - but does run in 0.075 secs!
Such a shame this idea fails
SELECT cus.cusid,cus.FirstName,cus.Surname, lastact.actionid, lastact.actiondate, lastact.siteid
FROM cus
LEFT JOIN (SELECT action.actionid, action.actiondate, event.cusid, event.siteid
FROM action
INNER JOIN event ON event.eventid = action.eventid
ORDER BY actionid DESC LIMIT 1
) AS lastact ON lastact.cusid = cus.cusid
WHERE UCASE(CONCAT(firstname, surname)) LIKE '%JIM%HEMM%'
2) EXPLAIN results of original query are:
3) Adding LIKE 'JIM%' AND cus.surname LIKE 'HEMM%' doesn't affect query time much but will include as per suggestion
Hi - have got great result by using ideas from everyone - Thank you
1) Changed WHERE to cus.FirstName LIKE 'JIM%' AND cus.surname LIKE 'H%'
2) Added index on firstname, surname
3) Added cusid in action table (don't need event table anymore)
4) Moved lookup tables (not in orig question) outside of action sub query
Finished sql looks like (runs in 0.063 secs - tested with a surname of only one letter!)
SELECT cus.cusid,cus.FirstName,cus.Surname, lastact.actionid, lastact.actiondate, lastact.siteid, actiontype.action,
FROM cus
LEFT JOIN (
SELECT action.actionid, action.actiondate, event.cusid, event.siteid
FROM action
ORDER BY actionid DESC
) AS lastact ON lastact.cusid = cus.cusid
LEFT JOIN actiontype ON actiontype.actiontypeid = lastact.typeid
WHERE cus.FirstName LIKE 'JIM%' AND cus.surname LIKE 'H%'
GROUP BY lastact.cusid
As JC Sama said "change select MAX(actionid) by select actionid and adding a limit 1 and order by desc", helps indexed
searchs.
As David K-J said "run an EXPLAIN first to see what the planner is trying to do. I would suspect it's the (non-indexable) search on concatenation strings".
You shouldn't put jokers '%' at the begining of a string when comparing, that disables indexed search.
You shouldn't use functions when comparing (at least, avoid them if you can), also for the indexed search.
Now that you can use indexes, add them if you haven't done it yet.
I may be wrong here, but I don't see the point of the last LEFT JOIN, as far as I'm concerned. You could withdraw that data from the first LEFT JOIN. Neither why are you grouping by cusid.
With all, the sql I made is (obviously not tested, you may have to fix some thing):
SELECT cus.cusid,cus.FirstName,cus.Surname,
maxaction.actionid, maxaction.actiondate, maxaction.siteid
FROM cus
LEFT JOIN(
SELECT actionid AS maxaction, action.actiondate, event.cusid, event.siteid
FROM `action`
INNER JOIN `event` ON event.eventid = action.eventid
order by actionid desc limit 1
) AS maxaction ON maxaction.cusid = cus.cusid
WHERE cus.FirstName like 'JIM%' and cus.surname like 'HEMM%'

Using data from 5 different tables on a mysql query

I need some help on doing multiple Joins, im not very good at this and need a way to get it to work.
There are 5 tables with data and need to get data to output from each table. There is a person, visit, center, date and seenby table. The visit table has ID's to fetch data from other tables. I want to use this table to get the status of the person, to see what date they visited, at what center, their name, and who they were seen by. (i hope this makes sense).
The output should look hopefully like this:
> Person FirstName
> Person LastName
> Seen By
> Date
> Center
> Status
EDIT// Here is a mockup of what i want to see
Ive already read up on pivot tables and would prefer not to use that. Ive created a SQL fiddle here:
http://www.sqlfiddle.com/#!2/d19d2c
EDIT//
Ive managed to write half a query but i doubt it works but i guess its a starting point.
SELECT d.date
, p.Firstname
, p.Lastname
, c.centername
, v.status
, s.FirstName
, s.LastName
FROM visit v
LEFT
JOIN date d
ON v.dateID = d.id
LEFT
JOIN centerName c
ON c.centerID = c.id
Thanks!
From your table structure it would seem you want a query like this:
SELECT
d.date,
CONCAT_WS(' ', p.Firstname ,p.Lastname) AS "Person",
v.status,
CONCAT_WS(' ', s.FirstName, s.LastName) AS "Seenby",
c.centername
FROM visit v
JOIN person p ON v.PersonID = p.ID
JOIN seenby s ON v.seenbyID = s.ID
LEFT JOIN date d ON v.dateID = d.id
LEFT JOIN center c ON v.centerID = c.id
The last two joins should maybe be normal inner joins and not left joins, adjust as appropriate.
TheCONCAT_WS()function concatenates its parameters into a string, using the value of the first parameter as separator (a space in this case).
Sample SQL Fiddle

IF... ELSE statement in mySQL

Can anyone help me to fix the error? I'm still new with mySQL. The error is at if else statement.
select idpersonal,fname,lname,city from fathi.personal where city='QS';
if (fname=A%) then
begin
select idorder,order_no,item_total from fathi.order;
else
update fathi.order
set item_total=0
where personal.idpersonal=order.idpersonal;
IF is not a valid SQL statement in MySQL.
There's three separate statements here, a SELECT from personal, a SELECT from order (which returns all rows from the table), and an UPDATE statement that has a predicate that references a column from an unknown rowsource.
Here are some examples of SQL based on what was posted in the question.
1) return all rows from personal with city='Q5'
SELECT p.idpersonal
, p.fname
, p.lname
, p.city
FROM fathi.personal p
WHERE p.city='QS';
2) return all rows from order that are related to personal with city='Q5' and fname starting with 'A'. (This only returns rows from personal that are related to an order.)
SELECT o.idorder
, o.order_no
, o.item_total
, p.idpersonal
, p.fname
, p.lname
, p.city
FROM fathi.order o
JOIN fathi.personal p
ON p.idpersonal = o.idpersonal
AND p.city = 'Q5'
AND p.fname LIKE 'A%' ;
3) Modify the contents of table "order", to set the item_total to zero, for all rows that are related to personal with city=`Q5' and have fname not starting with 'A'
UPDATE order o
JOIN personal p
ON p.idpersonal = o.idpersonal
AND p.city = 'Q5'
AND (p.fname IS NULL OR p.fname NOT LIKE 'A%') ;
SET o.item_total=0
Those are just examples. We're just guessing at what you are trying to achieve.

return results of same ID from 2 tables

I'm using an opensource database, so it's setup is a bit over my head.
Its basically like this.
A persons normal information is in the table 'person_per'
There is custom information in the table 'person_custom'
both use 'per_ID' to organize.
select per_ID from person_custom where c3 like '2';
gives my the IDs of people who fit my search, I want to "join" (I think) their name, phone, ect from the 'person_per' table using the ID as the "key"(terms I read that seem to fit).
How can I do that in a single query?
select per.*
from person_per per
inner join person_custom cus on cus.per_id = per.per_id
where cus.c3 = 2
You can retrieve all the columns from both tables with a single query:
SELECT p.name
, p.phone
, p.ect
, c.custom_col
FROM person_per p
JOIN person_custom c
ON c.per_ID = p.per_ID
WHERE c.c3 LIKE '2'
Use a JOIN operator between the table names, and include the "matching" criteria (predicate) in the ON clause.

SELECT CASE WHEN THEN (SELECT)

I am trying to select a different set of results for a product depending on a product type.
So if my product should be a book I want it to look up the UPC and Artist for a normal product these details are however irrelevant and for another product I would want a completely different set of results.
SELECT CASE Product.type_id
WHEN 10 THEN (
SELECT
Product.product_id,
Product.type_id,
Product.product_name,
Product.UPC,
Product_Type.type,
CONCAT_WS(' ' , first_name, middle_name, last_name ) AS artistC
FROM Product, Product_Type, Product_ArtistAuthor
WHERE Product.type_id = Product_Type.type_id
AND Product.product_id = $pid
AND Product.artist_id = Product_ArtistAuthor.artist_id
)
ELSE (
SELECT
Product.product_id,
Product.type_id,
Product.product_name,
Product_Type.type
FROM Product, Product_Type
WHERE Product.type_id = Product_Type.type_id
AND Product.product_id = $pid
)
END
FROM Product
WHERE Product.product_id = $pid
I am not sure where I am going wrong
You Could try the other format for the case statement
CASE WHEN Product.type_id = 10
THEN
(
Select Statement
)
ELSE
(
Other select statement
)
END
FROM Product
WHERE Product.product_id = $pid
See http://msdn.microsoft.com/en-us/library/ms181765.aspx for more information.
You should avoid using nested selects and I would go as far to say you should never use them in the actual select part of your statement. You will be running that select for each row that is returned. This is a really expensive operation. Rather use joins. It is much more readable and the performance is much better.
In your case the query below should help. Note the cases statement is still there, but now it is a simple compare operation.
select
p.product_id,
p.type_id,
p.product_name,
p.type,
case p.type_id when 10 then (CONCAT_WS(' ' , first_name, middle_name, last_name )) else (null) end artistC
from
Product p
inner join Product_Type pt on
pt.type_id = p.type_id
left join Product_ArtistAuthor paa on
paa.artist_id = p.artist_id
where
p.product_id = $pid
I used a left join since I don't know the business logic.
For a start the first select has 6 columns and the second has 4 columns. Perhaps make both have the same number of columns (adding nulls?).
I ended up leaving the common properties from the SELECT queries and making a second SELECT query later on in the page. I used a php IF command to call for different scripts depending on the first SELECT query, the scripts contained the second SELECT query.