MySQL SELECT calculation subject to stricter criteria than other SELECT fields--how? - mysql

Previously, the following query was limited based on work_category_id. Turns out we need information from as subclass of another work_category_id, so now I'm limiting on job_code_id instead. Job_code_id 29 is work_category_id 88, all other job_code_ids shown are work_category_id 36.
I need hours and performance for each of these job_code_ids, but specifically for the 'cases_per_hr' calculation, I only want to divide cases by all hours except those from job_code_id 29. I tried a nested case when, but that didn't seem to make much sense. Please help!
SELECT
d.user_id as 'employee_ID',
round((sum(d.goal_hours)/sum(d.worked_hours)),2)*100 as 'performance',
round(sum(d.goal_hours),2) as 'goal_hrs',
round(sum(d.worked_hours),2) as 'hrs_worked',
sum(d.cases) as 'total_cases_slctd',
round(sum(d.cases)/sum(d.worked_hours),0) as 'cases_per_hr',
d.metric_dt
FROM
roster r,
prod_detail d
WHERE
d.process_level = r.process_level
and d.accounting_unit = r.accounting_unit
and d.job_code_id in ('29','322','304','303','302','305','181')
-- and d.work_category_id in('36')

If you only want to exclude job_code_id = '29' from your cases_per_hr calculation, you could do the following. It does use CASE WHEN.
SELECT d.user_id as 'employee_ID',
round((sum(d.goal_hours)/sum(d.worked_hours)),2)*100 as 'performance',
round(sum(d.goal_hours),2) as 'goal_hrs',
round(sum(d.worked_hours),2) as 'hrs_worked',
sum(d.cases) as 'total_cases_slctd',
round(
sum(CASE WHEN d.job_code_id <> '29' THEN d.cases ELSE 0 END)
/
sum(CASE WHEN d.job_code_id <> '29' THEN d.worked_hours ELSE 0 END)
,0) as 'cases_per_hr',
d.metric_dt
FROM roster r,
prod_detail d
WHERE
d.process_level = r.process_level
and d.accounting_unit = r.accounting_unit
and d.job_code_id in ('29','322','304','303','302','305','181')

Related

Generating a table of subtraction of two colum count

Hello i want to make a summary table where the filter is the segment and date
The columns will be the subtraction of count of two column in same table so far i have come up to this
select
case
when SEGMENT='champion'THEN SUM(SEGMENTED_DATE = '2022-10-14')-SUM(SEGMENTED_DATE='2022-10-07')
END as total_change_champion,
case
when SEGMENT='Hibernating'THEN SUM(SEGMENTED_DATE = '2022-10-14')-SUM(SEGMENTED_DATE='2022-10-07')
END as total_change_hibernate
from weekly_customer_RFM_TABLE;
This query is giving me null value for columns
select
SUM(SEGMENTED_DATE = '2022-10-14')-
SUM(SEGMENTED_DATE='2022-10-07')as total_changes_in_14th
From weekly_customer_RFM_TABLE
where
SEGMENT ='Hibernating'
This query is actually giving me the result. but when I am going to make a consolidated table using different segment subtraction i am getting null value in my result table.Kindly help me out
my sample data
which is i want to substract totalcount of 2022/10/14 - 2022/10/07 for each segment
image is not loading unfortunately
You must include the CASE expressions inside the aggregate functions:
SELECT COUNT(CASE WHEN SEGMENT = 'champion' AND SEGMENTED_DATE = '2022-10-14' THEN 1 END) -
COUNT(CASE WHEN SEGMENT = 'champion' AND SEGMENTED_DATE = '2022-10-07' THEN 1 END) AS total_change_champion,
COUNT(CASE WHEN SEGMENT = 'Hibernating' AND SEGMENTED_DATE = '2022-10-14' THEN 1 END) -
COUNT(CASE WHEN SEGMENT = 'Hibernating' AND SEGMENTED_DATE='2022-10-07' THEN 1 END) AS total_change_hibernate
FROM weekly_customer_RFM_TABLE;
For MySql this can be simplified to:
SELECT SUM(SEGMENT = 'champion' AND SEGMENTED_DATE = '2022-10-14')-
SUM(SEGMENT = 'champion' AND SEGMENTED_DATE = '2022-10-07') AS total_change_champion,
SUM(SEGMENT = 'Hibernating' AND SEGMENTED_DATE = '2022-10-14')-
SUM(SEGMENT = 'Hibernating' AND SEGMENTED_DATE='2022-10-07') AS total_change_hibernate
FROM weekly_customer_RFM_TABLE;
You may also use a WHERE clause to filter the table for only the SEGMENTs and SEGMENTED_DATEs that you want:
WHERE SEGMENT IN ('champion', 'Hibernating') AND SEGMENTED_DATE IN ('2022-10-07', '2022-10-14')

