How to ORDER BY a temporary table - mysql

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

Related

Sort MySql query by field in exists sub query

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.

How to remove duplicates from table using join in mysql

select *
from
(
SELECT id, imei1, status
FROM `owarranty_imei` mto
WHERE EXISTS
(
SELECT 1
FROM `owarranty_imei` mti
WHERE mto.imei1=mti.imei1
LIMIT 1, 1
)
) t1
left join `owarranty_warranty_activations` as t2 on t1.id=t2.imei_id
where t2.id is null
limit 100
this is my query. In owarranty_imei has more than 100000 records. i want to get duplicates from imei table which owarranty_imei not in owarranty_warranty_activation table. This query work for few records but when i run it for more than 1000000 records its not working
SELECT
mto.id,
mto.imei1,
mto.status
FROM
`owarranty_imei` mto
INNER JOIN
`owarranty_imei` mti ON mto.imei1=mti.imei1
LEFT JOIN
`owarranty_warranty_activations` as t2 ON mto.id=t2.imei_id
GROUP BY mto.id
HAVING COUNT(t2.id)=0

SQL Subquery: Column not found

I have the following SQL query:
SELECT t1.`userID`,`name`, COUNT( * ) AS `count`, (SELECT `val` FROM `user-data` WHERE `userID` = t1.userID AND `keyID` = 2 LIMIT 1) AS `staff`
FROM `activity` t1
LEFT JOIN `users` ON `users`.`id` = t1.`userID`
WHERE
t1.`userID` <> 0
GROUP BY t1.`userID`
ORDER BY `count` DESC LIMIT 10
Which works, it takes about 2 seconds. But I want to find entries where staff <> 1:
SELECT t1.`userID`,`name`, COUNT( * ) AS `count`, (SELECT `val` FROM `user-data` WHERE `userID` = t1.userID AND `keyID` = 2 LIMIT 1) AS `staff`
FROM `activity` t1
LEFT JOIN `users` ON `users`.`id` = t1.`userID`
WHERE
t1.`userID` <> 0
AND `staff` <> 1
GROUP BY t1.`userID`
ORDER BY `count` DESC LIMIT 10
I get the error: Unknown column 'staff' in 'where clause'
I can put the subquery in the WHERE clause, but then the query takes 70 seconds.
But surely I should be able to access the column i've reference in the SELECT statement?
Since the select list is processed after the where clause, you cannot reference any calculated field in the where clause via its alias.
You can move the subquery into a join, provided it returns a single record only even if there is no limit clause:
SELECT t1.`userID`,`name`, COUNT( * ) AS `count`, `user-data`.`val` as staff
FROM `activity` t1
LEFT JOIN `users` ON `users`.`id` = t1.`userID`
LEFT JOIN `user-data` ON `user-data`.`userID`=t1.userID AND `user-data`.`keyID` = 2
WHERE
t1.`userID` <> 0
AND `user-data`.`val` <> 1
GROUP BY t1.`userID`, `user-data`.`val`
ORDER BY `count` DESC
LIMIT 10

Unique result set with inner join query

