Sort MySql query by field in exists sub query - mysql

I am looking for a way to sort a query by a field that exists within a where exists query.
An attempt to use a field from the exists subquery I get the 'Unknown column' error.
Example query;
select
*
from
`table_a`
where
`a_field` = 'foo'
and exists (
select
*
from
`table_b`
where
`table_a`.`an_id` = `table_b`.`another_id` and `table_b`.`another_field` = 'bar'
)
order by
`table_a`.`created_at` asc,
`table_b`.`another_id` desc;
Is the only solution to use an inner join query like;
select
`t1`.*
from
`table_a` as `t1`
inner join `table_2` as `t2` on `t2`.`another_id` = `t1`.`an_id`
where
`t1`.`a_field` = 'foo'
and `t2`.`another_field` = 'bar'
order by
`t1`.`created_at` asc,
`t2`.`another_id` desc;

Your example query is ordering by another_id, which is used in the correlation clause. So, you can just do:
select a.*
from table_a a
where a.a_field = 'foo' and
exists (select 1
from table_b b
where a.an_id = b.another_id and
b.another_field = 'bar'
)
order by a.created_at asc,
a.an_id desc;
Assuming you actually want a different column, you can use a JOIN. The issue is that more than one row may match. So you need to remove the duplicates in the subquery:
select a.*
from table_a a join
(select b.another_id, max(b.another_col) as another_col
from table_b b
where another_field = 'bar'
group by b.another_id
) b
on a.an_id = b.another_id
where a.a_field = 'foo'
order by a.created_at asc, b.another_id desc;
You can only use your form of the JOIN if you know that at most one row will match.

Related

How to ORDER BY a temporary table

In the following query I want to ORDER BY RAND() c table. When I put the ORDER BY RAND() inside the JOIN, query need more than 5 seconds to execute because ORDER BY runs before GROUP BY.
UPDATE `backlinks` as a
JOIN (
SELECT b.`id` as bid
FROM `backlinks` b
WHERE b.`googlebot_id` IS NULL
AND b.`used_time` IS NULL
AND b.`campaign_id` IN (
SELECT `id` FROM `campaigns` WHERE `status`=true
)
GROUP BY b.`campaign_id`
) AS c ON a.id = c.bid
SET a.`crawler_id` = 'test'
limit 1;
Why you are using group by withou ana aggregation function
if you want just a row for each b.campaign_id use some aggregation function for avoid unpredictable result for others column value and error with the most recente version of db
a proper aggregation function could avoid the needs for order by and limit 1
and for performance you could avoid the IN clause for a subquery and use inner join this produce the same result but is more fast
UPDATE `backlinks` as a
JOIN(
SELECT min(b.`id`) as bid
FROM `backlinks` b
INNER JOIN (
SELECT `id`
FROM `campaigns`
WHERE `status`=true
) t1 on t1.id = b.`campaign_id`
WHERE b.`googlebot_id` IS NULL
AND b.`used_time` IS NULL
GROUP BY b.`campaign_id`
) AS c ON a.id = c.bid
SET a.`crawler_id` = 'test'
limit 1;
Anyway if you are using mysql version prevoius then 5.7 you can use group by without aggreation function .. and order by .. but .. both of that have an impact on performance
UPDATE `backlinks` as a
JOIN(
SELECT b.`id` as bid
FROM `backlinks` b
INNER JOIN (
SELECT `id`
FROM `campaigns`
WHERE `status`=true
) t1 on t1.id = b.`campaign_id`
WHERE b.`googlebot_id` IS NULL
AND b.`used_time` IS NULL
GROUP BY b.`campaign_id`
) AS c ON a.id = c.bid
SET a.`crawler_id` = 'test'
limit 1;
the uniques way for improve performance is related to the use of join instead of IN clause and a proper index on table backlinks columns campaign_id
you could try using order by rand and limit outside the subquery but inside a proper outer subquery and join the result for the update
UPDATE `backlinks` as a
INNER JOIN (
select a1.id
from backlinks as a1
INNER JOIN (
SELECT b.`id` as bid
FROM `backlinks` b
INNER JOIN (
SELECT `id`
FROM `campaigns`
WHERE `status`=true
) t1 on t1.id = b.`campaign_id`
WHERE b.`googlebot_id` IS NULL
AND b.`used_time` IS NULL
GROUP BY b.`campaign_id`
) AS c ON a1.id = c.bid
ORDER BY rand()
limit 1
) t on t.id = a.id

