SQL Query - adding max condition for distinct name - mysql

Warmest thanks by advance for your help
My current SQL query :
SELECT
`id`,
`comp`,
`jour`,
`hippo`,
`numcourse`,
`cl`,
`dist`,
`partant`,
`typec`,
`cheque`,
`numero`,
`cheval`,
`age`,
`cotedirect`
FROM `turf_12dec`.`cachedate` c
WHERE
`partant` > '7'
AND `typec` = 'Attelé'
AND `jour` > '2017-01-01'
AND `cl` != ''
AND `cl`!= 'NP'
That I wish :
AND max(jour) for distinct cheval is > '2019-01-01'

This query:
SELECT `cheval`
FROM `turf_12dec`.`cachedate`
GROUP BY `cheval`
HAVING MAX(`jour`) > '2019-01-01'
returns all the chevals that you describe in your condition and you can join it to the table:
SELECT t.`id`, t.`comp`, t.`jour`, t.`hippo`, t.`numcourse`, t.`cl`,
t.`dist`, t.`partant`, t.`typec`, t.`cheque`, t.`numero`,
t.`cheval`, t.`age`, t.`cotedirect`
FROM `turf_12dec`.`cachedate` t INNER JOIN (
SELECT `cheval`
FROM `turf_12dec`.`cachedate`
GROUP BY `cheval`
HAVING MAX(`jour`) > '2019-01-01'
) tt ON tt.`cheval` = t.`cheval`
WHERE t.`partant` > '7' and
t.`typec` = 'Attelé' and
t.`jour` > '2017-01-01' and
t.`cl` != '' AND
t.`cl`!= 'NP'

You can add a correlated subquery:
and exists (select 1
from `turf_12dec`.`cachedate` cd
where cd.cheval = cachedate.cheval and cd.jour > '2019-01-01'
)
You don't mention the additional filtering conditions. You may need to repeat them in the subquery as well, if they should also apply to the maximum jour.

You could add an additional filter with a correlated subquery:
SELECT
`id`,
`comp`,
`jour`,
`hippo`,
`numcourse`,
`cl`,
`dist`,
`partant`,
`typec`,
`cheque`,
`numero`,
`cheval`,
`age`,
`cotedirect`
FROM `turf_12dec`.`cachedate` c
WHERE
`partant` > '7'
AND `typec` = 'Attelé'
AND `jour` > '2017-01-01'
AND `cl` != ''
AND `cl`!= 'NP'
AND (
SELECT MAX(`jour`)
FROM `turf_12dec`.`cachedate` c1
WHERE c1.`cheval` = c.`cheval`
) > '2019-01-01'
This can also be expressed with an EXITS condition:
AND EXISTS (
SELECT 1
FROM `turf_12dec`.`cachedate`
WHERE c1.`cheval` = c.`cheval` AND `jour` > '2019-01-01'
)

Related

SQL how to create aggregate of two aggregated columns for each row

