Mysql using variable in select - mysql

I have a rather involved query because I'm trying to keep the math out of the application code and in the query. I am trying to set a variable in the select and then re-use it in the same select. Unfortunately, any of my columns where I use these variables is returning null where there should be data. Everything else is working fine.
SELECT #signups:= COUNT(registrations.id) as signups,
#registrations:= SUM(IF(registrations.fees_paid_by_users = '1', registrations.amount - registrations.databar_fees - registrations.taxes - registrations.extras_price + registrations.discount_total, registrations.amount - registrations.taxes - registrations.extras_price + registrations.discount_total)) as registrations,
#activities:= SUM(registrations.extras_price) as activities,
#coupons:= SUM(discount_total) as coupons,
#subtotal:= #registrations + #activities - #coupons as subtotal,
#fees_not_paid_by_user:= SUM(IF(registrations.fees_paid_by_users = '0', registrations.databar_fees, 0)) as fees_not_paid_by_user,
#taxes:= SUM(registrations.taxes) as taxes,
#total_including_taxes:= #subtotal - #fees_not_paid_by_user + #taxes as total_including_taxes,
events.name,
event_forms.title ,
event_forms.id,
CONCAT(users.first_name, ' ', users.last_name) as user_name
FROM registrations,
events,
event_forms,
transactions,
users
WHERE transactions.date >= '2013-09-01 00:00:00'
AND transactions.date <= '2013-09-30 23:59:59'
AND registrations.transaction_id = transactions.id
AND registrations.event_forms_id = event_forms.id
AND event_forms.event_id = events.id
AND events.owner_id = users.id
GROUP BY registrations.event_forms_id
ORDER BY user_name ASC, name ASC, title ASC
In the above query, the subtotal and the total_including_taxes columns are returning null, I'm assuming because the query cannot access the previously defined variables.
This is my first time really using MySQL's user variables (I'm a developer, not a DBA) and I'm unsure if I'm doing something wrong and if so, how to fix it. I can do the math in the code if I need to, but I would really like to keep it on the database server as it is much beefier than the app server and can handle this easier.

Given your query, you're doing SUM(SUM(...)). SUM's intended for adding together field values, and I kind of doubt that variables will do the same thing e.g..
SELECT ..
#foo := SUM(...),
#bar := SUM(#foo)
might as well just be
#bar := #bar + #foo

Unfortunately, the previous variables in the query are undefined. You'll have either to substitute the formulas instead of them. Or to the next variables calculate in the code.

Related

SQL if query functionality

I want to write a query to determine the success rate for every day for each different mode. I did write a query that'll just group by date and mode which serves my purpose but one of my seniors wrote this following query which also works but I am just unable to understand how the if clause is working. I'll add a bit of the query here -
SELECT
dt,
sum(if(mode='A',success,0))AS a_s,
sum(if(mode='A',total,0))AS a_t,
sum(if(mode='B',success,0))AS b_s,
sum(if(mode='B',total,0))AS b_t,
sum(if(mode='C',success,0))AS c_s,
sum(if(mode='C',total,0))AS c_t,
sum(if(mode='D',success,0))AS d_s,
sum(if(mode='D',total,0))AS d_t,
sum(if(mode NOT in('A','B','C','D'),success,0))AS other_s,
sum(if(mode NOT in('A','B','C','D'),total,0))AS other_t
FROM
(SELECT
mode,
date(addedon)AS dt,
sum(if(status in('success','partial'),1,0))AS success,
count(*)AS total
FROM `a_huge_ass_table`
WHERE `studentid`=159633 AND addedon>'2021-01-15'
GROUP BY mode,date(addedon)
)AS t
Here I am unable to understand how sum(if(mode='A',success,0))AS a_s, - this if clause is working. If the condition is true then the clause is returning success? how does that work does adding success also somehow verify that its status is a success case? I cant find this on google.
First, if() is not standard SQL. I recommend rewrite this using case:
sum(case when mode = 'A' then success else 0 end) as a_s,
sum(case when mode = 'A' then total else 0 end) as a_t,
and so on.
Second, this query is missing the final group by dt. Otherwise it produces one row, rather than a separate row for each dt value.
This is called conditional aggregation. Every row in the final result set represents a group of rows from the subquery. Within this group, some have mode = 'A' and some do not. For the ones with mode = 'A' the above sums the value of success and total.
There is no need for a subquery by the way. That just slows down the query. I would recommend writing the query as:
SELECT date(addedon) as dt
SUM( mode = 'A' AND status IN ('success', 'partial') ) as a_success,
SUM( mode = 'A' ) as a_total,
. . .
FROM `a_huge_ass_table`
WHERE studentid = 159633 AND addedon >= '2021-01-15'
GROUP BY date(addedon);
Note that this uses a MySQL extension where boolean expressions are treated as integers, with "1" for true and "0" for false.

SUM inside SUM SQL Invalid use of group function

