Where exists SQL with internal where condition? - mysql

I have the following request, to say more precise the SQL parameterized query:
select * from `products`
where (exists (select * from `productslocation` where `products`.`Id` = `productslocation`.`Product_Id` and `Country_Id` = ?) and
exists (select * from `productprices` where `products`.`Id` = `productprices`.`Products_Id` and `Price` >= ?)
and `Organization_Id` = ? and `name` like ? or `Description` like ?) and `Status` = ?
This query retrieves only products where exist country, price using operator WHERE EXISTS.
If it was found it returns TRUE for first sub query, then works remaining two queries WHERE. First sub query returns TRUE, second gives TRUE, cause sub query is right also. result = TRUE * TRUE = TRUE. But it is wrong result.
Problem is, that need to use two intern queries WHERE for result from WHERE EXISTS.
Does it mean I need to replace WHERE EXISTS ON JOIN'S? Or is it possible to modify query above?

Your parentheses and ORs and ANDs are making the statement very complicated.
Try this:
select * from `products`
where
(
exists (select * from `productslocation` where `products`.`Id` = `productslocation`.`Product_Id` and `Country_Id` = ?) and
exists (select * from `productprices` where `products`.`Id` = `productprices`.`Products_Id` and `Price` >= ?) and
`Organization_Id` = ? and (`name` like ? or `Description` like ?) and `Status` = ?
)