I'm working on a big query in SQL (MySQL 5.7) to calculate aggregated columns based on raw values in my table. I've created several aggregated columns (see attached screenshot and SQL) and I now need to create a conversion_percent column for each tlp_aff_id in my query.
This conversion_percent should be a division of the aggregated JoinedSessions.total_sessions and COUNT(Report.tlp_aff_id) as leads_total.
My current SQL:
SELECT
# Application details
Report.tlp_aff_id,
# Revenue
JoinedRevenue.total_revenue,
# Commission
JoinedCommission.total_commission,
# Profit
JoinedProfit.total_profit,
# Sessions
JoinedSessions.total_sessions,
# Submits
COUNT(Report.tlp_aff_id) as total_submits,
# Leads
COUNT(Report.tlp_aff_id) as leads_total,
SUM(case when Report.application_result = 'Accepted' then 1 else 0 end) leads_accepted,
SUM(case when Report.application_result = 'Rejected' then 1 else 0 end) leads_rejected
# Conversion percent
# JoinedConversion.conversion_percent
FROM
tlp_payout_report_minute AS Report
INNER JOIN
(
SELECT
JoinedRevenue.tlp_aff_id,
JoinedRevenue.minute_rounded_timestamp,
SUM(commission) AS total_revenue
FROM
tlp_payout_report_minute AS JoinedRevenue
WHERE
JoinedRevenue.minute_rounded_timestamp >= 1664841600
AND
JoinedRevenue.minute_rounded_timestamp <= 1664927999
GROUP BY
JoinedRevenue.tlp_aff_id
) AS JoinedRevenue
ON JoinedRevenue.tlp_aff_id = Report.tlp_aff_id
INNER JOIN
(
SELECT
ReportCommission.tlp_aff_id,
ReportCommission.seller_code,
ReportCommission.minute_rounded_timestamp,
SUM(commission) AS total_commission
FROM
tlp_payout_report_minute AS ReportCommission
WHERE
ReportCommission.minute_rounded_timestamp >= 1664841600
AND
ReportCommission.minute_rounded_timestamp <= 1664927999
AND
ReportCommission.seller_code != 44
GROUP BY
ReportCommission.tlp_aff_id
) AS JoinedCommission
ON JoinedCommission.tlp_aff_id = Report.tlp_aff_id
INNER JOIN
(
SELECT
ReportProfit.tlp_aff_id,
ReportProfit.seller_code,
ReportProfit.application_result,
ReportProfit.minute_rounded_timestamp,
SUM(commission) AS total_profit
FROM
tlp_payout_report_minute AS ReportProfit
WHERE
ReportProfit.minute_rounded_timestamp >= 1664841600
AND
ReportProfit.minute_rounded_timestamp <= 1664927999
AND
ReportProfit.application_result = 'Accepted'
AND
ReportProfit.seller_code = 44
GROUP BY
ReportProfit.tlp_aff_id
) AS JoinedProfit
ON JoinedProfit.tlp_aff_id = Report.tlp_aff_id
INNER JOIN
(
SELECT
Conversion.aff_id,
Conversion.conversion_type,
COUNT(Conversion.ip_address) as total_sessions
FROM
tlp_conversions AS Conversion
WHERE
Conversion.conversion_time >= '2022-10-04 00:00:00'
AND
Conversion.conversion_time <= '2022-10-04 23:59:59'
AND
Conversion.aff_id IS NOT NULL
AND
Conversion.conversion_type = 2
GROUP BY
Conversion.aff_id
) AS JoinedSessions
ON JoinedSessions.aff_id = Report.tlp_aff_id
WHERE
Report.minute_rounded_timestamp >= 1664841600
AND
Report.minute_rounded_timestamp <= 1664927999
GROUP BY
Report.tlp_aff_id
ORDER BY
JoinedRevenue.total_revenue DESC
I'm thinking something along the lines of:
INNER JOIN
(
...
) AS JoinedConversion
ON JoinedConversion.aff_id = Report.tlp_aff_id
But I don't think this is necessary for conversion_percent.
What's the right approach here?

Convert mysql to doctrine

I have the following MySQL query
select a.*, d.*, p.*, pow.* from appointment a
left join doctor d on d.id = a.doctor_id
left join patient p on p.id = a.patient_id
left join point_of_work pow on pow.id = a.point_of_work_id
where (doctor_id, patient_id, date) = (
select doctor_id, patient_id,
coalesce(
min(case when date > curdate() then date end),
max(case when date < curdate() then date end)
) date
from appointment
where (doctor_id, patient_id) = (a.doctor_id, a.patient_id)
)
and d.external_id = 1
And I am trying to convert it to DQL.
Right now I come to this version of DQL but it seems I'am doing something (or maybe more things:( wrong)
$expr = $this->getEntityManager()->getExpressionBuilder();
$queryBuilder = $this->createQueryBuilder('a')
->leftJoin(Doctor::class, 'd')
->leftJoin(Patient::class, 'p')
->leftJoin(PointOfWork::class, 'pow')
->where(
$expr->eq('doctorId, patient_id, date',
$this->createQueryBuilder('a')
->select(Appointment::class . ',
coalesce(
min(case when date > curdate() then date end),
max(case when date < curdate() then date end)
) date'
)
->where ('(doctorId, patientId) = (a.doctorId, a.patientId)')
)
)
->andWhere('d.externalId = :externalId')
->setParameter('externalId', $doctorExternalId)
->setMaxResults($limit)
->setFirstResult($offset);
What approaches do I need for the DQL conversion?

Combining all data with a unique ID - MySQL

