How do I add a NOT clause to my SQL query - mysql

I would like to add a NOT clause to this SQL query:
Select
members.Member_Id,
members.Title,
members.FirstName,
members.LastName,
members.Po_Box,
members.Street,
members.City,
members.Del,
members.Mobile,
members.eMail,
members.WFTD,
ship_info.Renewal_Date
From
members
Left Join
ship_info on (members.Member_Id = ship_info.Member_Id)
Order By
ship_info.Renewal_Date
The NOT clause is this:
Where Member_Id Not Between 2000 And 3000;
I have tried to place this line in different places, but get an error each time, and since Wamp reports errors in french, find it unhelpful.
Yes there are similar questions like this, but they confuse me more, as I don't understand them enough to modify my script accordingly. I don't know much about arrays and complex code.
I export data from the database for mail merge purposes, and Members whose Ids are in the 2000s are deleted Members, whose Id's were moved from their original Id to that of higher numbers, as I don't like deleting people permanently in case they change their mind later down the track.
Thank you.

You could try it like this:
Select members.Member_Id
,members.Title
,members.FirstName
,members.LastName
,members.Po_Box
,members.Street
,members.City
,members.Del
,members.Mobile
,members.eMail
,members.WFTD
,ship_info.Renewal_Date
From members
LEFT JOIN ship_info ON (members.Member_Id=ship_info.Member_Id)
WHERE (members.Member_ID < 2000 OR members.member_ID > 3000)
ORDER BY ship_info.Renewal_Date

Since you are using a JOIN and member_id field resides in both tables of the JOIN, you must specify for which table you need the where statement. Try:
SELECT members.Member_Id
,members.Title
,members.FirstName
,members.LastName
,members.Po_Box
,members.Street
,members.City
,members.Del
,members.Mobile
,members.eMail
,members.WFTD
,ship_info.Renewal_Date
FROM members
LEFT JOIN ship_info ON (members.Member_Id = ship_info.Member_Id)
WHERE members.Member_Id NOT BETWEEN 2000
AND 3000
ORDER BY ship_info.Renewal_Date

According to "Database Administration Fundamentals", the following would be the appropriate syntax:
Select members.Member_Id
,members.Title
,members.FirstName
,members.LastName
,members.Po_Box
,members.Street
,members.City
,members.Del
,members.Mobile
,members.eMail
,members.WFTD
,ship_info.Renewal_Date
From members
LEFT JOIN ship_info ON (members.Member_Id=ship_info.Member_Id)
WHERE NOT members.Member_Id BETWEEN 2000 AND 3000
ORDER BY ship_info.Renewal_Date ;
In the previously mentioned book, it states,
" JOIN statements can be specified in either the FROM or the WHERE
clause, but it is recommended that you specify them in the FROM clause
".
As for clause precedence, here is the correct order to follow:
SELECT -- "what" we want
FROM -- "where" to look for it
JOIN
WHERE -- condition
GROUP BY
HAVING
ORDER BY -- sorting order

I think below should work, if not then please specify error which you got, you just need to prefix table name members (better if you use this table name as alias)
SELECT members.Member_Id
,members.Title
,members.FirstName
,members.LastName
,members.Po_Box
,members.Street
,members.City
,members.Del
,members.Mobile
,members.eMail
,members.WFTD
,ship_info.Renewal_Date
FROM members
LEFT JOIN ship_info ON (members.Member_Id = ship_info.Member_Id)
WHERE members.Member_Id NOT BETWEEN 2000
AND 3000
ORDER BY ship_info.Renewal_Date

Related

SQL query optimization taking lot of time in execution

