Difference between "and not ()" and "and (... not like ...)"? - mysql

I receive completely different results from my query depending on where I put NOT. Can you please explain the difference?
Below is the first way:
SELECT COUNT(*)
FROM [table]
WHERE condition = 'N'
AND (Category NOT LIKE '%str1%'
OR Category NOT LIKE '%str2%'
OR Category NOT LIKE '%str3%')
The second way:
SELECT COUNT(*)
FROM [table]
WHERE condition = 'N'
AND NOT (Category LIKE '%str1%'
OR Category LIKE '%str2%'
OR Category LIKE '%str3%')
Both seem the same for me.

You need to change the operators within the parentheses to AND, if you add NOT, which will impact adversly all the terms within parentheses, such as
SELECT count(*)
FROM[table]
WHERE condition = 'N'
AND NOT (Category LIKE '%str1%'
AND Category LIKE '%str2%'
AND Category LIKE '%str3%')
A OR B equals NOT ( A AND B ) in Boolean logic

I just want to note that you can simplify this logic:
WHERE condition = 'N' AND
Category NOT REGEXP 'str1|str2|str3'
This eliminates issues with parentheses and the placement of the NOT.

Related

Using Case in WHERE condition MYSQL

Is it possible to use CASE statement in WHERE condition like below?
SELECT act.id_activity FROM activity act
LEFT JOIN work w ON w.id_work = act.id_work
WHERE
w.work_type=1
AND w.work_tender in (1,2)
AND act.id_activity_type IN
(CASE WHEN w.work_tender=1 THEN '2,3' WHEN w.work_tender=2 THEN '2,3,4,9' END)
it returns no error but the results always display act.id_activity_type = 2 instead of 2,3 or 2,3,4,9
In this case 1 work (table work) can have many activities (table activity). i want to display activities based on work.work_tender type. if work.work_tender=1 then need to choose activity.id_activity_type IN (2,3). if work.work_tender=2 then need to choose activity.id_activity_type IN (2,3,4,9)
You can try to write correct logic by OR & AND.
SELECT act.id_activity FROM activity act
LEFT JOIN work w ON w.id_work = act.id_work
WHERE
w.work_type=1
AND (
(act.id_activity_type IN ('2','3') AND w.work_tender=1) OR
(act.id_activity_type IN ('2','3','4','9') AND w.work_tender=2)
)
I think case is used for that case. I think it is possible to use in that case. And also for orderby phrase.
Maybe you can try with this:
SELECT *
FROM activity a
JOIN work w
ON w.work_tender=
CASE WHEN a.id_activity_type IN (2,3) THEN 1
WHEN a.id_activity_type IN (2,3,4,9) THEN 2 END;
I'm using CASE expression here to assign value matching w.work_tender if the a.id_activity_type fit the condition. So, if a.id_activity_type IN (2,3) THEN 1 will match with w.work_tender=1 similarly with a.id_activity_type IN (2,3,4,9) THEN 2 will match with w.work_tender=2.
Demo fiddle

Double AND Where Clause with between Dates