PHP SQL declare YES or NO based on count withing query

I am searching for a way to make the sql statement declare a AS example as Yes when the value is greater than 0 and No if 0 after I count the result while retreiving the data from the database.
This (is not working) is what I tried so far. I hope my tryout is making sence. I first make a select count on planning_clientid the result is 0 or more. If the result is 0 I need timesonplanning (perhaps change that name after its working) to be No and if higher than Yes. So in steady of the count result I need Yes or No, Is this possible?
Part that is not working:
(CASE WHEN(SELECT COUNT(planning_clientid) FROM tbl_planning WHERE planning_afgehandeld = 0 AND a.client_id = planning_clientid)> 0 THEN 'Yes' ELSE 'No' END AS timesonplanning
The whole statement:
SELECT a.*, own1.naam AS resposible_btw, own2.naam AS resposible_client, (CASE WHEN(SELECT COUNT(planning_clientid) FROM tbl_planning WHERE planning_afgehandeld = 0 AND a.client_id = planning_clientid)> 0 THEN 'Yes' ELSE 'No' END AS timesonplanning FROM tbl_clients a LEFT JOIN gebruikers own1 ON own1.id = a.client_ownerob LEFT JOIN gebruikers own2 ON own2.id = a.client_owner
Desired result:
timesonplanning Yes (when count if higher than 0)
timesonplanning No (when count is 0)
The error you indicated in the comments indicates a syntax error (albeit in Dutch). This is indeed to be expected as the query you included doesn’t close the initial parenthesis character ( you used right before your CASE keyword.
Resolve this by removing the initial parenthesis before CASE (as it doesn’t seem particularly necessary in this context), or properly close it by inserting a close parenthesis ) after the END keyword:
SELECT a.*, own1.naam AS resposible_btw, own2.naam AS resposible_client, (CASE WHEN(SELECT COUNT(planning_clientid) FROM tbl_planning WHERE planning_afgehandeld = 0 AND a.client_id = planning_clientid)> 0 THEN 'Yes' ELSE 'No' END) AS timesonplanning FROM tbl_clients a LEFT JOIN gebruikers own1 ON own1.id = a.client_ownerob LEFT JOIN gebruikers own2 ON own2.id = a.client_owner

Trouble interpreting what is making my query so slow

I have a query that takes 15 seconds to get 350 results in a MySQL 5.6 Server and I am unable to diagnose why, I am still very new to database optimizing. U
The EXPLAIN visual does show some non-unique key lookups but each only says one 1 row look up.
The tabular EXPLAIN which I am not able to interpret and I am hoping someone else can here looks like .
I have tried switching the ending LIMIT = 350 to 100, 10, and the query takes exactly the same amount of time to run, about 15 seconds.
I have tried nixing the views but besides making it hard to recreate this query it did not improve performance.
Perhaps related, in other EXPLAIN statements in our MySQL DB, I've seen a view referenced with Materialized next to it, but that does not appear near next to any of the three views used in this query, in fact I don't even see the views referenced at all instead only the tables they reference. Is that a factor?
My last attempt was replacing the final selected column which is a listlineitems.* with the specific columns, since I've read that can improve speed and is just better practice, but I get the sense that is not going to dramatically improve this situation.
Here's the query -
SELECT
0 AS 'Check',
DATE_FORMAT(`listlineitems`.`dateEntered`,
'%Y-%m-%d') AS 'Date Entered',
`listlineitems`.`itemId` AS 'parentTableIdx',
`listlineitems`.`parentProjectId` AS 'parentProjectIdx',
`listlineitems`.`idx` AS 'ID',
IF(`listlineitems`.`active` = 1,
'Active',
'Inactive') AS 'Active/Inactive',
CONCAT(`listUsers`.`FirstName`,
' ',
`listUsers`.`LastName`) AS 'Employee',
CASE `listlineitems`.`type`
WHEN 1 THEN 'Time Entry'
WHEN 2 THEN 'Expense Entry'
END AS 'Type',
`listcustomers`.`name` AS 'Customer',
`listlocations`.`name` AS 'Location',
`listareas`.`name` AS 'Area',
`listassets`.`name` AS 'Asset',
`listprojects`.`name` AS 'Project',
`listprojects`.`number` 'Project #',
`listprojects`.`autoassign` 'autoassign',
`listactivities`.`name` AS 'Activity',
(CASE `listlineitems`.`type`
WHEN 1 THEN `listlineitems`.`qty`
WHEN 2 THEN `listlineitems`.`qty`
END) AS 'Quantity',
`listlineitems`.`taxable` AS 'Taxable',
`listlineitems`.`totalAmount` - `listlineitems`.`taxAmount` AS 'Pre-Tax Amount',
`listlineitems`.`taxAmount` AS 'Tax Amount',
`listlineitems`.`totalAmount` AS 'Total Amount',
`listCustomers`.`idx` AS 'parentCustomerIdx',
`listLocations`.`idx` AS 'parentLocationIdx',
`listAreas`.`idx` AS 'parentAreaIdx',
`listAssets`.`idx` AS 'parentAssetIdx',
CONCAT(`listcustomers`.`name`,
'/',
`listlocations`.`name`,
'/',
`listareas`.`name`,
'/',
`listassets`.`name`,
'/',
`listprojects`.`name`) AS 'Path',
IF(`listlineitems`.`customerViewable` = 1,
'Yes',
'No') AS 'Cust. Viewable',
(CASE
WHEN `listlineitems`.`type` = 2 THEN `listexpenseentry`.`TotalCostToPSI` - `listexpenseentry`.`TaxCostToPSI`
ELSE `listlineitems`.`totalAmount` - `listlineitems`.`taxAmount`
END) AS 'preTaxCostPSI',
(CASE
WHEN `listlineitems`.`type` = 2 THEN `listexpenseentry`.`TaxCostToPSI`
ELSE `listlineitems`.`taxAmount`
END) AS 'taxCostPSI',
(CASE
WHEN `listlineitems`.`type` = 2 THEN `listexpenseentry`.`TotalCostToPSI`
ELSE `listlineitems`.`totalAmount`
END) AS 'totalCostPSI',
view_solinx2.lastAltered AS 'lastalteredSO',
view_polinx2.lastAlteredPO AS 'lastalteredPO',
view_invlinx2.lastAlteredInv AS 'lastalteredInv',
view_solinx2.lastAlteredAfterConfirmation AS 'lastAlteredAfterConfirmation',
view_solinx2.roleIdSO AS 'roleIdSO',
view_polinx2.roleIdPO AS 'roleIdPO',
view_polinx2.userIdPO AS 'userIdPO',
view_polinx2.lastAlteredafterConfirmation AS 'lastAlteredAfterConfirmationPO',
view_invlinx2.roleIdInv AS 'roleIdInv',
view_invlinx2.userIdInv AS 'userIdInv',
view_invlinx2.lastAlteredafterConfirmation AS 'lastAlteredAfterConfirmationInv',
view_solinx2.roleId AS 'roleId',
view_solinx2.userId AS 'userId',
view_solinx2.soId AS 'SOId',
view_solinx2.autoassignSO AS 'autoassignSO',
IF(view_solinx2.notNeeded = 1,
'Not Needed',
view_solinx2.number) AS 'SOname',
view_solinx2.dateEntered AS 'SoDate',
view_solinx2.totalSOAmount AS 'SoTotal',
view_invlinx2.invId AS 'InvId',
IF(view_solinx2.notNeeded = 1,
'------',
view_invlinx2.`number`) AS 'InvName',
view_invlinx2.dateEntered AS 'InvDate',
view_invlinx2.amount AS 'InvTotal',
view_polinx2.poId AS 'POId',
IF(view_solinx2.notNeeded = 1,
'------',
view_polinx2.`number`) AS 'POName',
view_polinx2.dateEntered AS 'PODate',
view_polinx2.amount AS 'POTotal',
(SELECT
listsalesorders.number
FROM
listsalesorders
WHERE
listsalesorders.idx = autoassign) AS 'test',
`listlineitems`.*
FROM
`listlineitems`
LEFT JOIN
`listUsers` ON `listlineitems`.`individualId` = `listUsers`.`idx`
LEFT JOIN
`listprojects` ON `listlineitems`.`parentProjectId` = `listprojects`.`idx`
LEFT JOIN
`listassets` ON `listlineitems`.`parentAssetId` = `listassets`.`idx`
LEFT JOIN
`listareas` ON `listlineitems`.`parentAreaId` = `listareas`.`idx`
LEFT JOIN
`listlocations` ON `listlineitems`.`parentLocationId` = `listlocations`.`idx`
LEFT JOIN
`listcustomers` ON `listlineitems`.`parentCustomerId` = `listcustomers`.`idx`
LEFT JOIN
`listactivities` ON `listactivities`.`idx` = `listlineitems`.`activityCode`
LEFT JOIN
`listexpenseentry` ON (`listexpenseentry`.`idx` = `listlineitems`.`itemId`
AND `listlineitems`.`type` = 2)
LEFT JOIN
view_solinx2 ON view_solinx2.idx = listlineitems.idx
LEFT JOIN
view_polinx2 ON view_polinx2.idx = listlineitems.idx
LEFT JOIN
view_invlinx2 ON view_invlinx2.idx = listlineitems.idx
GROUP BY `listlineitems`.`idx`
ORDER BY `listlineitems`.`dateEntered` DESC
LIMIT 10;
I am at a loss as to what else I can do to improve this and any suggestions are very much appreciated.
You are selecting everything from listlineitems table (100+ K records), joining many tables, then grouping by idx and then throwing out most results.
You can:
Try to add unique index (dateEntered, idx) to listlineitems
Try limit listlineitems by dateEntered if acceptable (WHERE dateEntered > DATE_SUB(NOW(), INTERVAL 30 DAYS)). dateEntered must be indexed
Try to put select from listlineitems + grouping + limit into subquery so MySQL will do joins to only these 10 rows returned by subquery.
Convert dependent subquery (listsalesorders) to left join

Summing Custom Column

First Stackoverflow question - so go easy on me :).
Hello, I am trying to flag items as "Attributed" using the following query that I have written. Essentially, if a patient ID has a PERSON_PROVIDER_RELATIONSHIP flag, they are given a 1 for that instance. If they have another type of flag (there are two other possible flags you can receive). Everything goes fine (the assigning of "1" to the instances of PERSON_PROVIDER_RELATIONSHIP), but then when I try to sum that custom column I created ("Attribution"), I get this error: (Column "Attribution" does not exist). I get this error whether I try to make another column that does the summing or when I add a "having" clause to the end where I state I only want to see records with a sum of >0. Any help would be appreciated here! I'm using MySQL to write this and am happy to provide any clarifying information.
select distinct c.empi_id as "Patient",
c.incurred_from_date as "Service Date",
(case when c.billing_organization_source_id IN ('xxxx','yyyy') then 1 else 0
end) as "In-Network Indicator",
(case when t.ref_record_type = 'PERSON_PROVIDER_RELATIONSHIP' then 1 else 0
end) as "Attribution",
(sum("Attribution") over (partition by c.empi_id)) as "Attribution Flag",
p.cleanprovidername as "Provider", t.ref_record_type
from ph_f_annotated_claim c
left outer join PH_F_Attribution_Component_Data_Point t
on t.empi_id = c.empi_id and t.population_id = c.population_id
inner join ph_d_personnel_alias a
on a.prsnl_id = t.prsnl_id
inner join xxxx_xxxx_xxxx_xxxx p
on a.prsnl_alias_id = p.NPI
where (c.bill_type_code like '33%'
or c.bill_type_code like '32%'
or c.bill_type_code like '033%'
or c.bill_type_code like '032%')
and c.source_description = 'MSSP Claims'
and c.incurred_from_date >= '2015-12-01'
and c.incurred_from_date <= '2017-01-31'
and c.population_id = '2feb2cb1-be55-4827-a21f-4e2ef1a40340'
and p.DegreeName IN ('MD','DO')
and a.prsnl_alias_type = 'NPI'
and p.PrimaryPHO = 'Yes'
group by c.empi_id, c.incurred_from_date, c.billing_organization_source_id,
p.cleanprovidername, t.ref_record_type
You can't use an aliased column name as an expression in the same SELECT clause. You have to do something like this:
sum(case when t.ref_record_type = 'PERSON_PROVIDER_RELATIONSHIP' then 1 else 0 end) over (partition by c.empi_id) as "Attribution Flag"

How to specify an array in the Where clause using Moodle DB API Call?

I want to filter data based on an array, similar to "in" keyword in a query:
SELECT count(*) as number_of_records,
count(CASE WHEN result = 'SUCCESS' THEN 1 END) as successful_builds_no,
min(CASE WHEN result = 'FAILURE' THEN 0 ELSE 1 END) as is_success,
min(duration) as best_duration,
max(build_date) as build_date
FROM mdl_selenium_results
WHERE build_date in ('2014-03-13', '2014-03-12')
GROUP BY build_date
How to achieve that using Moodle DB api??
If you are creating an SQL query to use within Moodle, you could just use the IN keyword, exactly as you have done in the example.
Alternatively, to make it a bit more cross-DB compatible, and to make your queries run a bit faster when there is only one item in the list, you can write:
list($dsql, $dparam) = $DB->get_in_or_equal(array('2014-03-13', '2014-03-12'), SQL_PARAMS_NAMED);
$sql = "SELECT count(*) as number_of_records,
count(CASE WHEN result = 'SUCCESS' THEN 1 END) as successful_builds_no,
min(CASE WHEN result = 'FAILURE' THEN 0 ELSE 1 END) as is_success,
min(duration) as best_duration,
max(build_date) as build_date
FROM {selenium_results}
WHERE build_date $dsql
GROUP BY build_date";
$result = $DB->get_records_sql($sql, $dparams);
OR, if you just want to get all the matching records from the given table (and then worry about doing the calculations in PHP), you could write:
$result = $DB->get_records_list('selenium_results', 'build_date', array('2014-03-13', '2014-03-12'));
(I've not run any of the code above, so apologies for any typos)