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

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);

Related

MYSQL GROUP BY on 2 Tables with MAX

I have 2 mysql tables:
record table:
and
race table:
I want to select the records from the 1st table group by id_Race but only the MAX from column "secs".
I tried the following but didnt work:
$query = "SELECT rec.RecordsID,rec.id_Athlete,rec.date_record,rec.id_Race,rec.placeevent,rec.mins,rec.secs,rec.huns,rec.distance,rec.records_text,r.name,MAX(rec.secs)
FROM records AS rec INNER JOIN race AS r ON r.RaceID=rec.id_Race WHERE (id_Athlete=$u_athlete) GROUP BY rec.id_Race;";
($u_athlete is a variable i get from _SESSION)
Can you help me about that?
Thank you.
When you use an aggregation function like MAX and select all fields, you are forced to include all selected fields that are not affected by the MAX inside the GROUP BY clause.
Though you can use a window function like ROW_NUMBER that will group by specifically on id_Race and order by the secs column in a descendent way (so that the highest value of secs will be associated with row_number=1).
Afterwards you can select the rows which have row_number=1 and the id_Athlete you pass using the variable.
SELECT
rec.RecordsID,
rec.id_Athlete,
rec.date_record,
rec.id_Race,
rec.placeevent,
rec.mins,
rec.secs,
rec.huns,
rec.distance,
rec.records_text,
race.name,
FROM
(
SELECT
*,
ROW_NUMBER() OVER(PARTITION BY id_race ORDER BY secs) rank
FROM
record
) rec
INNER JOIN
race race
ON
race.RaceID=rec.id_Race
WHERE
rec.rank = 1
AND
rec.id_Athlete = $u_athlete;

MySQL Select delete any element except for first one per day

my problem ist the following one:
I have a database which receives reports from a server and saves the data into the report table:
enter image description here
and I want to delete and select every report which are made on the same day, except for the first one.
I've already tried to select the reports, which are on the same day:
WITH res as (
select
cis_anlagen.name as plant,
ReportTimestamp,
LAG(ReportTimestamp, 1) OVER (
partition by cis_anlagen.name
ORDER BY ReportTimestamp
) prevTime
from reports
inner join hosts_to_apps using (HostToAppId)
join hosts using(HostId)
Left join cis_anlagen on hosts.anId = cis_anlagen.anId )
select
plant,
ReportTimestamp,
prevTime
from res
where DATEDIFF(ReportTimestamp, prevTime) = 0;
this gives me any report made on the same they, but I still need to exclude the first one.
I want to delete ... every report which are made on the same day, except for the first one
DELETE t1
FROM reports t1
JOIN reports t2 ON t1.HostToAppId = t2.HostToAppId
AND DATE(t1.ReportTimestamp) = DATE(t2.ReportTimestamp)
WHERE t1.ReportTimestamp > t2.ReportTimestamp
I.e. we delete the row when the row with the same HostToAppId and DATE but greater ReportTimestamp exitst.
If there exists 2 or more rows for the same HostToAppId with absolutely the same (and minimal within this day) ReportTimestamp then all of them will be stored.
I want to ... select every report which are made on the same day, except for the first one.
SELECT t1.*
FROM reports t1
JOIN reports t2 ON t1.HostToAppId = t2.HostToAppId
AND DATE(t1.ReportTimestamp) = DATE(t2.ReportTimestamp)
WHERE t1.ReportTimestamp > t2.ReportTimestamp
Instead of using LAG, you could use row_number.
If you use row number partitioned by date (not the whole timestamp, but just the day) and the HostToAppID (Which I am assuming that is an unique identifier of some kind) you would have the the reports numbered for HostToAppID and for day, which would allow you to exclude anything where the row number is not 1.
I can't test it right now but I would go with something like this:
WITH res as (
select
cis_anlagen.name as plant,
ReportTimestamp,
row_number(ReportTimestamp) OVER (
partition by cis_anlagen.name, date(ReportTimestamp)
ORDER BY ReportTimestamp
) rn
from reports
inner join hosts_to_apps using (HostToAppId)
join hosts using(HostId)
Left join cis_anlagen on hosts.anId = cis_anlagen.anId )
select
plant,
ReportTimestamp,
prevTime from res where rn <> 1;
Why all the joins? You want to delete everything except the oldest row per day, so delete all rows where exists a row for the same day, but earlier time:
delete from reports
where exists
(
select null
from (select * from reports) older
where date(older.reporttimestamp) = date(reports.reporttimestamp)
and older.reporttimestamp < reports.reporttimestamp
);
Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=c8a941f3813ae60e14e32dadef46b361
You may wonder about (select * from reports) older. This is because of a MySQL peculiarity that forbids to select from the same table directly that you are deleting from. In other DBMS that would simply be from reports older.