Hi I want to perform a calculation inside a SUM with my sql, but there is one SUM field that consist of other SUM fields. I get the General error: 1111 Invalid use of group function. What is the proper way of summing other sum fields in SQL?
I can't use the alias of other sum fields to perform the calculation because it says that the alias is unidentified.
This part is my problem
SUM((SUM(transactions.payable) + SUM(transactions.discount) ) - SUM(deliveries.delivery_fee) ) AS raw_sales
Thank you
Here is my SQL.
SELECT
MONTHNAME(transactions.date_transac) AS MONTH,
SUM(transactions.payable) AS total,
SUM(transactions.discount) AS discount,
SUM(deliveries.delivery_fee) AS delivery,
SUM(
(
SUM(transactions.payable) + SUM(transactions.discount)
) - SUM(deliveries.delivery_fee)
) AS raw_sales,
MONTH(transactions.date_transac) AS monthnum
FROM
`transactions`
LEFT JOIN `requisitions` ON `transactions`.`requisition_id` = `requisitions`.`id`
LEFT JOIN `transactions` AS `ct`
ON
`transactions`.`code` = `ct`.`charge_transaction_code`
LEFT JOIN `deliveries` ON `transactions`.`delivery_id` = `deliveries`.`id`
WHERE
`transactions`.`transaction_type` = Sale AND YEAR(`transactions`.`date_transac`) = 2020
GROUP BY
`month`
ORDER BY
`monthnum` ASC
enter image description here
You can't nest aggregate functions. Here, I suspect that you could move the arithmetics within the aggregate function rather than attempting to nest:
SUM(
transactions.payable
+ transactions.discount
- COALESCE(deliveries.delivery_fee, 0)
) AS raw_sales
delivery_fee comes from a left join table so it could be null, hence we use coalesce().
That said, I am quite suspicious about the logic of your query. I am wondering, for example, why transactions appears twice in the from clause. There are also missing quotes around literal string "Sale" in the WHERE clause. If you were to ask a legitimate question, including sample data, desired results, and an explanation of the purpose of the query, one might be able to suggests optimizations.
The query just worked, I haven't realized that it is no longer necessary to calculate all Sum fields. I just removed the external sum.

SQL: Something wrong with inheriting variables for NULL next-row values