Multiple select queries in WHERE IN statement

I have the following sql query :
SELECT `main_table`.* FROM `prd_brand` AS `main_table`
INNER JOIN
(SELECT DISTINCT value from catalog_product_entity_int where row_id in
(select row_id from catalog_product_entity_int where attribute_id = 97 and value = 1) ,
(select row_id from catalog_product_entity_int where attribute_id = 99 and value = 4)) t
ON main_table.brand_id = t.value
Is that possible to add multiple select queries in the WHERE IN statement.
BTW, when executing the query I have #1248 - Every derived table must have its own alias.
I'm not quite sure what your query is trying to do. But this seems like a simpler way to write the logic:
SELECT b.*
FROM `prd_brand` AS b INNER JOIN
(SELECT DISTINCT value
FROM catalog_product_entity_int
WHERE (attribute_id, value) IN ( (97, 1), (99, 4) )
) t
ON b.brand_id = t.value

MYSQL Incorrect usage of UPDATE and ORDER BY RAND

I am trying to update with JOIN and RAND
UPDATE table1 a INNER JOIN table2 b USING(id)
SET a.description = CONCAT('different words', b.name)
WHERE a.description LIKE ''
ORDER BY RAND() LIMIT 100;
I get the error : Incorrect usage of UPDATE and ORDER BY
without JOIN the following code works perfectly
UPDATE table1 SET description = CONCAT('different words', name)
WHERE description LIKE ''
ORDER BY RAND() LIMIT 100;
thanks for helping
Try this:
UPDATE a
SET a.description = CONCAT('different words', b.name)
FROM table1 a
INNER JOIN table2 b ON a.id=b.id
WHERE a.description LIKE ''
ORDER BY RAND() LIMIT 100;
Assuming you're using mysql, you should wrap your query that's working (with the user variable and the order by) as an inline view (MySQL calls it a derived table). Reference that whole view as a row source in the UPDATE statement. So your query should be something like this:
UPDATE table1 a
INNER JOIN (
--query
) as someName
SET a.description = CONCAT('different words', b.name)

How to use JOINS instead of sub query

SELECT *
FROM table_a
LEFT JOIN table_b ON (table_b.id = table_a.id)
WHERE table_b.created BETWEEN ? AND ?
AND table_b.manager IN(
SELECT DISTINCT (b.id)
FROM table_b a
INNER JOIN table_b b ON a.manager = b.id
AND b.user_level > 0
AND b.id != 1
)
How can I remove the sub query and use JOINS instead in the above query
Thanks
MySQL 5.5 (and lower version)'s optimizer produces a DEPENDENT SUBQUERY for IN (SELECT ...) which means every matching row is found, IN(SELECT ...) is evaluated that makes select slow.
Simple optimization of your query is make inline view as follows:
SELECT *
FROM table_a LEFT JOIN table_b ON (table_b.id = table_a.id)
INNER JOIN (
SELECT DISTINCT b.id AS id
FROM table_b a
INNER JOIN table_b b ON a.manager = b.id
AND b.user_level > 0
AND b.id != 1
) x ON table_b.manager = x.id
WHERE table_b.created BETWEEN ? AND ?
AND x.id IS NOT NULL;
I think avobe query would produce as same as your own.
Last, DISTINCT is not a function. please use SELECT DISTINCT b.id rather SELECT DISTINCT (b.id)

SQL select the last 3 dates from a table

I have a table with lots of fields in mysql
I need a query to return (in the same raw!) the top last 3 dates (dates can have large gaps between them)
ie:
2012/01/20
2012/01/18
2012/01/12
2012/01/10
2012/01/04
etc...
Any help will be appreciated
I must get them in the same row!
This is the query I am trying to use with no success:
SELECT a.id, a.thedate, b.id AS id1, b.thedate AS thedate1, c.id AS id2, c.thedate as thedate2
FROM mytable AS a INNER JOIN mytable AS b ON a.id = b.id INNER JOIN mytable AS c ON b.id=c.id
WHERE c.thedate = SELECT MAX(thedate)
EDIT :
SELECT group_concat(date) FROM (SELECT date FROM my_table ORDER BY date DESC LIMIT 3) AS temp
Corrected-
SELECT group_concat(date) FROM ( select date from table_name order by date desc limit 3) as a
SELECT GROUP_CONCAT(a.date )
FROM (
SELECT date
FROM my_table
ORDER BY date DESC
LIMIT 3
) AS a