We have two tables one is properties and another one is property meta when we are getting data from one table "properties" , query only take less then one second in execution but when we are use join to get the data using bellow query from both tables its taking more then 5 second to fetch the data although we have only 12000 record in the tables , i think there is an issue in the sql query any help or suggestion will be appreciated.
SELECT
u.id,
u.property_title,
u.description,
u.city,
u.area,
u.address,
u.slug,
u.latitude,
u.longitude,
u.sync_time,
u.add_date,
u.is_featured,
u.pre_construction,
u.move_in_date,
u.property_status,
u.sale_price,
u.mls_number,
u.bedrooms,
u.bathrooms,
u.kitchens,
u.sub_area,
u.property_type,
u.main_image,
u.area_size as land_area,
pm7.meta_value as company_name,
pm8.meta_value as virtual_tour,
u.year_built,
u.garages
FROM
tbl_properties u
LEFT JOIN tbl_property_meta pm7
ON u.id = pm7.property_id
LEFT JOIN tbl_property_meta pm8
ON u.id = pm8.property_id
WHERE
u.status = 1
AND (pm7.meta_key = 'company_name')
AND (pm8.meta_key = 'virtual_tour')
AND (
(
( u.city = 'Delta'
OR u.post_code LIKE '%Delta%'
OR u.sub_area LIKE '%Delta%'
OR u.state LIKE '%Delta%')
AND country = 'Canada'
)
OR (
( u.city = 'Metro Vancouver Regional District'
OR u.post_code LIKE '%Metro Vancouver Regional District%'
OR u.sub_area LIKE '%Metro Vancouver Regional District%'
OR u.state LIKE '%Metro Vancouver Regional District%' )
AND country = 'Canada'
)
)
AND
u.pre_construction ='0'
GROUP BY
u.id
ORDER BY
u.is_featured DESC,
u.add_date DESC
Try adding this compound index:
ALTER TABLE tbl_property_meta ADD INDEX id_key (property_id, meta_key);
If it doesn't help make things faster, try this one.
ALTER TABLE tbl_property_meta ADD INDEX key_id (meta_key, property_id);
And, you should know that column LIKE '%somevalue' (with a leading %) is a notorious performance antipattern, resistant to optimization via indexes. (There's a way to create indexes for that shape of filter in PostgreSQL, but not in MariaDB / MySQL.)
Add another column with the meta stuff; throw city, post_code, sub_area, and state and probably some other things into it. Then build a FULLTEXT index on that column. Then use MATCH(..) AGAINST("Delta Metro Vancouver Regional District") in the WHERE clause _instead of the LEFT JOINs (which are actually INNER JOINs) and the really messy part of the WHERE clause.
Also, the GROUP BY is probably unnecessary, thereby eliminating extra sort on the intermediate set of rows.

MySQL DISTINCT returning not so distinct results

Good day,
I have a small issue with MySQL Distinct.
Trying the following query in my system :
SELECT DISTINCT `booking_id`, `booking_ticket`, `booking_price`, `bookingcomment_id`, `bookingcomment_message` FROM `mysystem_booking`
LEFT JOIN `mysystem_bookingcomment` ON `mysystem_booking`.`booking_id` = `mysystem_bookingcomment`.`bookingcomment_link`
WHERE `booking_id` = 29791
The point is that there are bookings like 29791 that have many comments added.
Let's say 10. Then when running the above query I see 10 results instead of one.
And that's not the way DISTINCT supposes to work.
I simply want to know if there are any comments. If the comment ID is not 0 then there is a comment. Of course I can add COUNT(blabla) as comment_number but that's a whole different story. For me now I'd like just to have this syntax right.
You may try aggregating here, to find which bookings have at least a single comment associated with them:
SELECT
b.booking_id,
b.booking_ticket,
b.booking_price
FROM mysystem_booking b
LEFT JOIN mysystem_bookingcomment bc
ON b.booking_id = bc.bookingcomment_link
WHERE
b.booking_id = 29791
GROUP BY
b.booking_id
HAVING
COUNT(bc.bookingcomment_link) > 0;
Note that depending on your MySQL server mode, you might have to also add the booking_ticket and booking_price columns to the GROUP BY clause to get the above query to run.
You can try below - using a case when expression
SELECT DISTINCT `booking_id`, `booking_ticket`, `booking_price`, `bookingcomment_id`,
case when `bookingcomment_message`<>'0' then 'No' else 'Yes' end as comments
FROM `mysystem_booking`
LEFT JOIN `mysystem_bookingcomment` ON `mysystem_booking`.`booking_id` = `mysystem_bookingcomment`.`bookingcomment_link`
WHERE `booking_id` = 29791

SQL error: Ambiguous column name

I have troubles with execution sql
any time I execute it gives me an error Ambiguous column name 'salesYTD'
my statement is :
SELECT COUNTRYREGIONCODE, NAME, AVG(SALESQUOTA),AVG(BONUS), AVG(SALESYTD)
FROM SALES.SALESPERSON SP
INNER JOIN SALES.SALESTERRITORY ST
ON SP.TERRITORYID = ST.TERRITORYID
GROUP BY NAME, COUNTRYREGIONCODE;
the name of that column is correct. I don't understand what I am doing wrong. Thanks for any help
This means that SALESYTD is in both tables. I don't know which you want.
When you have more than one table in a query always qualify your column names.
SELECT ST.NAME, ST.COUNTRYREGIONCODE,
AVG(SP.SALESQUOTA), AVG(SP.BONUS), AVG(SP.SALESYTD)
FROM SALES.SALESPERSON SP INNER JOIN
SALES.SALESTERRITORY ST
ON SP.TERRITORYID = ST.TERRITORYID
GROUP BY ST.NAME, ST.COUNTRYREGIONCODE;
I'm just guessing where the columns come from.
Does that column exist in more than one table?
If so, you should name the field like this:
SP.salesYTD
or
ST.salesYTD
Depending on what you want to show.
Good luck.

mysql JOIN Inside a JOIN and search a group_concatenated values

I cant seem to find a solution for Searching a group_concatenated value,
I have 3 table that are connected with id's
1st table have the same value with 2nd table, but no same value with 3rd,
2nd table have the same value with 1st and 3rd table,
I want to get the value inside 3rd table,
concat the values in accordance to Distinct ID's of 2nd table, display them, and be able to search
this are my tables look like
how do i search for the concatenated values
please if there's a better way, your help is much appreciated?
the query below is what i have so far
$query = $db->prepare("
SELECT
a.problem_encountered,
GROUP_CONCAT(
DISTINCT
c.full_name)
AS
fnames
FROM
maintenance_sheet_table a
LEFT JOIN
mis_incharge_table b
ON
b.mis_incharge_id = a.mis_incharge_id
INNER JOIN
users_table c
ON
c.mis_id=b.mis_id
WHERE
a.problem_encountered
LIKE
:findMe
HAVING
fnames
LIKE
:findMe
GROUP BY a.id ORDER BY a.id
");
$query->bindValue(':findMe', '%' . $keywordSearch. '%');
A potential answer is to filter the Users_table in a subquery. There are a number of different forms of this option, and hard to tell from your data which is required. The one I have below simply returns the users that match the search criteria.
SELECT a.problem_encountered, GROUP_CONCAT(DISTINCT innerc.full_name) AS fnames
FROM maintenance_sheet_table a
LEFT JOIN mis_incharge_table b ON b.mis_incharge_id = a.mis_incharge_id
LEFT JOIN (SELECT c.mis_id, c.full_name
FROM users_table c
WHERE c.full_name LIKE :findMe) innerc ON innerc.mis_id=b.mis_id
WHERE a.problem_encountered LIKE :findMe
GROUP BY a.id
ORDER BY a.id
However, you could also do the concatenation within the subquery if required.
SELECT a.problem_encountered, innerc.fnames
FROM maintenance_sheet_table a
INNER JOIN (SELECT mit.mis_incharge_id, GROUP_CONCAT(DISTINCT ut.full_name) AS fnames
FROM users_table ut
INNER JOIN mis_incharge_table mit ON ut.user_id = mit.user_id
GROUP BY mit.mis_incharge_id
HAVING fnames LIKE :findMe) innerc ON innerc.mis_incharge_id = a.mis_incharge_id
WHERE a.problem_encountered LIKE :findMe
GROUP BY a.id
ORDER BY a.id
Note: I agree with spencer7593, that you shouldn't use the same :findMe variable against 2 separate fields. Even if it works, to a maintenance programmer or even yourself in a few years time, will probably look at this and think that the wrong fields are being interrogated.
You can "search" the return from the GROUP_CONCAT() expression in the HAVING clause. As a more efficient alternative, I suspect you could use an EXISTS predicate with a subquery.
I suspect part of the problem is that your query is referencing the same bind placeholder more than one time. (In previous releases of PDO, this was a restriction, a named bind placeholder could be referenced only once.)
The workaround to this issue is to use a separate bind placeholder, e.g.
HAVING fnames LIKE :findMeToo
And then bind a value to each placeholder:
$query->bindValue(':findMe', '%' . $keywordSearch. '%');
$query->bindValue(':findMeToo', '%' . $keywordSearch. '%');
(With this issue, I don't think PDO issued a warning or error; the effect was as if no value was supplied for the second reference to the named bind placeholder. Not sure if this issue is fixed, either by a code change or a documentation update. The workaround as above, reference a bind placeholder only once within a query.)
Beyond that, it's not clear what problem you are observing.
Your HAVING clause should come after your GROUP BY clause
change
HAVING
fnames
LIKE
:findMe
GROUP BY a.id ORDER BY a.id
to
GROUP BY a.id
HAVING
fnames
LIKE
:findMe
ORDER BY a.id

SQL problem, LEFT JOIN [..] IN()

This small SQL error is bugging me. It doesn't seem to be a problem with the query, just the scope(?), examples work best:
SELECT ocp.*, oc.*, GROUP_CONCAT( u.username SEPARATOR ', ') AS `memjoined`
FROM gangs_ocs_process ocp, gangs_ocs oc
LEFT JOIN users u ON u.userid IN ( ocp.membersin )
WHERE ocp.ocid =1 AND ocp.gangid =1 AND oc.oc_name = ocp.crimename
GROUP BY ocp.ocid
LIMIT 0 , 30
Theres a column (gangs_ocs_process.membersin) which has a list of IDs that have joined (ie 1,2,5). I'm trying to get the usernames for each of these IDs (from the users table) in one go.
The problem is LEFT JOIN users u ON u.userid IN ( ocp.membersin )
If I substitue 1,2,4 in for ocp.membersin (putting the literal list instead of column name), it works ok. It returns a column that has the usernames (image). However, if I leave in the ocp.membersin, I get this error:
#1054 - Unknown column 'ocp.membersin' in 'on clause'
This is the first time I've even used IN in left joins so I'm a bit lost.
Any help would be great :)
I don't think that "IN" will work for this syntax. MySQL expects IN to be something akin to a dataset, not a delimited string. I think you need to find a way to take membersin, expand it into a dataset MySQL can work with (maybe a temporary table), and join on that.
If you have delimited strings in your table, you have a design problem in your database. Add a new table to hold these values.
Are you sure 'membersin' is in the 'gangs_ocs_process' table, and not the 'gangs_ocs' table?
The reason you can't get it to work is because first you need to get your database NORMALIZED. You should NEVER, EVER have a list of ID's in a single column.
After taking another look, I think your problem is trying to aggregate at the wrong point as well as the IN syntax and that you should aggregate in a subquery restricted by the contents of the IN. I don't know enough about your schema to make this out of the box correct, but you want something like this. SomeKeyfield should relate back to gangs_ocs_process
SELECT ocp.*, oc.*, u.Memjoined
FROM gangs_ocs_process ocp, gangs_ocs oc
LEFT JOIN (Select SomeKeyField, GROUP_CONCAT( u.username SEPARATOR ', ') as memjoined
from users where userid in
(select membersin from gangs_ocs_process
where [whatever conditions] )
Group By SomeKeyField) u on ocp.SomeKeyField = u.SomeKeyField
WHERE ocp.ocid =1 AND ocp.gangid =1 AND oc.oc_name = ocp.crimename
GROUP BY ocp.ocid
LIMIT 0 , 30
This is a bad way to keep membership.
But if you still need to live with it, you may try REGEXP matching to test for membership:
SELECT ocp.*, oc.*, GROUP_CONCAT( u.username SEPARATOR ', ') AS `memjoined`
FROM gangs_ocs_process ocp
LEFT JOIN users u ON (ocp.membersin RLIKE CONCAT('(^|,)[[:blank:]]?', userid, '[[:blank:]]?($|,)'))
JOIN gangs_ocs oc ON (ocp.ocid = 1 AND ocp.gangid = 1 AND oc.oc_name = ocp.crimename)
GROUP BY ocp.ocid
LIMIT 0 , 30