How to acces outer column in mysql subquery? - mysql

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;

Related

MySQL problem joining 2 tables with UNION

I'm doing UNION in MySQL that I'm unable to troubleshoot for a while.
Error says that
syntax is incorrect around t1.*
Those 2 SELECTs work ok separately, checked. But UNION fails. I'm not custom to MySQL syntax, maybe something is wrong with that.
SELECT (
t1.*,
a.region_count
FROM
(
SELECT
data_region,
COUNT(*) AS region_count
FROM
t2
GROUP BY
data_region
) AS a
LEFT OUTER JOIN
t1
ON
t1.values_att0 = a.data_region
WHERE
t1.name_0 = 'region'
) AS b
UNION
SELECT (
t1.*,
c.age_gen_count
FROM
(
SELECT
data_dage,
data_gen,
COUNT(*) AS age_gen_count
FROM
t2
GROUP BY
data_dage,
data_gen
) AS c
LEFT JOIN
t1
ON
t1.values_att0 = c.data_dage AND
t1.id_question_1 = c.data_gen
WHERE
t1.name_0 = 'age' AND
t1.q_name_1 = 'gen'
)
You are using parenthesis around your SELECT field, this is your syntax error origin (the UNION is not the cause). Just remove them:
SELECT
t1.*,
a.region_count
FROM
(
SELECT
data_region,
COUNT(*) AS region_count
FROM t2
GROUP BY data_region
) AS a
LEFT OUTER JOIN t1
ON t1.values_att0 = a.data_region
WHERE t1.name_0 = 'region'
UNION ALL
SELECT
t1.*,
c.age_gen_count
FROM
(
SELECT
data_dage,
data_gen,
COUNT(*) AS age_gen_count
FROM t2
GROUP BY data_dage, data_gen
) AS c
LEFT JOIN t1
ON t1.values_att0 = c.data_dage
AND t1.id_question_1 = c.data_gen
WHERE t1.name_0 = 'age'
AND t1.q_name_1 = 'gen'

How to use 'group by' while having a sub query in MySQL?

I have the following query:
SELECT c.text1, sum(c.num1), sum(c.num2), sum(c.num3),
(SELECT count(id) FROM table2 WHERE type = 1 AND txt = c.text1 AND spec_id = c.sp_id)
FROM table1 as c
WHERE c.type = 1
GROUP BY c.text1, c.sp_id
Is there a workaround to loose the c.sp_id from the GroupBy clause somehow? I know that if I remove it MySQL will return an error.
Or is there a way to group the results of this query by c.text1 only?
If I understand the problem correctly, you need to do two separate aggregations. This is one version of the query:
SELECT c.text1, c.sum1, c.sum2, c.sum3, t2.cnt
FROM (SELECT c.text1, sum(c.num1) as sum1, sum(c.num2) as cum2, sum(c.num3) as sum3
FROM table1 c
GROUP BY c.text1
) c LEFT JOIN
(SELECT txt, count(*) as cnt
FROM table2 t2
WHERE t2.type = 1 AND
EXISTS (SELECT 1
FROM table1 c2
WHERE t.txt = c2.txt AND c2.type = 1 AND
t.spec_id = c2.sp_id
)
) t2
ON t2.txt = c.text1
WHERE c.type = 1;

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.

How to ignore WHERE IN clause if subquery did not find junctions?

