Create a generated column in MySql with count - mysql

I am not a database guy, despite this I have created a statement which counts the ids function by the unique group ids from the table as this:
USE farm;
SELECT reg.grpId, COUNT(reg.id) as TOTAL FROM farm.reg group by reg.grpId;
Because I do't want to operate over the NodeJs server I need to know if it is possible to make a generated column as like the below which gives me an error 1064 -SELECT not valid at this position
the statement:
USE farm;
ALTER TABLE reg ADD total INT GENERATED ALWAYS AS(SELECT reg.grpId COUNT(reg.id) FROM farm.reg group by reg.grpId)STORED AFTER grpId;
Thank you!

You can't do what you want with a computed column. I would recommend a view and window functions (available in MySQL 8.0)
create view reg_view as
select r.*, count(*) over(partition by grpId) total
from reg r
In MySQL < 8.0, an option is to join with an aggregate query:
create view reg_view as
select r.*, g.total
from reg r
inner join (select grpId, count(*) total from reg group by grpId) g on g.grpId = r.grpId

Related

MySQL Correlated sub query table name out of scope

This form of my correlated sub query comes up with the error message "Unknown column 'Invoices.TranDate' in 'where clause'"
select InvoiceID, TranDate
, ifnull(TotPayments,0) TotPayments, ifnull(CountPayments,0) CountPayments
from Invoices
left join (select DebtorID, sum(TranAmount) TotPayments, count(*) CountPayments
from CashTrans
where CashTrans.TranDate >= Invoices.TranDate
group by DebtorID) PY on PY.DebtorID = Invoices.DebtorID
Yet this version works
select InvoiceID, TranDate
, (select sum(TranAmount) from CashTrans
where CashTrans.TranDate >= Invoices.TranDate
and CashTrans.DebtorID = Invoices.DebtorID) TotPayments
, (select count(*) from CashTrans
where CashTrans.TranDate >= Invoices.TranDate
and CashTrans.DebtorID = Invoices.DebtorID) CountPayments
from Invoices;
What is wrong with the first query? The only thing I can think of is that on my Windows system I have configured lower_case_table_names=2 as I want to preserve mixed case names. Perhaps that has something to do with the first query not seeing Invoice.TranDate in scope? MySQL Documentation and internet searches have not thrown any light on the matter.
https://dev.mysql.com/doc/refman/8.0/en/lateral-derived-tables.html says:
A derived table cannot normally refer to (depend on) columns of preceding tables in the same FROM clause. As of MySQL 8.0.14, a derived table may be defined as a lateral derived table to specify that such references are permitted.
In SQL:1999, the query becomes legal if the derived tables are preceded by the LATERAL keyword (which means “this derived table depends on previous tables on its left side”):
I have not tested it, but I believe your query could be written this way:
SELECT InvoiceID, TranDate,
IFNULL(TotPayments,0) AS TotPayments,
ifnull(CountPayments,0) AS CountPayments
FROM Invoices
LEFT JOIN LATERAL (
SELECT DebtorID,
SUM(TranAmount) AS TotPayments,
COUNT(*) AS CountPayments
FROM CashTrans
WHERE CashTrans.TranDate >= Invoices.TranDate
GROUP BY DebtorID
) AS PY ON PY.DebtorID = Invoices.DebtorID;
Also be aware this requires you to use at least MySQL 8.0.14.

How to aggregate SQL query and display result in a different column?

I've a MY-SQL query which is pulling a set of records from database. I want to aggregate slightly different way to use in my application. When duplicate rows present in record set with same ticker value query will sum up est_units and est_trans_value and display in new columns as total_est_units and total_est_trans_value. If there is no duplicate with same ticker value it should display total_est_units as est_units and total_est_trans_value as est_trans_value. How can I do this -- Can you please help to modify this query?
SQL:
SELECT
oc.*
FROM
order_confirm_daily oc
INNER JOIN
(SELECT
id, ticker, MAX(est_order_time) AS mts
FROM
order_confirm_daily
WHERE DATE(est_order_time) LIKE '2021-04-26%'
GROUP BY ticker) ds ON ds.ticker = oc.ticker
AND oc.est_order_time = ds.mts;
Sample Data:
desired results: Added two new derived column "total_est_units" and "Total_est_trans_value" which will display Sum of est_units and est_trans_value respectively only when multiple rows present with same ticker -- here it is "TNA" highlighted in screen shot.
I see. You just want window functions:
select oc.*,
sum(est_units) over (partition by ticker) as total_est_units,
sum(est_trans_value) over (partition by ticker) as total_est_trans_value
from order_confirm_daily oc;
EDIT:
In older versions of MySQL, you would use JOIN and GROUP BY:
select *
from order_confirm_daily oc join
(select ticker, sum(est_units) as total_est_units,
sum(est_trans_value) as total_est_trans_value
from order_confirm_daily oc
group by ticker
) oct
using (ticker);

