How to perform SUM, MINUS & DIVIDE in MySql - mysql

I have a following query which is giving me Opening_HC/Attrition/Moved/Addition:
select(select SUM(Opening_HC) from(
(select count(emp_id) as Opening_HC from hcdata where status =
"Active" and DOJ <='2014-11-02' and sub_department='Sub_dep_07' and
production_support='prod_sup-02')
UNION ALL
(select count(emp_id) as Opening_HC from hcdata where status = "Moved"
and DOJ <='2014-11-02' and inactive_date >= '2014-11-02' and
sub_department='Sub_dep_07' and production_support='prod_sup-02')
UNION ALL
(select count(emp_id) as Opening_HC from hcdata where status =
"Attrition" and DOJ <='2014-11-02' and inactive_date >= '2014-11-02'
and sub_department='Sub_dep_07' and production_support='prod_sup-
02'))t1) as Opening_HC, (select count(emp_id) from hcdata where
sub_department='Sub_dep_07' and production_support='prod_sup-02' and
status='Attrite'and inactive_date between '2014-11-02' and '2014-11-
08') as Attrition, (select count(emp_id) from hcdata where
sub_department='Sub_dep_07' and production_support='prod_sup-02' and
status='Moved' and inactive_date between '2014-11-02' and '2014-11-
08') as Moved,(select count(emp_id) from hcdata where
sub_department='Sub_dep_07' and production_support='prod_sup-02' and
sub_department = 'Sub_dep_07' and DOJ between '2014-11-02' and
'2014-11-08') as Addition
Now what i am looking for is Closing_HC, Entity_Attrition% & Process_Attrition%
Calculation should be:
Closing_HC = Opening_HC + Addition - Attrition - Moved
Entity_Attrition% = Attrition/((Opening_HC + Closing_HC)/2)
Process_Attrition% = (Attrition + Moved)/((Opening_HC + Closing_HC)/2)

Am I right in thinking that all of t1/Opening_HC can be rewritten as follows:
SELECT COUNT(emp_id) Opening_HC
FROM hcdata
WHERE (status = 'Active')
OR (status IN('Moved','Attrition') AND inactive_date >= '2014-11-02')
AND DOJ <= '2014-11-02'
AND sub_department = 'Sub_dep_07'
AND production_support = 'prod_sup-02'
?
AND does status really ever equal 'Attrite'?

Related

Pulling data from same table twice with different keys? [duplicate]

`
Select peo.employee_number,
bpf.name plan_name,
typ.name plan_type,
ben.effective_start_date,
ben.effective_end_date,
ben.enrt_cvg_strt_dt,
ben.enrt_cvg_thru_dt
from apps.ben_prtt_enrt_rslt_f ben,
apps.ben_pl_f bpf,
apps.ben_pl_typ_f typ,
apps.per_all_people_f peo
where (ben.enrt_cvg_thru_dt >= '01-JAN-2017' and typ.name ='Choice Health')
and (ben.enrt_cvg_strt_dt >= ben.enrt_cvg_thru_dt and typ.name ='Waive
Health')
and ben.person_Id = peo.person_id
and ben.pl_id = bpf.pl_id
and typ.name ='choice Health' or 'waive health'
and typ.pl_typ_id = ben.pl_typ_id`
I need to retrieve all the employees which are having coverage_thru_date >= 01-JAN-2017 and enrolled for plan_name ='Choice Health' as well as those whose coverage_start_dt >= coverage_thru_dt and are enrolled for plan_name='Waive Health'
Try this.
SELECT *
FROM employees
WHERE (coverage_thru_date >= TO_DATE('01-JAN-2017')
AND plan_name ='Choice Health')
OR
(coverage_start_dt >= coverage_thru_dt
AND plan_name='Waive Medical');
--------------REVISED BASED ON SUPPLIED QUERY--------------
SELECT peo.employee_number,
bpf.name plan_name,
typ.name plan_type,
ben.effective_start_date,
ben.effective_end_date,
ben.enrt_cvg_strt_dt,
ben.enrt_cvg_thru_dt
FROM apps.ben_prtt_enrt_rslt_f ben,
apps.ben_pl_f bpf,
apps.ben_pl_typ_f typ,
apps.per_all_people_f peo
WHERE ( ben.enrt_cvg_thru_dt >= '01-JAN-2017'
AND typ.name = 'Choice Health' )
OR
( ben.enrt_cvg_strt_dt >= ben.enrt_cvg_thru_dt
AND typ.name = 'Waive Health' )
AND ben.person_id = peo.person_id
AND ben.pl_id = bpf.pl_id
AND typ.pl_typ_id = ben.pl_typ_id;

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?

Script is freezing. Want to take the average count of "Women" for 1 month ago to 60 months ago. This portion of the code is freezing on me

/*This is the code Im using to count and take the Average?*/
`SELECT GETDATE() AS CurrentDate,
(SELECT COUNT(1) FROM People WITH(NOLOCK) LEFT JOIN LinkPeopleToCompanies WITH(NOLOCK) ON
People.PeopleID = LinkPeopleToCompanies.PeopleID
WHERE (LinkPeopleToCompanies.ToDate >= GETDATE() OR LinkPeopleToCompanies.ToDate IS NULL)
AND LinkPeopleToCompanies.SinceDate <= GETDATE() - 2190
AND LinkPeopleToCompanies.CompaniesID = Companies.CompaniesID) AS TotalDirectorsAddedin6years,
(SELECT AVG(DATEDIFF("yyyy",People.BirthDay,GETDATE())) FROM People WITH(NOLOCK) LEFT JOIN
LinkPeopleToCompanies WITH(NOLOCK) ON People.PeopleID = LinkPeopleToCompanies.PeopleID
WHERE (LinkPeopleToCompanies.ToDate >= GETDATE() - 30 OR LinkPeopleToCompanies.ToDate IS NULL)
AND LinkPeopleToCompanies.SinceDate <= GETDATE() - 30
AND LinkPeopleToCompanies.CompaniesID = Companies.CompaniesID) AS AverageDirectorAge1MonthAgo,
/I repeat this same code going back progressively by 30 days or 1 month. Need some more effective code/
(SELECT AVG(LinkPeopleToCompanies.CustomInt1) FROM People WITH(NOLOCK) LEFT JOIN
LinkPeopleToCompanies WITH(NOLOCK) ON People.PeopleID = LinkPeopleToCompanies.PeopleID
WHERE (LinkPeopleToCompanies.ToDate >= GETDATE() - 30 OR LinkPeopleToCompanies.ToDate IS NULL)
AND LinkPeopleToCompanies.SinceDate <= GETDATE() - 30
AND LinkPeopleToCompanies.CompaniesID = Companies.CompaniesID) AS AverageDirectorTenure1MonthAgo,
TotalWomenonBoard1 = CASE WHEN ((SELECT COUNT(1) FROM People WITH(NOLOCK) INNER JOIN
LinkPeopleToCompanies WITH(NOLOCK) ON People.PeopleID = LinkPeopleToCompanies.PeopleID
WHERE (LinkPeopleToCompanies.ToDate >= GETDATE()- 30 OR LinkPeopleToCompanies.ToDate IS NULL)
AND LinkPeopleToCompanies.SinceDate <= GETDATE()- 30
AND LinkPeopleToCompanies.CompaniesID = Companies.CompaniesID) = 0 )
THEN '9999999'
ELSE (SELECT COUNT(1) FROM People WITH(NOLOCK) INNER JOIN LinkPeopleToCompanies WITH(NOLOCK) ON
People.PeopleID = LinkPeopleToCompanies.PeopleID
WHERE (LinkPeopleToCompanies.ToDate >= GETDATE() - 30 OR LinkPeopleToCompanies.ToDate IS NULL)
AND LinkPeopleToCompanies.SinceDate <= GETDATE() - 30
AND LinkPeopleToCompanies.CompaniesID = Companies.CompaniesID
AND People.Gender = 'F')
END,
TotalWomenonBoard2 = CASE WHEN ((SELECT COUNT(1) FROM People WITH(NOLOCK) INNER JOIN
LinkPeopleToCompanies WITH(NOLOCK) ON People.PeopleID = LinkPeopleToCompanies.PeopleID
WHERE (LinkPeopleToCompanies.ToDate >= GETDATE()- 60 OR LinkPeopleToCompanies.ToDate IS NULL)
AND LinkPeopleToCompanies.SinceDate <= GETDATE()- 60
AND LinkPeopleToCompanies.CompaniesID = Companies.CompaniesID) = 0 )
THEN '9999999'
ELSE (SELECT COUNT(1) FROM People WITH(NOLOCK) INNER JOIN LinkPeopleToCompanies WITH(NOLOCK) ON
People.PeopleID = LinkPeopleToCompanies.PeopleID
WHERE (LinkPeopleToCompanies.ToDate >= GETDATE() - 60 OR LinkPeopleToCompanies.ToDate IS NULL)
AND LinkPeopleToCompanies.SinceDate <= GETDATE() - 60
AND LinkPeopleToCompanies.CompaniesID = Companies.CompaniesID
AND People.Gender = 'F')
END,
TotalWomenonBoard60 = CASE WHEN ((SELECT COUNT(1) FROM People WITH(NOLOCK) INNER JOIN
LinkPeopleToCompanies WITH(NOLOCK) ON People.PeopleID = LinkPeopleToCompanies.PeopleID
WHERE (LinkPeopleToCompanies.ToDate >= GETDATE()- 1825 OR LinkPeopleToCompanies.ToDate IS NULL)
AND LinkPeopleToCompanies.SinceDate <= GETDATE()- 1825
AND LinkPeopleToCompanies.CompaniesID = Companies.CompaniesID) = 0 )
THEN '9999999'
ELSE (SELECT COUNT(1) FROM People WITH(NOLOCK) INNER JOIN LinkPeopleToCompanies WITH(NOLOCK) ON
People.PeopleID = LinkPeopleToCompanies.PeopleID
WHERE (LinkPeopleToCompanies.ToDate >= GETDATE()- 1825 OR LinkPeopleToCompanies.ToDate IS NULL)
AND LinkPeopleToCompanies.SinceDate <= GETDATE()- 1825
AND LinkPeopleToCompanies.CompaniesID = Companies.CompaniesID
AND People.Gender = 'F')
END
FROM Companies WITH(NOLOCK)
ORDER BY Company`
Syntax in the question appears to be Transact-SQL ala Microsoft SQL Server (which is different than MySQL and Oracle; this question seems to be unrelated to the actual client program, that detail might be important... setting that aside.
For performance, I would opt to use conditional aggregation. I would use a single SELECT and one set of table references, and avoid multiple SELECT queries against the same tables with different WHERE clauses.
To get a count of "some" rows, I'd use a conditional in an expression to return a 1 or 0, and then total those up with SUM. (Or, I return a non-null and NULL, and use COUNT.)
Without digging into every SELECT ... FROM included in the question, it looks like the only form of statement we need is this:
SELECT GETDATE() AS CurrentDate
, SUM(CASE WHEN ... THEN 1 ELSE 0 END) AS stat_count_foo
FROM Companies c
LEFT
JOIN LinkPeopleToCompanies t
ON t.companiesid = c.companiesid
LEFT
JOIN People p
ON p.peopleid = t.peopleid
GROUP
BY c.companiesid
Note that there is not a WHERE clause in there. (We would only include conditions in the WHERE clause to exclude rows that we don't need for any metrics.)
Adding some example metrics, our statement would look something like this:
SELECT GETDATE() AS CurrentDate
, SUM( CASE
WHEN (t.todate >= GETDATE() OR t.todate IS NULL)
AND t.sincedate <= GETDATE() - 2190
THEN 1
ELSE 0
END
) AS TotalDirectorsAddedin6years
, AVG( CASE
WHEN (t.todate >= GETDATE() - 30 OR t.todate IS NULL)
AND t.sincedate <= GETDATE() - 30
THEN DATEDIFF('yyyy',p.birthDay,GETDATE())
ELSE NULL
END
) AS AverageDirectorAge1MonthAgo
, SUM( CASE
WHEN (t.todate >= GETDATE()- 1825 OR t.todate IS NULL)
AND t.sincedate <= GETDATE()- 1825
AND p.Gender = 'F'
THEN 1
ELSE 0
END
) AS TotalWomenonBoard60
FROM Companies c
LEFT
JOIN LinkPeopleToCompanies t
ON t.companiesid = c.companiesid
LEFT
JOIN People p
ON p.peopleid = t.peopleid
GROUP
BY c.companiesid
Extend this by adding additional expressions. Do NOT add any additional SELECT, FROM or JOIN keywords. We could wrap the aggregate expressions in another expression to replace a NULL value with a "0" (for a company that doesn't have any people linked to it.

Mysql - Min and Max per month as oppose to daily?

The query below does its job to select the min, max, start and last price per day in a given month.
I would like to select the same but for the whole month, as in show the overall performance for the given month instead of on a daily basis.
Fiddle: http://sqlfiddle.com/#!9/ca4867/10
SELECT maxminprice.metal_id,
maxminprice.metal_price_datetime_IST,
maxminprice.max_price,
maxminprice.min_price,
firstlastprice.first_price,
firstlastprice.last_price
FROM (SELECT metal_id,
DATE(metal_price_datetime) metal_price_datetime_IST,
MAX(metal_price) max_price,
MIN(metal_price) min_price
FROM metal_prices
GROUP BY metal_id,
DATE(metal_price_datetime)
ORDER BY metal_id,
DATE(metal_price_datetime_IST)) maxminprice
INNER JOIN (SELECT mp.metal_id,
day_range.metal_price_datetimefl,
SUM(CASE
WHEN TIME(mp.metal_price_datetime_IST) = first_time
THEN
mp.metal_price
ELSE NULL
END) first_price,
SUM(CASE
WHEN TIME(mp.metal_price_datetime_IST) = last_time
THEN
mp.metal_price
ELSE NULL
END) last_price
FROM metal_prices mp
INNER JOIN (SELECT metal_id,
DATE(metal_price_datetime_IST)
metal_price_datetimefl,
MAX(TIME(metal_price_datetime_IST))
last_time,
MIN(TIME(metal_price_datetime_IST))
first_time
FROM metal_prices
GROUP BY metal_id,
DATE(metal_price_datetime_IST))
day_range
ON mp.metal_id = day_range.metal_id
AND DATE(mp.metal_price_datetime_IST) =
day_range.metal_price_datetimefl
AND TIME(mp.metal_price_datetime_IST) IN
( last_time, first_time )
GROUP BY mp.metal_id,
day_range.metal_price_datetimefl) firstlastprice
ON maxminprice.metal_id = firstlastprice.metal_id
AND maxminprice.metal_price_datetime_IST =
firstlastprice.metal_price_datetimefl
AND maxminprice.metal_price_datetime_IST BETWEEN '2018-02-01' AND LAST_DAY('2018-02-01')
ORDER BY metal_id, metal_price_datetime_IST DESC
Here is the query changed to work for each month. I have not changed the column names so you might need to look into doing that for better maintenance. Also, I have not tested this with data for multiple months or over years so you should do that before you start using it.
SELECT maxminprice.metal_id,
maxminprice.metal_price_datetime_IST,
maxminprice.max_price,
maxminprice.min_price,
firstlastprice.first_price,
firstlastprice.last_price
FROM (SELECT metal_id,
DATE_FORMAT(metal_price_datetime_IST, "%Y%m") metal_price_datetime_IST,
MAX(metal_price) max_price,
MIN(metal_price) min_price
FROM metal_prices
GROUP BY metal_id,
DATE_FORMAT(metal_price_datetime_IST, "%Y%m")
ORDER BY metal_id,
DATE_FORMAT(metal_price_datetime_IST, "%Y%m")) maxminprice
INNER JOIN (SELECT mp.metal_id,
day_range.metal_price_datetimefl,
SUM(CASE
WHEN mp.metal_price_datetime_IST = first_time
THEN
mp.metal_price
ELSE NULL
END) first_price,
SUM(CASE
WHEN mp.metal_price_datetime_IST = last_time
THEN
mp.metal_price
ELSE NULL
END) last_price
FROM metal_prices mp
INNER JOIN (SELECT metal_id,
DATE_FORMAT(metal_price_datetime_IST, "%Y%m")
metal_price_datetimefl,
MAX(metal_price_datetime_IST)
last_time,
MIN(metal_price_datetime_IST)
first_time
FROM metal_prices
GROUP BY metal_id,
DATE_FORMAT(metal_price_datetime_IST, "%Y%m")) day_range
ON mp.metal_id = day_range.metal_id
AND DATE_FORMAT(mp.metal_price_datetime_IST, "%Y%m") =
day_range.metal_price_datetimefl
AND mp.metal_price_datetime_IST IN
( last_time, first_time )
GROUP BY mp.metal_id,
day_range.metal_price_datetimefl) firstlastprice
ON maxminprice.metal_id = firstlastprice.metal_id
AND maxminprice.metal_price_datetime_IST =
firstlastprice.metal_price_datetimefl

SUM and get AVG from two tables in MySQL with WHERE clause based on their DATE

Here is my code. I have a difficulty with it.
SELECT NAMA_GRUP, SUM(TOTAL_KPI_PROGRAM)/COUNT(ctr.TANGGAL) AS AVG_KPI, COUNT(ctr.TANGGAL) AS JUMLAH_TANGGAL, ctr.TANGGAL AS TANGGAL
FROM ckm_t_grup ctg, ckm_t_program ctp, ckm_t_rundown ctr, ckm_t_calculate ctc
WHERE ctg.ID_GRUP = ctp.ID_GRUP AND ctp.ID_PROGRAM = ctr.ID_PROGRAM AND ctr.ID_RUNDOWN = ctc.ID_RUNDOWN AND (ctr.TANGGAL BETWEEN '2015-07-01' AND '2015-07-15')
GROUP BY ctr.TANGGAL, NAMA_GRUP
UNION
SELECT NAMA_GRUP, SUM(TOTAL_KPI_PROGRAM)/COUNT(ctr.TANGGAL) AS AVG_KPI, COUNT(ctr.TANGGAL) AS JUMLAH_TANGGAL, ctr.TANGGAL AS TANGGAL
FROM ckm_t_grup ctg, ckm_t_program ctp, ckm_t_rundown ctr, ckm_t_calculate_2 ctcc
WHERE ctg.ID_GRUP = ctp.ID_GRUP AND ctp.ID_PROGRAM = ctr.ID_PROGRAM AND ctr.ID_RUNDOWN = ctcc.ID_RUNDOWN AND (ctr.TANGGAL BETWEEN '2015-07-01' AND '2015-07-15')
GROUP BY ctr.TANGGAL, NAMA_GRUP
All I want is just to SUM the column 'AVG_KPI', JUMLAH_TANGGAL and do the AVG of 'AVG_KPI' with total from JUMLAH_TANGGAL. Well, here is the result from my query above.
Here's my picture of my query result: http://i.stack.imgur.com/VJ4ma.png
Is there someone can give me some advice? I really stuck with it.
Try this.....
SELECT NAMA_GRUP, SUM(TOTAL_KPI_PROGRAM)/COUNT(TANGGAL) AS AVG_KPI, COUNT(TANGGAL) AS JUMLAH_TANGGAL
(
SELECT NAMA_GRUP, TOTAL_KPI_PROGRAM, ctr.TANGGAL
FROM ckm_t_grup ctg, ckm_t_program ctp, ckm_t_rundown ctr, ckm_t_calculate ctc
WHERE ctg.ID_GRUP = ctp.ID_GRUP AND ctp.ID_PROGRAM = ctr.ID_PROGRAM AND ctr.ID_RUNDOWN = ctc.ID_RUNDOWN AND (ctr.TANGGAL BETWEEN '2015-07-01' AND '2015-07-15')
UNION
SELECT NAMA_GRUP, TOTAL_KPI_PROGRAM, ctr.TANGGAL
FROM ckm_t_grup ctg, ckm_t_program ctp, ckm_t_rundown ctr, ckm_t_calculate_2 ctcc
WHERE ctg.ID_GRUP = ctp.ID_GRUP AND ctp.ID_PROGRAM = ctr.ID_PROGRAM AND ctr.ID_RUNDOWN = ctcc.ID_RUNDOWN AND (ctr.TANGGAL BETWEEN '2015-07-01' AND '2015-07-15')
) as tmp
GROUP BY NAMA_GRUP, TANGGAL
This will resolve your issue