I'm selecting transactions from a table using the following query:
SELECT t.*
FROM transactions AS t
WHERE t.id IN
(
SELECT t2.id
FROM `virtual_account-account` AS vaa
LEFT JOIN transactions AS t2
ON t2.account = vaa.account
WHERE vaa.virtual_account = 3
)
AND t.id IN
(
SELECT tt.transaction
FROM `virtual_account-tag` AS vat
LEFT JOIN `transaction-tag` AS tt
ON tt.tag = vat.tag
WHERE vat.virtual_account = 3
)
ORDER BY t.date
However, I'd like to modify this such that if, e.g., the junction table virtual_account-account does not contain any junctions where vaa.virtual_account = 3, then the corresponding t.id IN (...) condition should be ignored. Thus far, I've failed to find a solution for this so any help would be highly appreciated.
Just an OR between both conditions:
SELECT t.*
FROM transactions AS t
WHERE t.id IN
(
SELECT t2.id
FROM `virtual_account-account` AS vaa
LEFT JOIN transactions AS t2
ON t2.account = vaa.account
WHERE vaa.virtual_account = 3
)
OR t.id IN
(
SELECT tt.transaction
FROM `virtual_account-tag` AS vat
LEFT JOIN `transaction-tag` AS tt
ON tt.tag = vat.tag
WHERE vat.virtual_account = 3
)
ORDER BY t.date
If one is returning nothing, it will still return the other transactions.
The following approach turns the subquery into a join and uses a variable to count the number of rows in the subquery. The where clause then uses this variable for the logic you want:
SELECT t.*
FROM transactions t left outer join
(SELECT t2.id, #cnt := #cnt + 1
FROM `virtual_account-account` AS vaa
LEFT JOIN transactions AS t2
ON t2.account = vaa.account cross join
(select #cnt := 0)
WHERE vaa.virtual_account = 3
group by t2.id
) c1
on c1.id = t.id
WHERE (c1.id is not null or #cnt = 0) and
t.id IN (SELECT tt.transaction
FROM `virtual_account-tag` AS vat
LEFT JOIN `transaction-tag` AS tt
ON tt.tag = vat.tag
WHERE vat.virtual_account = 3
)
ORDER BY t.date;
Note that the subquery eliminates duplicates (uses group by). Otherwise, you might have the problem of multiple matches resulting in multiple rows.
A bit clumsy and verbose, but...
SELECT t.*
FROM transactions AS t
WHERE t.id IN
(
SELECT t2.id
FROM `virtual_account-account` AS vaa
LEFT JOIN transactions AS t2
ON t2.account = vaa.account
WHERE vaa.virtual_account = 3
)
AND t.id IN
(
SELECT tt.transaction
FROM `virtual_account-tag` AS vat
LEFT JOIN `transaction-tag` AS tt
ON tt.tag = vat.tag
WHERE vat.virtual_account = 3
AND EXISTS
(
SELECT t2.id
FROM `virtual_account-account` AS vaa
LEFT JOIN transactions AS t2
ON t2.account = vaa.account
WHERE vaa.virtual_account = 3
)
)
ORDER BY t.date
Try:
SELECT t.*
FROM (select count(*) vaa
FROM `virtual_account-account`
WHERE virtual_account = 3) a
CROSS JOIN (select count(*) vat
FROM `virtual_account-tag`
WHERE virtual_account = 3) g
CROSS JOIN transactions AS t
LEFT JOIN `virtual_account-account` vaa
ON t.id = vaa.id AND vaa.virtual_account = 3
LEFT JOIN `virtual_account-tag` vat
JOIN `transaction-tag` tt ON tt.tag = vat.tag
ON t.id = tt.transaction AND vat.virtual_account = 3
WHERE (a.vaa = 0 OR vaa.id IS NOT NULL) AND
(g.vat = 0 OR vat.tag IS NOT NULL)
GROUP BY t.id
ORDER BY t.date

How to optimise below sql query?

What I'm doing here is getting the reservations and the user which are duplicate. Here reservation ticket can not be printed twice. If a user prints a ticket tracker table updates with that record. If a user prints the same ticket twice it's marked as a duplicate. What subquery does here is return some reservation ids which are marked as duplicates.
SELECT t1.id AS res_id,
t1.tx_id,
t1.tx_date,
t1.bx_date,
t1.method,
t1.theater_id,
t1.showtime_id,
t1.category_id,
t1.amount,
t1.fname,
t1.status,
t1.mobile,
u.username,
t2.*
FROM `reservation` AS t1
INNER JOIN
( SELECT *
FROM `tracker`
WHERE reservation_id IN
( SELECT reservation_id
FROM `tracker`
GROUP BY reservation_id HAVING ( METHOD = 1
AND TYPE = 0
AND COUNT(*) > 1 )
OR ( METHOD = 1
AND TYPE = 1
AND COUNT(*) > 1 )
OR ( METHOD = 2
AND TYPE = 2
AND COUNT(*) > 0 )
OR ( METHOD = 3
AND TYPE = 0
AND COUNT(*) > 0 )
OR ( METHOD = 3
AND TYPE = 1
AND COUNT(*) > 1 )
OR ( METHOD = 3
AND TYPE = 3
AND COUNT(*) > 0 )) ) AS t2 ON t1.id = t2.reservation_id
INNER JOIN `users` AS u ON u.id = t2.user_id
WHERE t2.resolved = 0
AND t2.duplicate = 1
ORDER BY t2.issue_date DESC, t1.id DESC
EXPLAIN Command of the above query.
What should I do? If I'm index which keys should I use? How can I decide which keys to index? I know subquery slows me down What procedures should I follow to eliminate the slowness?
In MySQL, exists subqueries are often faster than in subqueries. You might try:
SELECT t1.id AS res_id, t1.tx_id, t1.tx_date, t1.bx_date,t1.method, t1.theater_id, t1.showtime_id,
t1.category_id, t1.amount, t1.fname, t1.status, t1.mobile, u.username, t2.*
FROM `reservation` t1 INNER JOIN
(SELECT *
FROM `tracker` t
WHERE EXISTS (SELECT 1
FROM `tracker` t3
where t3.reservation_id = t.reservation_id
GROUP BY reservation_id
HAVING (METHOD = 1 AND TYPE = 0 AND COUNT(*) > 1) OR
(METHOD = 1 AND TYPE = 1 AND COUNT(*) > 1) OR
(METHOD = 2 AND TYPE = 2 AND COUNT(*) > 0) OR
(METHOD = 3 AND TYPE = 0 AND COUNT(*) > 0) OR
(METHOD = 3 AND TYPE = 1 AND COUNT(*) > 1) OR
(METHOD = 3 AND TYPE = 3 AND COUNT(*) > 0)
)
) t2
ON t1.id = t2.reservation_id INNER JOIN
`users` AS u ON u.id = t2.user_id
WHERE t2.resolved = 0 AND t2.duplicate = 1
ORDER BY t2.issue_date DESC, t1.id DESC
I notice the subquery is using Hidden Columns in the having clause. It may not be doing what you expect. Normally, the query would include method and type in the group by clause or have an expression such as max(Method).