I have this data that I got from my current query.
What I want to do is combine and make it a single row where the type is Senior, the cashamount and Tenderamount are the same as well.
This is my desired result:
I'm getting my data from this table:
Here's my query:
SELECT a.DATE as `DATE`, a.employee as `EMPLOYEE`, a.TYPEID, a.NAME as
`NAME`, (select (case when a.typeid = 1 then a.amount else NULL end)) as
`CASHAMOUNT`,
(select (case when a.typeid <> 1 then a.amount else NULL end)) as
`TENDERAMOUNT`, (select gndtndr.IDENT from gndtndr where gndtndr.TYPE = 12
and `gndtndr`.`CHECK`= a.CHECK and gndtndr.DATE = a.DATE) as `ID`,
from gndtndr a
where STR_TO_DATE(a.DATE, '%m/%d/%Y') BETWEEN '20170901' AND '20170901'
order by STR_TO_DATE(a.DATE, '%m/%d/%Y')
My MySQL is a bit rusty, but give this a try!
SELECT a.Date, a.Employee, a.Name, a.ID, SUM(b.Amount) AS CashAmount,
SUM(c.Amount) AS TenderAmount FROM
(SELECT DISTINCT Date, Employee, Name, ID FROM gndtndr WHERE Type = 12) AS a
LEFT JOIN gndtndr AS b
ON a.ID = b.ID AND b.TypeID = 1
LEFT JOIN gndtdr AS c
ON a.ID = c.ID and c.TypeID <> 1
GROUP BY a.Date, a.Employee, a.Name, a.ID
I've figured it out :) I just have to define the type conditions in my where clause where the type is 1(for cash).
SELECT a.DATE as `DATE`, a.employee as `EMPLOYEE`, a.TYPEID, a.NAME as
`NAME`, (select sum(gndtndr.amount) from gndtndr where gndtndr.typeid = 1
and gndtndr.`CHECK` = a.`CHECK` and gndtndr.DATE = a.DATE) as `CASHAMOUNT`,
(select (case when a.typeid <> 1 then a.amount else NULL end)) as
`TENDERAMOUNT`, (select gndtndr.IDENT from gndtndr where gndtndr.TYPE = 12
and `gndtndr`.`CHECK`= a.CHECK and gndtndr.DATE = a.DATE) as `ID` from
gndtndr a
where a.TYPEID <> 1 and STR_TO_DATE(a.DATE, '%m/%d/%Y') BETWEEN '20170901'
AND '20170901' order by STR_TO_DATE(a.DATE, '%m/%d/%Y')

Query using group by month

I have problem with the query using group by month. This query returns total_revenue per month. but if month of year doesn't contain any data then total_revnue is increased unnecessarily.
SELECT COUNT(CT.cumTxnReportId),
CT.cumTxnReportId,
CT.ticketNum,
DATE_FORMAT(CT.exitDateTimeUtc,'%m-%Y'),
sum(netAmount) AS total_revenue,
D.name,
HOUR(CT.entranceDateTimeUtc) AS entryHour,
HOUR(CT.exitDateTimeUtc) AS exitHour,
CT.entranceDateTimeUtc,
CT.exitDateTimeUtc,
CT.netAmount AS netAmount,
CT.grossAmount,
CT.discountAmount,
CT.rate,
CT.txnType,
CT.ticketType,
CT.txnNum,
CT.numDiscounts
FROM Parkloco.ParkingArea PA
JOIN IParcPro.Device D ON PA.id = D.parkingAreaId
JOIN Parkloco.RateCard RC ON PA.id = RC.parkingAreaId
JOIN IParcPro.CumTxn CT ON D.id = CT.deviceId
WHERE PA.uuid = '27d842c1-7057-11e6-a0eb-1245b0d35d23'
AND (CT.txnType = 'Allowed'
OR CT.txnType = 'Add'
OR CT.txnType = 'Normal'
OR CT.txnType = 'Offline'
OR CT.txnType = 'Repay')
AND ((CT.entranceDateTimeUtc >= '2016-08-01 00:00:00'
AND CT.exitDateTimeUtc <= '2017-04-31 23:59:59'))
AND (RC.state = 'active'
OR RC.state = 'archived')
AND RC.fromDateTimeUtc <= '2017-04-31 23:59:59'
AND (RC.thruDateTimeUtc IS NULL
OR RC.thruDateTimeUtc >= '2016-08-01 00:00:00')
AND (TIMESTAMPDIFF (SECOND, CT.entranceDateTimeUtc, CT.exitDateTimeUtc) >= '0' * 60)
AND (TIMESTAMPDIFF (SECOND, CT.entranceDateTimeUtc, CT.exitDateTimeUtc) < '1441' * 60)
AND CT.numDiscounts=0
AND CT.ticketNum !=0
GROUP BY DATE_FORMAT(CT.exitDateTimeUtc,'%m-%Y')
but when I am increasing the range month - at that point of time I am getting unneccessary increment in total_revenue
SELECT COUNT(CT.cumTxnReportId),
CT.cumTxnReportId,
CT.ticketNum,
DATE_FORMAT(CT.exitDateTimeUtc,'%m-%Y'),
sum(netAmount) AS total_revenue,
D.name,
HOUR(CT.entranceDateTimeUtc) AS entryHour,
HOUR(CT.exitDateTimeUtc) AS exitHour,
CT.entranceDateTimeUtc,
CT.exitDateTimeUtc,
CT.netAmount AS netAmount,
CT.grossAmount,
CT.discountAmount,
CT.rate,
CT.txnType,
CT.ticketType,
CT.txnNum,
CT.numDiscounts
FROM Parkloco.ParkingArea PA
JOIN IParcPro.Device D ON PA.id = D.parkingAreaId
JOIN Parkloco.RateCard RC ON PA.id = RC.parkingAreaId
JOIN IParcPro.CumTxn CT ON D.id = CT.deviceId
WHERE PA.uuid = '27d842c1-7057-11e6-a0eb-1245b0d35d23'
AND (CT.txnType = 'Allowed'
OR CT.txnType = 'Add'
OR CT.txnType = 'Normal'
OR CT.txnType = 'Offline'
OR CT.txnType = 'Repay')
AND ((CT.entranceDateTimeUtc >= '2016-08-01 00:00:00'
AND CT.exitDateTimeUtc <= '2017-07-31 23:59:59'))
AND (RC.state = 'active'
OR RC.state = 'archived')
AND RC.fromDateTimeUtc <= '2017-07-31 23:59:59'
AND (RC.thruDateTimeUtc IS NULL
OR RC.thruDateTimeUtc >= '2016-08-01 00:00:00')
AND (TIMESTAMPDIFF (SECOND, CT.entranceDateTimeUtc, CT.exitDateTimeUtc) >= '0' * 60)
AND (TIMESTAMPDIFF (SECOND, CT.entranceDateTimeUtc, CT.exitDateTimeUtc) < '1441' * 60)
AND CT.numDiscounts=0
AND CT.ticketNum !=0
GROUP BY DATE_FORMAT(CT.exitDateTimeUtc,'%m-%Y')
output such as :
can anyone help me on this? Thanks in advance if you could let me know.
Despite MySQL allow this weird group by rules, in my opinion, you should to avoid use it. I explain, usually, all select clause non aggregate fields should appear on group by clause:
select a,b,c, sum(z)
from t
group by a,b,c
vs
select a,b,c, sum(z)
from t
group by a #<--- MySQL allow this!
Then, if b and c are not in group by, how MySQL figure up the right fields to be selected? Like this on <5.6:
The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate.
In my opinion, in your query has no sense: Look entryHour and total_revenue. One is for an entry the other one is for all month.
I guess you should to rethink the hole sql statement. Because the result of this one is incoherent.
Also, remember this is not 'code revision service'. Please, read how to create a Minimal, Complete, and Verifiable example in order your question also help other users.