I currently have a query like this
WHERE Category = 'Freezing' OR Category ='Ooredoo FTTH fault'OR Category ='Ooredoo TT fault ' OR Category ='No Picture'
but i want use this date search query with the above code,
im able to use any 1 of this code but im unable to use both query, i have used "AND" or "OR" But its Not working,
ScheduleDate BETWEEN '".$_POST["from_date"]."' AND '".$_POST["to_date"]."' ```
a or b or c and d is ambiguous. You need to use parenthesis to make it explicit how to group the ands and ors. If you want category to match ANY of the options AND the schedule is between certain dates. (a or b or c) and d.
where (
Category = 'Freezing' or
Category = 'Ooredoo FTTH fault' or
Category = 'Ooredoo TT fault ' or
Category = 'No Picture'
)
and ScheduleDate BETWEEN ? AND ?
(Note: Do not use string concatenation to put values into queries, especially not straight from user input. It's a security hole and can cause errors. Use bind parameters.)
(Note: You have an extra space in one of your options.)
You can also use in to make the query simpler.
where
Category in (
'Freezing', 'Ooredoo FTTH fault', 'Ooredoo TT fault', 'No Picture'
)
and ScheduleDate BETWEEN ? AND ?

mysql query to count how many times the like operator matches every column

$sql ="SELECT *
FROM members m
INNER JOIN author_details a
on m.email= a.email
where m.name like '".$search_text."%'
or a.username like '".$search_text."%'
or a.address_line1 like '%".$search_text."%'
or a.address_line2 like '%".$search_text."%'
or a.city like '%".$search_text."%'
or m.phone = ".(int)$search_text."
so what i am looking for is count which column has highest matches and then return that result set first for example if the keyword is found most matches in address column then result set should contain the address matched results first right now the results are displayed for name first even if they are very few.
i am kind of less known to sql so please try to keep it simple
A comparison operator returns 1 when it matches, so you can use SUM() to add them up.
$sql ="SELECT
SUM(m.name like '".$search_text."%') AS name_matches,
SUM(a.username like '".$search_text."%') AS username_matches,
SUM(a.address_line1 like '%".$search_text."%') AS addr1_matches,
SUM(a.address_line2 like '%".$search_text."%') AS addr2_matches,
SUM(a.city like '%".$search_text."%') AS city_matches,
SUM(m.phone = ".(int)$search_text.") AS phone_matches
FROM members m
INNER JOIN author_details a
on m.email= a.email";
Each of the _matches columns will contain the number of rows where the search text matches in that column.

How to sort by name in alphabets using mysql query

MY albums are sorted by id , now i would like to show only album only B alphabet.
My old query
$valueql_select="SELECT DISTINCT (i.gallery_album_id) FROM mov_gallery_album AS a, mov_gallery_images AS i WHERE a.gallery_album_id = i.gallery_album_id AND a.gallery_cat_id =".$_GET['cat']." ORDER BY gallery_id desc";
I tried by using LIKE
$valueql_select="SELECT DISTINCT (i.gallery_album_id) FROM mov_gallery_album AS a, mov_gallery_images AS i WHERE a.gallery_album_id = i.gallery_album_id AND a.gallery_cat_id =".$_GET['cat']." ORDER BY name LIKE 'b%'";
But the above query doesn't work .
Put the condition in the WHERE clause:
$valueql_select="SELECT DISTINCT i.gallery_album_id
FROM mov_gallery_album AS a
JOIN mov_gallery_images AS i
ON a.gallery_album_id = i.gallery_album_id
WHERE a.gallery_cat_id = '42'
AND name LIKE 'b%'
ORDER BY name";
Also you have an SQL injection vulnerability. Do not concatenate values into your SQL string. Especially when they are directly from user input without any validation.
Related
How can I prevent SQL injection in PHP?
If you need to sort these names which start with B first try this:
ORDER BY
CASE WHEN name name LIKE 'b%' THEN 0 ELSE 1 END, name ;
And if you want to get these names that start with B's you have to move the LIKE predicate to the WHERE clause like so:
WHERE a.gallery_album_id = i.gallery_album_id
AND a.gallery_cat_id =".$_GET['cat']."
AND name LIKE 'b%'
ORDER BY name

Tricky SQL including outer join and case

I use data from http://geonames.org. The table structure is as follows:
GN_Name 1 - 0:N GN_AlternateName
They are linked on:
(PK)GN_Name.GeoNameId == (FK)GN_AlternateName.GeoNameId
GN_Name is the main table containing all place names.
GN_AlternateName contains names in other languages if any.
EX:
GN_Name.Name - Stockholm
GN_AlternateName.AlternateName - Estocolmo (if IsoLanguage=="es")
Rules:
I want to use GN_AlternateName.AlternateName if it exists for the specified language and if it starts with the search string.
If not, i want to use GN_Name.Name if it starts with the search string.
I want GeoNameId to be unique.
Basically I could outer join in first record only, but that seemed to decrease performance.
I've got the following SQL (basically modified SQL from a LINQ query). The problem is that it only finds 'Estocolmo' if search string starts with "stock". "estoc" yields nothing.
select
distinct(n.GeoNameId) as Id,
an.IsoLanguage,
CASE WHEN (an.AlternateName like N'estoc%')
THEN an.AlternateName
ELSE n.Name
END AS [The name we are going to use]
from GN_Name as n
LEFT OUTER JOIN GN_AlternateName as an
ON n.GeoNameId = an.GeoNameId
AND 'es' = an.IsoLanguage
WHERE n.Name like N'estoc%'
UPDATE
Thanks Rahul and Lee D.
I now have the following:
select
distinct(n.GeoNameId) as Id,
an.IsoLanguage,
CASE WHEN (an.AlternateName like N'estoc%')
THEN an.AlternateName
ELSE n.Name
END AS [The final name]
from GN_Name as n
LEFT OUTER JOIN GN_AlternateName as an
ON n.GeoNameId = an.GeoNameId
AND 'es' = an.IsoLanguage
WHERE (n.Name LIKE N'estoc%' OR an.AlternateName LIKE N'estoc%')
This performs LIKE twice on an.AlternateName. Is there any way i could get rid of on LIKE clause?
UPDATE 2
Andriy M made a nice alternative query using COALESCE. I changed it a little bit and ended up with the following:
SELECT Id, LocalisedName
FROM (
SELECT
n.GeoNameId AS Id,
an.IsoLanguage,
COALESCE(an.AlternateName, n.Name) AS LocalisedName
FROM n
LEFT JOIN GN_AlternateName AS an ON n.GeoNameId = an.GeoNameId
AND IsoLanguage = 'es'
) x
WHERE LocalisedName LIKE 'estoc%'
This query does exactly what i am looking for. Thanks!
Here's a probable solution of the problem, which uses a slightly different apporach:
SELECT Id, LocalisedName
FROM (
SELECT
n.GeoNameId AS Id,
an.IsoLanguage,
COALESCE(an.AlternateName, n.Name) AS LocalisedName
FROM GN_Name AS n
LEFT JOIN GN_AlternateName AS an ON n.GeoNameId = an.GeoNameId
AND IsoLanguage = 'es'
) x
WHERE LocalisedName LIKE 'estoc%'
(Changed it based on your update.)
If I understand correctly, in your example the value 'Estocolmo' is in the GN_AlternateName.AlternateName column, so would be filtered out by the where clause which only looks at GN_Name.Name. What if you change the last line of SQL to:
WHERE n.Name LIKE N'estoc%' OR an.AlternateName LIKE N'estoc%'
I'm assuming 'estoc%' is your search string.
I guess you need to modify the WHERE clause to check in GN_AlternateName table as well
WHERE n.Name like N'estoc%' OR an.AlternateName like 'N'estoc%'