Not getting count of different string - MySql

I have one query as given below,
select device_id,CAST(device_dtt_st as date),count(*) as g,'' as s,'' as m
from event_data_170309
where device_id ='8D-15-DB'and raw_data like %GPRS%'
group by CAST(device_dtt_st as date)
union
select device_id,CAST(device_dtt_st as date),'' as g,count(*) as s,'' as m
from event_data_170309
where device_id ='8D-15-DB' and raw_data like '%SMS%'
group by CAST(device_dtt_st as date)
union
select device_id,CAST(device_dtt_st as date),'' as g,'' as s,count(*) as m
from event_data_170309
where device_id ='8D-15-DB'and !(raw_data like '%SMS%' or raw_data like '%GPRS%')
group by CAST(device_dtt_st as date);
and I got output as in two different row, but I want count in only one row.
see the below scenario,
Union will return multiple rows only.
You will need to wrap all these queries with another query and then count it.
ex.
select count(param), sum(param), param
from
(
select param as param, count(param)
union
another query with same column output
union
yet another query with same column output
) as childQuery
group by childQuery.param
EDIT
Added a aggregated function, whichever you want to use.
EDIT2
SELECT
DEVICE_ID,
DATE,
SUM(IF(DATA LIKE %SMS%,1,0)) AS TOTAL_SMS,
SUM(IF(DATA LIKE %GPRS%,1,0)) AS TOTAL_GPRS,
SUM(IF(DATA NOT LIKE %GPRS% AND DATA NOT LIKE %SMS%,1,0)) AS TOTAL_OTHER,
FROM
YOUR_TABLE T
GROUP BY
T.DATE
ABove query will work for your desired output

The query gives single row query returns more than one row

I'm trying to show staff_code, staff_name and dept_name for those who have taken one book.
Here's my query:
SELECT SM.STAFF_CODE,SM.STAFF_NAME,DM.DEPT_NAME,BT.BOOK_CODE
FROM STAFF_MASTER SM,DEPARTMENT_MASTER DM,BOOK_TRANSACTIONS BT
WHERE SM.DEPT_CODE =DM.DEPT_CODE
AND SM.STAFF_CODE = (
SELECT STAFF_CODE
FROM BOOK_TRANSACTIONS
HAVING COUNT(*) > 1
GROUP BY STAFF_CODE)
It gives the error:
single-row subquery returns more than one row.
How to solve this?
Change = to IN:
WHERE SM.STAFF_CODE IN (SELECT ...)
Because the select returns multiple values, using equals won't work, but IN returns true if any of the values in a list match. The list can be a hard-coded CSV list, or a select with one column like your query is.
That will fix the error, but you also need to remove BOOK_TRANSACTIONS from the table list and remove BOOK_CODE from the select list.
After making these changes, your query would look like this:
SELECT SM.STAFF_CODE,SM.STAFF_NAME,DM.DEPT_NAME
FROM STAFF_MASTER SM,DEPARTMENT_MASTER DM
WHERE SM.DEPT_CODE =DM.DEPT_CODE
AND SM.STAFF_CODE IN (
SELECT STAFF_CODE
FROM BOOK_TRANSACTIONS
HAVING COUNT(*) > 1
GROUP BY STAFF_CODE)
I recommend learning the modern (now over 25 year old) JOIN syntax.

sqlalchemy SELECT column FROM (SELECT columns FROM TABLE)

I have the following query
reports = self.session.query((
func.sum(Report.a) / func.sum(Report.b))
.label('c'),
Report.id,
Report.id2
).group_by(Report.id, Report.id2
)
I now want to get the max(c) for the reports, grouped by id.
Essentially, I am trying to have a sqlalchemy solution to this problem
SQL Select only rows with Max Value on a Column
but with the extra requirement that I need to calculate the value column I want to have the max in as in Selecting max value from calculated column in mysql
I am finding it difficult to perform a
SELECT MAX(C), id FROM (SELECT A/B AS C, id FROM TABLE) t
Mark your first query as subquery:
reports = session.query(
(func.sum(Report.a) / func.sum(Report.b)).label('c'),
Report.id,
Report.id2
).group_by(Report.id, Report.id2).subquery()
After this it can be used in another query as if it was a table:
# reports.c is a shorthand for reports.columns
q = session.query(
func.max(reports.c.c),
reports.c.id
).group_by(reports.c.id)