It's not better that way? Try this:
select * from `products` inner join productprices on `products`.`Id` = `productprices`.`Products_Id`
INNER JOIN `productslocation` ON `products`.`Id` = `productslocation`.`Product_Id`
where (`Organization_Id` = ? and `name` like ? or `Description` like ?) and `Status` = ?
AND `productprices`.`Price` >= ?
and `productslocation`.Country_Id` = ?

You missed brackets around your or statement:
select * from `products`
where (exists (select * from `productslocation` where `products`.`Id` = `productslocation`.`Product_Id` and `Country_Id` = ?) and
exists (select * from `productprices` where `products`.`Id` = `productprices`.`Products_Id` and `Price` >= ?)
and `Organization_Id` = ? and (`name` like ? or `Description` like ?)) and `Status` = ?

You are looking for a query that filters products on various criteria, some involving referential relationships.
Assuming that you have 1-1 relationships with the referential tables, you should be able to use JOINs :
select *
from
`products`
inner join `productslocation`
on `products`.`Id` = `productslocation`.`Product_Id` and `productslocation`.`Country_Id` = ?
inner join `productprices`
on `products`.`Id` = `productprices`.`Products_Id` and `productprices`.`Price` >= ?
where
`products`.`Organization_Id` = ?
and `products`.`name` like ?
and `products`.`Description` like ?
and `products`.`Status` = ?

Related

Unknown column due to second-level subquery nesting

I want to retrieve a user's rank based on how many points the given user has compared to other users (simply counting users with more points than the given user).
However, with all the queries I have tried, I always end up with Column not found: users.id. From what I can read there is a limit from referencing correlated parent columns more than one level up.
Can I refactor my query, or do I really need to use SET #rownum := 0 style of queries?
SELECT
`users`.*,
(
SELECT COUNT(*) + 1
FROM (
SELECT SUM(`amount`) AS `all_points`
FROM `points`
WHERE `type` = ?
GROUP BY `user_id`
HAVING `all_points` > (
SELECT SUM(`amount`)
FROM `points`
WHERE `type` = ? and `user_id` = `users`.`id`
)
) `points_sub`
) as `rank`
FROM `users`
WHERE `users`.`id` = ?
LIMIT 1
You can move your sub clause one level up, Remove having filter and use where filter
SELECT
`users`.*,
(
SELECT COUNT(*) + 1
FROM (
SELECT user_id,SUM(`amount`) AS `all_points`
FROM `points`
WHERE `type` = ?
GROUP BY `user_id`
) `points_sub`
WHERE `all_points` >
SELECT SUM(`amount`)
FROM `points`
WHERE `type` = ? and `user_id` = `users`.`id`
) as `rank`
FROM `users`
WHERE `users`.`id` = ?
LIMIT 1
I think the below query should work for you. You can pass the user_id of user whose rank you want to compute in both the arguments.
SELECT
`users`.*,
(
SELECT COUNT(*) + 1
FROM (
SELECT SUM(`amount`) AS `all_points`
FROM `points`
WHERE `type` = ?
GROUP BY `user_id`
HAVING `all_points` > (
SELECT COALESCE(SUM(`amount`),0)
FROM `points`
WHERE `type` = ? and `user_id` = ?
)
) `points_sub`
) as `rank`
FROM `users`
WHERE `users`.`id` = ?
LIMIT 1

MySQL query on two tables with conditions

I have two tables:
users and users_img.
I need to create one query to select all users from users table that have zip column not empty AND have img column empty in users_images (both tables have user ids: users.id and users_img.user_id so those could be joined).
users
id
name
zip
last_time
users_ids
id
user_id (same as id in users)
img
I tried this:
SELECT * FROM `users` JOIN `users_ids` on users.id = users_ids.user_id
WHERE `zip` != '' AND `img` = '' ORDER BY `last_time` DESC
with no luck. I know is supposed to be quite simple.
it will also work for you
SELECT * FROM `users` as `u`
JOIN `users_ids` as `uid` on `u`.`id` = `uid`.`user_id`
WHERE `u`.`zip` IS NOT NULL
AND `uid`.`img` IS NULL
ORDER BY `u`.`last_time` DESC
I have modified your query to check for Null values also in OR
Try this:
SELECT * FROM `users`
LEFT JOIN `users_ids` on users.id = users_ids.user_id
WHERE (TRIM(`zip`) != '' OR `zip` is not null) AND
(TRIM(`img`) = '' OR `img` is null) ORDER BY `last_time` DESC
This worked:
SELECT * FROM `users` as `u`
LEFT JOIN `users_ids` as `uid` on `u`.`id` = `uid`.`user_id`
WHERE `u`.`zip` != ''
AND `uid`.`img` IS NOT NULL
ORDER BY `u`.`last_time` DESC

MySQL Invalid Use of Group Function

I'm getting Error Code: 1111. Invalid use of group function when trying to build a query in MySQL. Apparently MySQL doesn't support WITH, which is what I'm more comfortable using.
SELECT DISTINCT `UserID`
FROM `user`
INNER JOIN `message`
ON `user`.`Message` = `message`.`Recipient`
WHERE MAX(`TotalSize`) IN (
SELECT SUM(`message`.`Size`) as `TotalSize`
FROM `message`
INNER JOIN `category`
ON `message`.`CatID` = `category`.`CatID`
WHERE `category`.`CatName` = 'Inbox'
GROUP BY `Recipient`);
SELECT `UserID`, MAX(SUM(message.Size)) as TotalSize
FROM `user`
INNER JOIN `message`
ON `user`.`Message` = `message`.`Recipient`
INNER JOIN category
ON message.CatID = category.CatID
WHERE category.CatName = 'Inbox'
GROUP BY UserID
You need to use HAVING clause instead of WHERE MAX(TotalSize)
SELECT DISTINCT `UserID`
FROM `user`
INNER JOIN `message`
ON `user`.`Message` = `message`.`Recipient`
GROUP BY `UserID`
HAVING MAX(`message`.`Size`) IN (
SELECT SUM(`message`.`Size`) as `TotalSize`
FROM `message`
INNER JOIN `category`
ON `message`.`CatID` = `category`.`CatID`
WHERE `category`.`CatName` = 'Inbox'
GROUP BY `Recipient`);
Group functions are not accessible in WHERE clause , HAVING can filter on aggregates.

Check in MySQL table if my ID exist in the results

How to check in MySQL table if my ID exist in the results and return TRUE, but this is a little complicated as I would like to check GROUP of records and not the last one from that GROUP, code below for the table and query which doesn't work, I would like to check if my $session_user_id exist in the GROUP OF auction_bid_item_id but not check last row as the last row is a WINNING ROW.
CREATE TABLE `auction_bids` (
`auction_bid_id` int(11) NOT NULL AUTO_INCREMENT,
`auction_bid_user_id` int(11) NOT NULL,
`auction_bid_seller_id` int(11) NOT NULL,
`auction_bid_item_id` int(11) NOT NULL,
PRIMARY KEY (`auction_bid_id`)
);
MySQL Query:
SELECT * FROM auction_bids
WHERE auction_bid_user_id = '$session_user_id'
GROUP BY auction_bid_item_id;
Join against a subselect which determines if the user is in that group.
Ie, the following will get you the bids and a field saying if the user is found.
SELECT auction_bids.*, IF(Sub1.auction_bid_item_id IS NULL, 'User not found', 'User found')
FROM auction_bids
LEFT OUTER JOIN
(
SELECT DISTINCT auction_bid_item_id
FROM auction_bids
WHERE auction_bid_user_id = '$session_user_id'
) Sub1
ON auction_bids.auction_bid_item_id = Sub1.auction_bid_item_id
GROUP BY auction_bids.auction_bid_item_id
EDIT - try this to try and ignore the latest bid
SELECT auction_bids.*, IF(Sub1.auction_bid_item_id IS NULL, 'User not found', 'User found')
FROM auction_bids
LEFT OUTER JOIN
(
SELECT DISTINCT auction_bids.auction_bid_item_id
FROM auction_bids
LEFT OUTER JOIN
(
SELECT auction_bid_item_id, MAX(auction_bid_id) AS LastBid
FROM auction_bids
GROUP BY auction_bid_item_id
) Sub2
ON auction_bids.auction_bid_item_id = Sub2.auction_bid_item_id
AND auction_bids.auction_bid_id = Sub2.LastBid
WHERE Sub2.auction_bid_item_id IS NULL
AND auction_bid_user_id = '$session_user_id'
) Sub1
ON auction_bids.auction_bid_item_id = Sub1.auction_bid_item_id
GROUP BY auction_bids.auction_bid_item_id
Something like this? (with php)
$id_exists = false;
$id = mysql_real_escape_string($_GET['id']);
$select = "SELECT auction_bid_id FROM auction_bids WHERE auction_bid_id ='$id'";
$result = mysql_query($select);
if(mysql_num_rows($result) > 0){
$id_exists = true;
}else{
$id_exists = false;
}

Combine conditions with AND in Mysql ON clause

I have the following query, that I use to filter rows based on software_id and level.
I've put the conditions in the ON-Clause since I still want rows returned, where there are no corresponding rows in the JobadvertsSoftware Table.
SELECT `Jobadvert`.`id` FROM `jobadverts` AS `Jobadvert`
LEFT JOIN `users` AS `User` ON (`Jobadvert`.`user_id` = `User`.`id`)
LEFT JOIN `jobadverts_softwares` AS `JobadvertsSoftware_0` ON
(`Jobadvert`.`id` = 'JobadvertsSoftware_0.jobadvert_id' AND
(`JobadvertsSoftware_0`.`software_id` = '32' AND
`JobadvertsSoftware_0`.`level` IN ('1', 4)))
WHERE `Jobadvert`.`active` = 1 AND `User`.`premium` = '1' AND
Jobadvert`.`department_id` = (5)
GROUP BY `Jobadvert`.`id`
The problem is that it also returns JobadvertsSoftware-rows where level is e.g. 2
Again, if I put that in the WHERE clause it will filter out the rows where there are not JobadvertsSoftware which it shouldn't do.
How can I tell MySQL to return all rows of Jobadvert, where the given software_id AND the level matches or are NULL?
Try this:
SELECT `Jobadvert`.`id`, `JobadvertsSoftware_0`.`level`
FROM `jobadverts` AS `Jobadvert`
LEFT JOIN `users` AS `User` ON (`Jobadvert`.`user_id` = `User`.`id`)
INNER JOIN `jobadverts_softwares` AS `JobadvertsSoftware_0` ON
(`Jobadvert`.`id` = 'JobadvertsSoftware_0.jobadvert_id' AND
(`JobadvertsSoftware_0`.`software_id` = '32' AND
`JobadvertsSoftware_0`.`level` IN ('1', 4)))
WHERE `Jobadvert`.`active` = 1 AND `User`.`premium` = '1' AND
Jobadvert`.`department_id` = (5)
GROUP BY `Jobadvert`.`id`
Saludos!
Try this( it's a bit unclear if some fields are numeric on string, it might be corrected):
SELECT distinct(`Jobadvert`.`id`) FROM `jobadverts` AS `Jobadvert`
LEFT JOIN `users` AS `User` ON (`Jobadvert`.`user_id` = `User`.`id`)
LEFT JOIN `jobadverts_softwares` AS `JobadvertsSoftware_0`
ON `Jobadvert`.`id` = `JobadvertsSoftware_0.jobadvert_id`
WHERE
`Jobadvert`.`active` = 1
AND `User`.`premium` = '1'
AND Jobadvert`.`department_id` = (5)
AND JobadvertsSoftware_0`.`software_id` = '32'
AND (`JobadvertsSoftware_0`.`level` IN (1, 4) OR `JobadvertsSoftware_0`.`level` is NULL)
Assuming the level parameters in your ON clause is not needed for the join you can do a nested SELECT on your Software table to clear out the data you do not need first:
SELECT * FROM jobadverts_softwares
WHERE
(`software_id` = 32 OR `software_id` IS NULL) --Select all software_id that are 32 or null
AND
`level` IN (1, 4)
Then you can incorporate this as a nested statement in your main SQL query so you only join on the data which is filtered in your LEFT JOIN but keep any null values that you needed:
SELECT `Jobadvert`.`id`
FROM `jobadverts` AS `Jobadvert`
LEFT JOIN `users` AS `User`
ON `Jobadvert`.`user_id` = `User`.`id`
LEFT JOIN
( --Software Subquery
SELECT `jobadvert_id`, `level` FROM jobadverts_softwares
WHERE
(`software_id` = 32 OR `software_id` IS NULL) --Select all software_id that are 32 or null
AND
`level` IN (1, 4)
) AS `software_subquery`
ON `Jobadvert`.`id` = `software_subquery`.`jobadvert_id`
WHERE
`Jobadvert`.`active` = 1
AND
`User`.`premium` = '1'
AND
`Jobadvert`.`department_id` = 5
ORDER BY `Jobadvert`.`id` --Changed GROUP BY to ORDER BY as not needed
This is untested but try it out and see if this will help.
Try this:
SELECT j.id
FROM jobadverts j
LEFT JOIN User u ON (j.user_id = u.id)
LEFT JOIN jobadverts_softwares AS js ON
(j.id = js.jobadvert_id)
WHERE j.active = 1
AND u.premium = '1'
AND j.department_id = (5)
AND js.software_id` = '32'
AND js.level IN ('1', 4)))
You won't need a GROUP BY unless summing data in some way.