SELECT
*
FROM `catalog_webdesign_products` t
INNER JOIN tbl_member_registration t1 ont.userid=t1.fld_loginid
WHERE 1
AND t1.fld_member_category_level<9
AND t.product_img IS NOT NULL
ORDER BY RAND() LIMIT 5
In this query , I need rows with unique userid. I had tried 'group by userid' also but then product_img with null value is coming in result set.
yes you can use GROUP BY userid. but your query looks wrong here
INNER JOIN tbl_member_registration t1 on t.userid=t1.fld_loginid
^------------------------space here
try this
SELECT
*
FROM `catalog_webdesign_products` t
INNER JOIN tbl_member_registration t1 on t.userid=t1.fld_loginid
WHERE t1.fld_member_category_level<9
AND t.product_img IS NOT NULL
group by userid
ORDER BY RAND() LIMIT 5
edit:
SELECT
*
FROM (select * from `catalog_webdesign_products` where product_img IS NOT NULL) t
INNER JOIN tbl_member_registration t1 on t.userid=t1.fld_loginid
WHERE t1.fld_member_category_level<9
group by t.userid
ORDER BY RAND() LIMIT 5
For better performance you should move the condition for t1 into join statement. You problem could be the wrong JOIN condition. Try LEFT JOIN instead of INNER JOIN.
More about joins: http://www.w3schools.com/sql/sql_join.asp
SELECT *
FROM `catalog_webdesign_products` t
LEFT JOIN tbl_member_registration t1
ON (t.userid = t1.fld_loginid AND t1.fld_member_category_level < 9)
WHERE t.product_img IS NOT NULL
GROUP BY t.userid
ORDER BY RAND() LIMIT 5

How do I get this SQL query to output two rows, rather than two fields?

Here is my SQL query, it produces a single result row, with two columns "lower", and "higher". These correspond to the primary keys ("id") of rows in the Rankable table.
The purpose of the query is to select a random pair of Rankable rows, that isn't already present in the Comparison table (which contains all previous pairs).
What I need, however, is for this query to return the two Rankables as rows, not just the Rankable ids as fields in a single row.
This is the current query:
SELECT a.id AS lower, b.id AS higher
FROM Rankable a
INNER JOIN Rankable b on a.id < b.id
WHERE
a.category_id = ? AND b.category_id = ?
AND NOT EXISTS (
SELECT *
FROM Comparison c
WHERE c.lower_id in (a.id, b.id))
AND NOT EXISTS (
SELECT *
FROM Comparison c
WHERE c.higher_id IN (a.id, b.id))
ORDER BY a.id * rand()
LIMIT 1;
I call this MySQL hacking..
select #a as one
from
(
SELECT #a := a.id, #b := b.id
FROM Rankable a
INNER JOIN Rankable b on a.id < b.id
WHERE
a.category_id = ? AND b.category_id = ?
AND NOT EXISTS (
SELECT *
FROM Comparison c
WHERE c.lower_id in (a.id, b.id))
AND NOT EXISTS (
SELECT *
FROM Comparison c
WHERE c.higher_id IN (a.id, b.id))
ORDER BY a.id * rand()
LIMIT 1
) SQ
union all
select #b
To join to the table to get all other columns:
select Rankable.*
from
(
select 1 as Sort, #a as one
from
(
SELECT #a := a.id, #b := b.id
FROM Rankable a
INNER JOIN Rankable b on a.id < b.id
WHERE
a.category_id = ? AND b.category_id = ?
AND NOT EXISTS (
SELECT *
FROM Comparison c
WHERE c.lower_id in (a.id, b.id))
AND NOT EXISTS (
SELECT *
FROM Comparison c
WHERE c.higher_id IN (a.id, b.id))
ORDER BY a.id * rand()
LIMIT 1
) SQ
union all
select 2, #b
) X
INNER JOIN Rankable ON Rankable.Id = X.one
ORDER BY X.Sort
Create 2 queries one for the lower and one for the higher ranks then union them together.
Create a static column with the rank to identify which is which. 'higher' or 'lower as rank
Not pretty but I think this will work:
SELECT * FROM Rankable JOIN (
SELECT a.id AS lower, b.id AS higher
FROM Rankable a
INNER JOIN Rankable b on a.id < b.id
WHERE
a.category_id = ? AND b.category_id = ?
AND NOT EXISTS (
SELECT *
FROM Comparison c
WHERE c.lower_id in (a.id, b.id)
)
AND NOT EXISTS (
SELECT *
FROM Comparison c
WHERE c.higher_id IN (a.id, b.id)
)
ORDER BY a.id * rand()
) AS rank_them
ON (Rankable.id = rank_them.higher OR Rankable.id = rank_them.lower)