MySQL syntax wrong - mysql

I have 3 tables :
user(id, name);
advert(id,name,category_id,user_id);
category(id,category_name);
What i want to do is show for a certain user how many adverts he has in each category.
I have to use a sub-query.I've tried something like this but is not working at all.
What I've tried looks like this:
SELECT c.id,c.name count(advert) number_of_adverts
FROM category c
GROUP BY c.name
HAVING count(advert)=(SELECT count(a.id)
FROM advert a
INNER JOIN user ON a.user_id=u.id
WHERE u.id="1"
HAVING a.category_id=c.id);
I know this is wrong but i dont quite understand how should i do it to make it work.

Your looking for the GROUP BY clause.
SELECT c.id, c.name, COUNT(a.id) AS number_of_adverts
FROM user u
JOIN advert a ON (u.id = a.user_id)
JOIN category c ON (c.id = a.category_id)
WHERE u.user_id = '999'
GROUP BY c.id, c.name
You can't use a sub-query as, there could be multiple categories and multiple adverts for each category.

Related

How to optimize this mysql query - %a% or

SELECT DISTINCT u.id AS userId,u.type AS userType
FROM User AS u,Personal AS p,Company AS c
WHERE (p.realName LIKE '%adf%' AND u.type=1 AND u.id=p.userId)
OR (c.name LIKE '%grge%' AND u.id=c.userId)
LIMIT 0 , 10000
You can write your query as:
SELECT DISTINCT u.id AS userId,u.type AS userType
FROM User AS u inner join Personal AS p on u.id=p.userId
inner join Company AS c on u.id=c.userId
where p.realName LIKE '%adf%' or c.name LIKE '%grge%'
LIMIT 0 , 10000
Try to avoid comma seperated JOINS
You appear to be doing a quite hideous cross join, and then selectively narrowing down the records in the WHERE clause.
It is probably better to do 2 queries and union the results together. Each query can do one proper join. It is still going to have to access one column using the LIKE, and with a leading wild card that is not going to be quick (it can't use indexes).
SELECT u.id AS userId,
u.type AS userType
FROM User AS u
INNER JOIN Personal AS p
ON u.id = p.userId
WHERE p.realName LIKE '%adf%'
AND u.type = 1
UNION
SELECT u.id AS userId,
u.type AS userType
FROM User AS u
INNER JOIN Company AS c
ON u.id=c.userId
WHERE c.name LIKE '%grge%'
LIMIT 0 , 10000

MYSQL subquery SELECT in JOIN clause

Ok... well I have to put the subquery in a JOIN clause since it selects more than one column and putting it in the SELECT clause does not allow that as it gives me an error of an operand.
Anywho, this is my query:
SELECT
c.id,
c.title,
c.description,
c.icon,
p.id as topic_id,
p.title AS topic_title,
p.date,
p.username
FROM forum_cat c
LEFT JOIN (
SELECT
ft.id,
ft.cat_id,
ft.title,
fp.date,
u.username
FROM forum_topic ft
JOIN forum_post fp ON fp.topic_id = ft.id
JOIN user u ON u.user_id = fp.author_id
WHERE ft.cat_id = c.id
ORDER BY fp.date DESC
LIMIT 1
) p ON p.cat_id = c.id
WHERE c.main_cat = ?
ORDER BY c.list_no
Now the important thing I need here... FOR EACH category, I want to show the latest post and topic title in each category.
However, this select statement is going INSIDE a foreach loop looping around the general categories which is found my main_cat.
So there are 5 main categories with 3-8 subcategories.. this is the subcategory query. BUT FOR EACH subcategory, I need to grab the latest post.. However, it only runs this SELECT query for each main category so it's only select THE LATEST post between all subcategories combined... I want to get the latest post of EACH subcategory, but I rather not run this query for each subcategory... since I want the page load to be fast.
BUT REMEMBER, some subcategories WILL NOT have a latest post since some of them may not even contain a topic yet! So hence the left join.
Does anyone know how to go about doing this?
AND BTW, there is an error it gives me (WHERE ft.cat_id = c.id) in the subquery because c.id is an unknown column. But I'm trying to reference it from the outer query so can someone help me on that issue as well?
Thank you!
All tables:
forum_cat (Subcategories)
-----------------------------------------------
ID, Title, Description, Icon, Main_cat, List_no
forum_topic (Topics in each subcategory)
--------------------------------------------
ID, Author_id, Cat_id, Title, Sticky, Locked
forum_post (Posts in each topic)
--------------------------------------------
ID, Topic_id, Author_id, Body, Date, Hidden'
The main categories are listed in a function. I didn't store them in the database since it was a waste of space since they never change. There are 7 main categories though.
It's hard to tell without seeing DDL of your tables, relevant sample data and desired output.
I could've got your requirements wrong, but try this:
SELECT *
FROM forum_cat c LEFT JOIN
(SELECT t.cat_id,
p.topic_id,
t.title,
p.id,
p.body,
MAX(p.`date`) AS `date`,
p.author_id,
u.username
FROM forum_post p INNER JOIN
forum_topic t ON t.id = p.topic_id INNER JOIN
`user` u ON u.user_id = p.author_id
GROUP BY t.cat_id) d ON d.cat_id = c.id
WHERE c.main_cat = 1
ORDER BY c.list_no

MySQL - A conditional WHERE

See, I've got this bulletin board. This query here works just fine.
SELECT bulletin.date,
bulletin.title,
bulletin.content,
bulletin.id,
bulletin.made_by,
users.ID,
users.name
FROM bulletin, users
WHERE bulletin.id = '12345'
AND bulletin.made_by = users.ID
LIMIT 1
Now, I'm running into troubles because when a user deletes his account there is no information about said person left, he is deleted from the users table. I know there may be other ways to deal with this but I can't fix that now.
So I ask: How can I make that query return bulletin.date, bulletin.title and bulletin.content where bulletin.id is equal to 12345 even though I've got "AND bulletin.made_by = users.ID"? You see, I need to have that for all the other posts where the user still exists.
Any suggestions?
Use a LEFT OUTER JOIN
SELECT b.date,
b.title,
b.content,
b.id,
b.made_by,
b.ID,
b.name
FROM bulletin b
LEFT OUTER JOIN users u on b.made_by = u.ID
WHERE b.id = '12345'
LIMIT 1
See this great explanation of joins
Currently you are using INNER JOIN, Use LEFT JOIN in order to solve your problem.
SELECT a.date,
a.title,
a.content,
a.id,
a.made_by,
a.ID,
a.name
FROM bulletin a
LEFT JOIN users c
ON a.made_by = c.ID
WHERE a.id = '12345'
LIMIT 1
LEFT JOIN basically fetches all the records from the left table whether it has a matching row in the second table or not.

SQL returning the same result multiple times

I am fairly new with advanced MySQL commands, I have database tables with multiple relationships. I have an advanced search feature that must match Keywords to a few fields (most being in the Assets table but a couple in the User table). When I execute the following Query for desk it returns the same row multiple times, while it should do it once.
SELECT
a.id, a.asset_id, a.name, a.serial_number, a.category_id, a.status_id, a.user_id, a.location_id
FROM
assets a, users u
WHERE
(a.asset_ID LIKE '%desk%' OR a.name LIKE '%desk%' OR (u.first_name LIKE '%desk%' OR u.last_name LIKE '%desk%')) AND
a.serial_number LIKE '%%' AND
a.category_id='2'
LIMIT 25 OFFSET 5450
You have a cartesian product in your query. You should JOIN assets and users, e.g. with
WHERE a.user_id = u.id
or like this
FROM assets a JOIN users u ON a.user_id = u.id
UPDATE: Your comment shows that you actually want to "left outer join" the users table. This means, that all assets are in the result set regardless if there exists a matching user:
FROM assets a LEFT OUTER JOIN users u ON a.user_id = u.id
Read more about joining tables here: http://dev.mysql.com/doc/refman/5.5/en/join.html
You could use a SELECT DISTINCT clause, though the actual problem looks like the one made by Lukas. It's good practice to use explicit joins like so:
FROM assets a
JOIN users u ON a.user_id=u.id
You need to actually join the two tables (Assets and Users) together. As you have it, every row in each table is matched with every row in the other. This is known as a Cartesian Product and is usually a bad thing.
I would also suggest that you start using proper JOIN syntax:
SELECT
a.id,
a.asset_id,
a.name,
a.serial_number,
a.category_id,
a.status_id,
a.user_id,
a.location_id
FROM
Assets A
INNER JOIN Users U ON A.user_id = U.user_id
WHERE
(
a.asset_ID LIKE '%desk%' OR
a.name LIKE '%desk%' OR
(
u.first_name LIKE '%desk%' OR
u.last_name LIKE '%desk%'
)
) AND
a.serial_number LIKE '%%' AND
a.category_id='2'
LIMIT 25
OFFSET 5450
You are missing the join between the two tables.
Add something like
AND a.user_id = u.user_id

Problem using MySQL Join

i have a MySQL SELECT query which fetches data from 6 tables using Mysql JOIN. here is the MySQL query i am using.
SELECT
u.id,u.password,
u.registerDate,
u.lastVisitDate,
u.lastVisitIp,
u.activationString,
u.active,
u.block,
u.gender,
u.contact_id,
c.name,
c.email,
c.pPhone,
c.sPhone,
c.area_id,
a.name as areaName,
a.city_id,
ct.name as cityName,
ct.state_id,
s.name as stateName,
s.country_id,
cn.name as countryName
FROM users u
LEFT JOIN contacts c ON (u.contact_id = c.id)
LEFT JOIN areas a ON (c.area_id = a.id)
LEFT JOIN cities ct ON (a.city_id = ct.id)
LEFT JOIN states s ON (ct.state_id = s.id)
LEFT JOIN countries cn ON (s.country_id = c.id)
although query works perfectly fine it sometimes returns duplicate results if it finds any duplicate values when using LEFT JOIN. for example in contacts table there exist two rows with area id '2' which results in returning another duplicated row. how do i make a query to select only the required result without any duplicate row. is there any different type of MySQL Join i should be using?
thank you
UPDATE :
here is the contacts table, the column area_id may have several duplicate values.
ANSWER :
there was an error in my condition in last LEFT JOIN where i have used (s.country_id = c.id) instead it should be (s.country_id = cn.id) after splitting the query and testing individually i got to track the error. thank you for your response. it works perfectly fine now.
Duplicating the rows like you mentioned seems to indicate a data problem.
If users is your most granular table this shouldn't happen.
I'd guess, then, that it's possible for a single user to have multiple entries in contacts
You could use DISTINCT as mentioned by #dxprog but I think that GROUP BY is more appropriate here. GROUP BY whichever datapoint could potentially be duplicated....
After all, if a user has corresponding contact records, which one are you intending to JOIN to?
You must specify this if you want to remove "duplicates" because, as far as the RDBMS is concerned, the two rows matching
LEFT JOIN contacts c ON (u.contact_id = c.id)
Are, in fact, distinct already
I think a DISTINCT may be what you're looking for:
SELECT DISTINCT
u.id,u.password,
u.registerDate,
u.lastVisitDate,
u.lastVisitIp,
u.activationString,
u.active,
u.block,
u.gender,
u.contact_id,
c.name,
c.email,
c.pPhone,
c.sPhone,
c.area_id,
a.name as areaName,
a.city_id,
ct.name as cityName,
ct.state_id,
s.name as stateName,
s.country_id,
cn.name as countryName
FROM users u
LEFT JOIN contacts c ON (u.contact_id = c.id)
LEFT JOIN areas a ON (c.area_id = a.id)
LEFT JOIN cities ct ON (a.city_id = ct.id)
LEFT JOIN states s ON (ct.state_id = s.id)
LEFT JOIN countries cn ON (s.country_id = c.id)
This should only return rows where the user ID is distinct, though you may not get all the joined data you'd hoped for.