MySQL 'cant reopen (temporary) table)

Attempting to normalize a column (wgt) by joining to the result of an inline query as follows:
select a.monthEnd, ticker, wgt/totWgt
from hold a
inner join (
select monthEnd, sum(wgt*(1+totRet)) as totWgt
from hold
group by monthEnd ) tot
on a.monthEnd = tot.monthEnd
Get the following error:
Error Code: 1137. Can't reopen table: 'a' 0.00023 sec
I'm coming from SQL Server and not acquainted. What exactly is the issue and/or workaround here? Both tables referenced are temporary tables created within a stored proc and running MySQL 8.0.
Please use WITH clause,
WITH hold as
(SELECT monthEnd, wgt, totWgt , totRet, ticker FROM <actual table>)
select a.monthEnd, ticker, wgt/totWgt
from hold a inner join
(select monthEnd, sum(wgt*(1+totRet)) as totWgt from hold group by monthEnd ) tot
on a.monthEnd = tot.monthEnd;

SQL - Nested query optimization

How can I optimize this query SQL?
CREATE TABLE table1 AS
SELECT * FROM temp
WHERE Birth_Place IN
(SELECT c.DES_COM
FROM tableCom AS c
WHERE c.COD_PROV IS NULL)
ORDER BY Cod, Birth_Date
I think that the problem is the IN clause
First of all it's not quite valid SQL, since you are selecting and sorting by columns that are not part of the group. What you want to do is called "select top N in group", check out Select first row in each GROUP BY group?
Your query doesn't make sense, because you have SELECT * with GROUP BY. Ignoring that, I would recommend writing the query as:
SELECT t.*
FROM temp t
WHERE EXISTS (SELECT 1
FROM tableCom c
WHERE t.Birth_Place = c.DES_COM AND
c.COD_PROV IS NULL
)
ORDER BY Cod, Birth_Date;
For this, I recommend an index on tableCom(desc_com, cod_prov). Your database might also be able to use an an index on temp(cod, birth_date, birthplace).

CTE recursive query in select statement

I have two MySQL server version 8.0, one for local development and another on an Heroku Instance, more precisely on Heroku i'm using a service called JAWSDB.
For my project I have to use the following CTE query, because the structure of the table tree_structure is hierarchical.
The purpose of the query is that for every row in tree_structure I have to get all of its child, and then count how many user in user_roles table are present in that particular row and its child.
SELECT mtr.id,
mtr.parent_id,
mtr.name,
mtr.manager_id,
CONCAT(users.nome, ' ', users.cognome) as resp_name,
(
with recursive cte (id, name, parent_id) as (
select id,
name,
parent_id
from tree_structure as tr_rec
where tr_rec.parent_id = mtr.id
and tr_rec.session_id = '2018'
union all
select tr.id,
tr.name,
tr.parent_id
from tree_structure as tr
inner join cte
on tr.parent_id = cte.id
WHERE tr.session_id = '2018'
)
select count(distinct (user_id))
from user_roles as ur_count
where ur_count.structure_id in (select distinct(id) from cte)
) as utenti
FROM tree_structure as mtr
LEFT JOIN users ON mtr.manager_id = users.id
WHERE level = 0
The problems is that on my local server it works whereas on the heroku instance it gaves me the following error:
unknow columns mtr.id in where clause.
Has someone any ideas of what is causing this error?
Thanks in advance and sorry for my bad english.
You have an ambiguous table reference in the CTE:
SELECT
....
(with recursive cte (id, name, parent_id) as (
....
from tree_structure as tr_rec -- here you have aliased the table
where tr_rec.id = tree_structure.id -- here you refer to the table and its alias
and tr_rec.session_id = '2018'
union all
....
)
....
) as utenti
....
Table tree_structure is used in the subselect and in the outermost select. The good practice is to make an unique alias for every table reference you have used.
Also you have a typo in the condition that should check self-referencing of the hierarcy root node:
where tr_rec.id = tr_rec.parent_id
and tr_rec.session_id = '2018'
OK guys I found out why the query was wrong. Apparently since MySQL version 8.0.14 they introduced support for using external parameters within subqueries.
My local version was 8.0.16 but the online version was 8.0.11 so because of this my query didn't work.