SQL Subquery: Column not found - mysql

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

Related

How to acces outer column in mysql subquery?

i have query
SELECT t1.account AS main, t1.id, tmp.* FROM account.account t1 LEFT JOIN
(
SELECT
tmp1.account,
tmp1.lot - tmp2.lot AS nett
FROM
( SELECT account, SUM( lot ) AS lot
FROM orders WHERE market_date = "2020-07-20"
AND `transaction` = 1 AND account = t1.id ) AS
tmp1
LEFT JOIN ( SELECT account, SUM( lot ) AS lot
FROM orders WHERE market_date = "2020-07-20"
AND `transaction` = 2 AND account = t1.id ) AS
tmp2 ON tmp1.account = tmp2.account
) tmp ON tmp.account = t1.id;
and the result is
1054 - Unknown column 't1.id' in 'where clause', Time: 0.001000s
how to access t1.id current subquery select ?
You may try just using a join to a single level subquery on orders:
SELECT
a.account AS main,
a.id,
COALESCE(o.nett, 0) AS nett
FROM account a
LEFT JOIN
(
SELECT
account,
SUM(CASE WHEN `transaction` = 1 THEN lot END) -
SUM(CASE WHEN `transaction` = 2 THEN lot END) AS nett
FROM orders
WHERE market_date = '2020-07-20'
GROUP BY account
) o
ON o.account = a.account;

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

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

MySQL Subquery SUM Limit

I'm trying to do an subquery with SUM() and LIMIT. This works fine with the following code:
SELECT id,
(
SELECT SUM(number)
FROM (
SELECT number
FROM t2
WHERE u_id = '1'
ORDER BY time ASC
LIMIT 30
) AS temp
) AS test
FROM t1
But I want to do it of course dynamically and with the current row ID.
I changed the Query to the following:
SELECT id,
(
SELECT SUM(number)
FROM (
SELECT number
FROM t2
WHERE u_id = p.id
ORDER BY time ASC
LIMIT 30
) AS temp
) AS test
FROM t1 p
This will give the following error:
Unknown column 'p.id' in 'where clause'
Any ideas how to make it working?
Unfortunately, MySQL limits the scope of table aliases. Oracle is another database that does this.
You can phrase your query as a complicated join:
select t1.id, sum(t2.number)
from t1 p join
t2
on p.id = t2.u_id
where 30 >= (select count(*)
from t2 t22
where t22.u_id = t2.u_id and
t22.time <= t2.time
)
group by t1.id;
Or you can do this with variables:
select p.id, sum(number)
from t1 p join
(select t2.*,
#rn := if(#u = t2.u_id, #rn + 1, if((#u := t2.u_id) is not null, 1, 0)) as rn
from t2
(select #u := 0, #rn := 0) vars
order by t2.u_d, time
) t2
on p.id = t2.u_id
where rn <= 30
group by p.id;
why not just change p.id to t1.id? I'm pretty sure it's because you are aliasing t1 in the first select, and it isn't defined in the subquery. Try an inner join instead.
SELECT id,
(
SELECT SUM(number)
FROM (
SELECT number
FROM t2
INNER JOIN t1 p
on u_id = p.id
ORDER BY time ASC
LIMIT 30
) AS temp
) AS test
FROM t1 p
Try this:
SELECT id, temp2.sum_number as test
FROM t1 p
INNER JOIN
(
SELECT SUM(number) as sum_number, temp.u_id
FROM (
SELECT number, u_id
FROM t2
WHERE u_id = p.id
ORDER BY time ASC
LIMIT 30
) AS temp
) AS temp2 ON temp2.u_id = p.id
I moved subqueries in the join part, so i can access to p.id in the subquery.

Selecting rows having more than one connection to another two tables

Let's say I have three tables:
table `customers` with columns `id`,`name`
table `contracts` with columns `id`, `customer_id`, `text`
table `phones` with columns `id`, customer_id`, `number`
I'd like to select customers which has more than 1 contracts AND more than one phone numbers. I tried to do the folowing:
SELECT * FROM `customers`
WHERE
(SELECT count(*) FROM `contracts` WHERE `customer_id` = `id`) > 1
AND
(SELECT count(*) FROM `phones` WHERE `customer_id` = `id`) > 1
But it produces error #1054 - Unknown column 'customer_id' in 'where clause'
Please try the following query:
SELECT customers.* FROM customers
INNER JOIN
(
SELECT customer_id, count(*) AS count FROM contracts GROUP BY customer_id
HAVING count > 1
) AS contracts
ON customers.id = contracts.customer_id
INNER JOIN
(
SELECT customer_id, count(*) AS count FROM phones GROUP BY customer_id
HAVING count > 1
) AS phones
ON customers.id = phones.customer_id
try this one
SELECT a.id,a.name , COUNT(b.id) AS no_of_contracts
FROM
customers a JOIN contracts b ON a.id = b.customer_id
GROUP BY a.id HAVING no_of_contracts > 1