I'm trying to inherit value from previous row (based on correct subscription_id + checking for IS NULL subscription_status), but something goes wrong and I get incorrect value.
Take a look at screenshot.
If I'm not mistaken it also called last non-null puzzle, but examples of possible solution for other DB provide window function with IGNORE NULLS.
But, I'm using MySQL 8.x and it doesn't support this function.
I'm sorry, but SQL fiddle doesn't provide correct text-value for variables in my code :(
https://www.db-fiddle.com/f/wHanqoSCHKJHus5u6BU4DB/4
Or, you can see mistakes here:
SET #history_subscription_status = NULL;
SET #history_subscription_id = 0;
SELECT
c.date,
c.user_id,
c.subscription_id,
sd.subscription_status,
(#history_subscription_id := c.subscription_id) as 'historical_sub_id',
(#history_subscription_status := CASE
WHEN #history_subscription_id = c.subscription_id AND sd.subscription_status IS NULL
THEN #history_subscription_status
ELSE
sd.subscription_status
END
) as 'historical'
FROM
calendar c
LEFT JOIN
subscription_data sd ON sd.date = c.date AND sd.user_id = c.user_id AND sd.subscription_id = c.subscription_id
ORDER BY
c.user_id,
c.subscription_id,
c.date
I expect to get results for this query in this way:
IMPORTANT: I'm going to use this code for a lot of data (about 1 mln rows), so it very important for me to avoid additional select or subquery that can slow down the execution of the query.

mysql Query performance is low

I have a query which is running for around 2 hours in last few days. But
before that it took only 2 to 3 minutes of time. i could not able to find
the reason for its sudden slowness. Can any one help me on this?
Please find the below query explain plan[![enter image description here][1]]
[1]...
select
IFNULL(EMAIL,'') as EMAIL,
IFNULL(SITE_CD,'') as SITE_CD,
IFNULL(OPT_TYPE_CD,'') as OPT_TYPE_CD,
IFNULL(OPT_IN_IND,'') as OPT_IN_IND,
IFNULL(EVENT_TSP,'') as EVENT_TSP,
IFNULL(APPLICATION,'') as APPLICATION
from (
SELECT newsletter_entry.email email,
newsletter.site_cd site_cd,
REPLACE (newsletter.TYPE, 'OPTIN_','') opt_type_cd,
CASE
WHEN newsletter_event_temp.post_status = 'SUBSCRIBED' THEN 'Y'
WHEN newsletter_event_temp.post_status = 'UNSUBSCRIBED' THEN
'N'
ELSE ''
END
opt_in_ind,
newsletter_event_temp.event_date event_tsp,
entry_context.application application
FROM amg_toolkit.newsletter_entry,
amg_toolkit.newsletter,
(select NEWSLETTER_EVENT.* from amg_toolkit.NEWSLETTER_EVENT,
amg_toolkit.entry_context where newsletter_event.EVENT_DATE >= '2017-07-11
00:01:23' AND newsletter_event.EVENT_DATE < '2017-07-11 01:01:23' and
newsletter_event.ENTRY_CONTEXT_ID = entry_context.ENTRY_CONTEXT_ID and
entry_context.APPLICATION != 'feedbackloop') newsletter_event_temp,
amg_toolkit.entry_context
WHERE newsletter_entry.newsletter_id = newsletter.newsletter_id
AND newsletter_entry.newsletter_entry_id =
newsletter_event_temp.newsletter_entry_id
AND newsletter.TYPE IN ('OPTIN_PRIM', 'OPTIN_THRD', 'OPTIN_WRLS')
AND newsletter_event_temp.entry_context_id NOT IN
(select d.ENTRY_CONTEXT_ID from amg_toolkit.sweepstake a,
amg_toolkit.sweepstake_entry b, amg_toolkit.user_entry c,
amg_toolkit.entry_context d where a.exclude_data = 'Y' and
a.sweepstake_id=b.sweepstake_id and b.USER_ENTRY_ID=c.USER_ENTRY_ID and
c.ENTRY_CONTEXT_ID = d.ENTRY_CONTEXT_ID)
AND newsletter_event_temp.entry_context_id =
entry_context.entry_context_id
AND newsletter_event_temp.event_date >= '2017-07-11 00:01:23'
AND newsletter_event_temp.event_date < '2017-07-11 01:01:23') a;`
[1]: https://i.stack.imgur.com/cgsS1.png
dont use .*
select only the columns of data you are using in your query.
Avoid nested sub selects if you dont need them.
I don't see a need for them in this query. You query the data 3 times this way instead of just once.
Slowness can be explained by an inefficient query haveing to deal with tables that have a growing number of records.
"Not in" is resource intensive. Can you do that in a better way avoiding "not in" logic?
JOINs are usually faster than subqueries. NOT IN ( SELECT ... ) can usually be turned into LEFT JOIN ... WHERE id IS NULL.
What is the a in a.exclude_data? Looks like a syntax error.
These indexes are likely to help:
newsletter_event: INDEX(ENTRY_CONTEXT_ID, EVENT_DATE) -- in this order
You also need it for newsetter_event_temp, but since that is not possible, something has to give. What version of MySQL are you running? Perhaps you could actually CREATE TEMPORARY TABLE and ADD INDEX.

Auto Incremental serial number for MySQL View

Having a issue with my project need to insert an auto incremental value for my MySQL view, I would be nice if you guys help in solving this obstacle, Here is the code in which I wanna have auto incremental serial number (say S.No) as the first column.
CREATE
ALGORITHM = UNDEFINED
DEFINER = `srems_admin`#`localhost`
SQL SECURITY DEFINER
VIEW `emp_elec_consumption_view` AS
SELECT
`t1`.`PFNUMBER` AS `PFNUMBER`,
`emp`.`EMPNAME` AS `EMPNAME`,
`t1`.`MonthAndYear` AS `MonthAndYear`,
`qt`.`QTRSCODE` AS `QTRSCODE`,
`t1`.`UNITS_CONSUMED` AS `UNITS_CONSUMED`,
(`t2`.`FIXED_COMPONENT` + (`t1`.`UNITS_CONSUMED` * `t2`.`RATE_COMPONENT`)) AS `Amount`
FROM
(((`srems`.`mstqtroccu` `qt`
JOIN `srems`.`mstemp` `emp`)
JOIN `srems`.`msttariffrate` `t2`)
JOIN (SELECT
`srems`.`tranmeterreading`.`PFNUMBER` AS `PFNUMBER`,
(`srems`.`tranmeterreading`.`CLOSINGREADING` - `srems`.`tranmeterreading`.`OPENINGREADING`) AS `UNITS_CONSUMED`,
CONCAT(CONVERT( IF((LENGTH(MONTH(`srems`.`tranmeterreading`.`READINGDATE`)) > 1), MONTH(`srems`.`tranmeterreading`.`READINGDATE`), CONCAT('0', MONTH(`srems`.`tranmeterreading`.`READINGDATE`))) USING UTF8), '/', RIGHT(YEAR(`srems`.`tranmeterreading`.`READINGDATE`), 2)) AS `MonthAndYear`,
(SELECT
`t`.`TRANSACTIONID`
FROM
`srems`.`msttariffrate` `t`
WHERE
(`t`.`TORANGE` > (`srems`.`tranmeterreading`.`CLOSINGREADING` - `srems`.`tranmeterreading`.`OPENINGREADING`))
LIMIT 1) AS `tariffplanid`
FROM
`srems`.`tranmeterreading`) `t1`)
WHERE
((`t1`.`tariffplanid` = `t2`.`TRANSACTIONID`)
AND (`t1`.`PFNUMBER` = `qt`.`PFNUMBER`)
AND (`t1`.`PFNUMBER` = `emp`.`PFNUMBER`))
Pls insert the things at the correct place and post it as an comment to get S.No which should be auto-incremental starting from 1 and also it should be the first column, ty in advance
Your view has no chance of working in MySQL anyway so you might as well give up.
MySQL does not allow subqueries in the FROM clause. And your query is pretty complicated with lots of subqueries.
It also does not allow variables, so getting a row number is rather complicated.