Unknown column in subquery - mysql

I am very close to completing this difficult query. It's quite long, so hopefully not too overwhelming. But in my case statment in the select block I am referencing a union from my where statement. It is giving me "MySQL Database Error: Unknown column 'U.EmpID' in 'where clause'". Any help would be much appreciated. And here is the query:
SELECT U.EmpID,
CASE
WHEN ((SELECT COUNT(*)
FROM (SELECT *
FROM timeclock_copy tp
WHERE PunchEvent = 'breakin'
AND DATE(tp.PunchDateTime) =
'2013-11-12'
AND tp.EmpID = U.EmpID) AS s) > 1)
AND ((SELECT COUNT(*)
FROM (SELECT *
FROM timeclock_copy tp
WHERE PunchEvent = 'breakout'
AND DATE(tp.PunchDateTime) =
'2013-11-12'
AND tp.EmpID = U.EmpID) AS s) > 1)
THEN
"MULTIPLE BREAKS"
ELSE
"ONE BREAK"
END
AS Lunch
FROM ((SELECT `enter`.EmpID,
`enter`.PunchDateTime AS `time`,
DATE_FORMAT(`enter`.PunchDateTime, '%m-%d-%Y')
AS 'Punch Date',
TIMESTAMPDIFF(SECOND,
`enter`.PunchDateTime,
'2003-05-01 00:00:00')
AS `delta`
FROM timeclock_copy AS `enter`
WHERE `enter`.`In-Out` = 1)
UNION
(SELECT `leave`.EmpID,
`leave`.PunchDateTime AS `time`,
DATE_FORMAT(`leave`.PunchDateTime, '%m-%d-%Y')
AS 'Punch Date',
-TIMESTAMPDIFF(SECOND,
`leave`.PunchDateTime,
'2003-05-01 00:00:00')
AS `delta`
FROM timeclock_copy AS `leave`
WHERE `leave`.`In-Out` = 0)) AS U
LEFT JOIN testclb.prempl pe ON u.EmpID = pe.prempl
WHERE DATE(U.`time`) >= '2013-11-12' AND DATE(U.`time`) < '2013-11-13'
GROUP BY date(U.`time`), EmpID
ORDER BY U.EmpID, U.`time` ASC
Subqueries in FROM clauses cannot be correlated with the outer statement. I think this is why you are getting the Unknown column 'U.EmpID' in 'where clause'" error.