is there a better way to write the query that I wrote - mysql

I have the following query which gives me the overall status of a project. I was wondering if there was a better way to write the same query.
an example schema for the table:
CREATE TABLE `test_status`
(
`test_id` int
(11) NOT NULL,
`group_id` int
(11) NOT NULL,
`sub_test_id` int
(11) NOT NULL,
`project_id` int
(11) NOT NULL,
`collection_status` varchar
(20) DEFAULT NULL,
`labeling_status` varchar
(20) DEFAULT NULL,
`upload_status` varchar
(20) DEFAULT NULL,
`upload_date` date DEFAULT NULL,
`disk_number` int
(11) DEFAULT NULL,
`subject_id` varchar
(10) DEFAULT NULL,
`collection_id` varchar
(25) DEFAULT NULL,
`assigned_to` int
(11) DEFAULT NULL,
`assigned_on` date DEFAULT NULL,
`turned_in_date` date DEFAULT NULL,
PRIMARY KEY
(`test_id`,`group_id`,`sub_test_id`,`project_id`));
My Query:
select
(select count(*)
from test_status
where project_id = 7 and collection_status = 'COLLECTED') as collected,
(select count(*)
from test_status
where project_id = 7 and collection_status = 'SCHEDULED') as scheduled,
(select count(*)
from test_status
where project_id = 7 and collection_status = 'CORRUPTED') as corrupted,
(select count(*)
from test_status
where project_id = 7 and collection_status is NULL) as 'not collected',
(select count(*)
from test_status
where project_id = 7 and ((labeling_status = 'GOOD' and (upload_status != 'UPLOADED' or upload_status != 'QUEUED')) or (labeling_status = 'Labeled'))) as 'Labeled',
(select count(*)
from test_status
where project_id = 7 and (labeling_status = 'RAW') or (labeling_status = 'ASSIGNED') ) as 'to be labeled',
(select count(*)
from test_status
where project_id = 7 and labeling_status = 'RE-LABEL') as 'Re-label',
(select count(*)
from test_status
where project_id = 7 and (upload_status = 'UPLOADED' or upload_status = 'QUEUED')) as 'Uploaded',
(select count(*)
from test_status
where project_id = 7 and labeling_status = 'GOOD' and upload_status is null) as 'ready to be uploaded';

You can try to use condition aggregate function will be better.
let the condition in CASE WHEN
SELECT
COUNT(CASE WHEN collection_status = 'COLLECTED' THEN 1 END),
COUNT(CASE WHEN collection_status = 'SCHEDULED' THEN 1 END),
COUNT(CASE WHEN collection_status = 'CORRUPTED' THEN 1 END),
COUNT(CASE WHEN collection_status is NULL THEN 1 END),
COUNT(CASE WHEN ((labeling_status = 'GOOD' and (upload_status != 'UPLOADED' or upload_status != 'QUEUED')) or (labeling_status = 'Labeled'))THEN 1 END),
COUNT(CASE WHEN (labeling_status = 'RAW') or (labeling_status = 'ASSIGNED') THEN 1 END),
COUNT(CASE WHEN labeling_status = 'RE-LABEL' THEN 1 END),
COUNT(CASE WHEN (upload_status = 'UPLOADED' or upload_status = 'QUEUED') THEN 1 END),
COUNT(CASE WHEN labeling_status = 'GOOD' and upload_status is null THEN 1 END)
FROM test_status
WHERE project_id = 7
Or you can try a simpler way, SUM with bool (0 or 1) to count
SELECT
SUM(collection_status = 'COLLECTED'),
SUM(collection_status = 'SCHEDULED'),
SUM(collection_status = 'CORRUPTED' ),
SUM(collection_status is NULL ),
SUM(((labeling_status = 'GOOD' and (upload_status != 'UPLOADED' or upload_status != 'QUEUED')) or (labeling_status = 'Labeled'))),
SUM((labeling_status = 'RAW') or (labeling_status = 'ASSIGNED') ),
SUM(labeling_status = 'RE-LABEL' ),
SUM((upload_status = 'UPLOADED' or upload_status = 'QUEUED')),
SUM(labeling_status = 'GOOD' and upload_status is null )
FROM test_status
WHERE project_id = 7

Related

How to get votes with results with percent calculating

In my Laravel 5.7/mysql 5 app I have a table with votes results:
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`vote_item_id` INT(10) UNSIGNED NOT NULL,
`user_id` INT(10) UNSIGNED NOT NULL,
`is_correct` TINYINT(1) NOT NULL DEFAULT '0',
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
where boolean is_correct field is if answer was correct or incorrect.
I need to get data on percents of correct answers.
Creating such request
$voteItemUsersResultsCorrect = VoteItemUsersResult:: // Grouped by vote name
getByIsCorrect(true)->
getByCreatedAt($filter_voted_at_from, ' > ')->
getByCreatedAt($filter_voted_at_till, ' <= ')->
getByUserId($filterSelectedUsers)->
getByVote($filterSelectedVotes)->
getByVoteCategories($filterSelectedVoteCategories)->
getByVoteIsQuiz(true)->
getByVoteStatus('A')->
select( \DB::raw('count(vote_item_users_result.id) as count, votes.id, votes.name as vote_name') )->
orderBy('vote_name', 'asc')->
groupBy( 'votes.id' )->
groupBy( 'vote_name' )->
join(\DB::raw('vote_items'), \DB::raw('vote_items.id'), '=', \DB::raw('vote_item_users_result.vote_item_id'))->
join(\DB::raw('votes '), \DB::raw('votes.id'), '=', \DB::raw('vote_items.vote_id'))->
get();
I can get number of correct votes with sql request.
SELECT count(vote_item_users_result.id) AS count, votes.id, votes.name AS vote_name
FROM `vote_item_users_result`
INNER JOIN vote_items on vote_items.id = vote_item_users_result.vote_item_id
INNER JOIN votes on votes.id = vote_items.vote_id
WHERE `vote_item_users_result`.`is_correct` = '1' AND vote_item_users_result.created_at > '2018-08-01' AND vote_item_users_result.created_at <= '2018-09-22 23:59:59' AND `votes`.`is_quiz` = '1' AND `votes`.`status` = 'A'
GROUP BY `votes`.`id`, `vote_name`
ORDER BY `vote_name` asc
I know a way to get 2nd similar request with is_correct = '0' and on php side to combine results with percent calculating,
but I wonder if that could be done with eloquent in 1 request?
If yes, how ?
Thanks!
One correct raw MySQL would use conditional aggregation:
SELECT
v.id,
100.0 * COUNT(CASE WHEN vir.is_correct = 1 THEN 1 END) / COUNT(*) AS pct_correct,
100.0 * COUNT(CASE WHEN vir.is_correct = 0 THEN 1 END) / COUNT(*) AS pct_incorrect
FROM votes v
INNER JOIN vote_items vi
ON v.id = vi.vote_id
INNER JOIN vote_item_users_result vir
ON vi.id = vir.vote_item_id
WHERE
vir.created_at > '2018-08-01' AND vir.created_at < '2018-09-23' AND
v.is_quiz = '1' AND
v.status = 'A'
GROUP BY
v.id;
Now we can try writing Laravel code for this:
DB::table('vote')
->select('vote.id',
DB::raw('100.0 * COUNT(CASE WHEN vir.is_correct = 1 THEN 1 END) / COUNT(*) AS pct_correct'),
DB::raw('100.0 * COUNT(CASE WHEN vir.is_correct = 0 THEN 1 END) / COUNT(*) AS pct_incorrect'))
->join('vote_items', 'votes.id', '=', 'vote_items.vote_id')
->join('vote_item_users_result', 'vote_items.id', '=', 'vote_item_users_result.vote_item_id ')
->where([
['vote_item_users_result.created_at', '>', '2018-08-01'],
['vote_item_users_result.created_at', '<', '2018-09-23'],
['vote.is_quiz', '=', '1'],
['vote.status', '=', 'A']
])
->groupBy('vote.id')
->get();

MYSQL Error code 1248 Every derived table must have it's own alias

MYSQL Error code 1248 Every derived table must have it's own alias
select supplier_id, supplier_name, strong_answers from
(select campaign_suppliers.id supplier_id, campaign_suppliers.supplier_name supplier_name,
count(case when supplier_answers.binary_answer is not null
or supplier_answers.value_answer is not null then 1 end) strong_answers
from supplier_answers join campaign_suppliers on (supplier_answers.supplier_id = campaign_suppliers.id)
where supplier_answers.campaign_id = 1 group by campaign_suppliers.id, campaign_suppliers.supplier_name
having count(case when supplier_answers.binary_answer is not null
or supplier_answers.value_answer is not null then 1 end) >=
(select count(distinct supplier_answers.question_index) from supplier_answers where campaign_id = 1))
where strong_answers >= (select count(distinct supplier_answers.question_index) from supplier_answers where campaign_id = 1)
You need a table name alias for the from ( ... ) t see // <---- symbol below
select t.supplier_id, t.supplier_name, t.strong_answers from (
select campaign_suppliers.id supplier_id, campaign_suppliers.supplier_name supplier_name,
count(case when supplier_answers.binary_answer is not null
or supplier_answers.value_answer is not null then 1 end) strong_answers
from supplier_answers join campaign_suppliers on (supplier_answers.supplier_id = campaign_suppliers.id)
where supplier_answers.campaign_id = 1 group by campaign_suppliers.id, campaign_suppliers.supplier_name
having count(case when supplier_answers.binary_answer is not null
or supplier_answers.value_answer is not null then 1 end) >=
(select count(distinct supplier_answers.question_index)
from supplier_answers where campaign_id = 1)) t //<---- here you need a table name eg: t
where t.strong_answers >= (select count(distinct supplier_answers.question_index) from supplier_answers where campaign_id = 1)

Passing parameter to a table-valued function

I am trying to pass a parameter value to a table-valued function which has four parameters and "returns table". However, I receive following error when I pass a parameter value to one of its varchar parameter:
Msg 8114, Level 16, State 5, Line 6 Error converting data type varchar
to bigint.
declare #Scenario1 as varchar(30)
set #Scenario1 = '2017_B01'
select *
From [dbo].[fn_GetAEAssumptionFacts](#Scenario1,null,null,null) fng
Glimpse at function:
CREATE FUNCTION [dbo].[fn_GetAEAssumptionFacts]
(
#pScenarioName varchar(500) = NULL
,#pBuildingID varchar(500) = NULL
,#pLeaseID varchar(500) = NULL
,#pTenantName varchar(500) = NULL
)
RETURNS TABLE
AS
RETURN
select
.....
from ae11.dbo.rvw_FinancialLineItems fli
....
INNER JOIN ae11.dbo.rvw_Scenarios s on s.Id = pas.ScenarioId
left join
(select
externalID,
PropertyAssetId,
LeaseID,
BeginDate
from ae11.dbo.ivw_Leases
WHERE PropertyAssetID IN
(select ID from AE11.dbo.PropertyAssets where scenarioID =
(CASE WHEN isnull(#pScenarioName, '') = ''
THEN (select ID from AEX.[dbo].[ConfigurationFieldTable]
where [Type] = 'Lease Connect Current Scenario' )
ELSE #pScenarioName
END)
)
) lea
ON lea.LeaseID = uni.ExternalID
AND lea.PropertyAssetID = uni.PropertyAssetId
where 1=1
......
AND s.id = (CASE WHEN isnull(#pScenarioName, '') = ''
THEN (select ID from AEX.[dbo].[ConfigurationFieldTable]
where [Type] = 'Lease Connect Current Scenario' )
ELSE #pScenarioName
END)
Here
(CASE WHEN isnull(#pScenarioName, '') = ''
THEN (select ID from AEX.[dbo].[ConfigurationFieldTable]
where [Type] = 'Lease Connect Current Scenario' )
ELSE #pScenarioName
END)
You are taking a value depending on #ScenarioName. This will either be the result of select ID from AEX.[dbo].[ConfigurationFieldTable] WHERE... or the content of #ScenarioName.
I assume, that this ID is a bigint, while your #SenarioName is a string. And the s.ID you want to compare it against - I don't know...
But - to be honest - my magic crystall ball is out for cleaning and the information you provide is not enough.

Optimizing Slow SQL Query

I have a query and it uses MySQL as its database. Now I'm going nuts as to why it took 11 minutes to render result, I have like 7K+ records on my table and running a recursive subquery(?), I'm not entirely sure if this is what eats up the memory but if you could look and give some remedy as to how can this be optimized I would be very happy and contented...
My goal is to compress records relative to a particular person... And rank them based on time finished.
Table structure:
CREATE TABLE `temptbl_raceeventresult_step1` (
`RunCatEventId` INT(11) NOT NULL,
`RunEventId` INT(11) NOT NULL,
`CategoryId` INT(11) NOT NULL,
`FullName` VARCHAR(255) NOT NULL,
`BIB` INT(11) NOT NULL,
`Category` DECIMAL(16,3) NOT NULL,
`Ord` INT(11) NOT NULL,
`TransitionId` INT(11) NOT NULL,
`Time` DATETIME NOT NULL)
COLLATE='latin1_swedish_ci'ENGINE=MyISAM;
//Query
SELECT
UCASE(g1.Name) Name
,g1.BIB
,g1.TimeDerived
,g1.CategoryName
,g1.TotalPace
,g1.Category
,COUNT(*) AS rank
FROM
(
SELECT
a.FullName Name,
a.RunCatEventId,
a.RunEventId,
a.CategoryId,
a.BIB,
a.Category,
a.Ord,
a.TransitionId,
SEC_TO_TIME(SUM(TIME_TO_SEC(Time) - (SELECT TIME_TO_SEC(Time) TimeMinuend FROM temptbl_raceeventresult_step1 WHERE BIB = a.bib AND (Ord + 1) = a.Ord AND CategoryId = a.CategoryId))) TimeDerived,
SEC_TO_TIME(SUM(TIME_TO_SEC(Time) - (SELECT TIME_TO_SEC(Time) TimeMinuend FROM temptbl_raceeventresult_step1 WHERE BIB = a.bib AND (Ord + 1) = a.Ord AND CategoryId = a.CategoryId)) / a.Category) TotalPace
FROM temptbl_raceeventresult_step1 a
JOIN (SELECT #cat:=null) xyz
GROUP BY a.RunCatEventId, a.RunEventId, a.CategoryId, a.FullName, a.BIB
) g1
JOIN
(
SELECT
a.FullName Name,
a.RunCatEventId,
a.RunEventId,
a.CategoryId,
a.BIB,
a.Category,
a.Ord,
a.TransitionId,
SEC_TO_TIME(SUM(TIME_TO_SEC(Time) - (SELECT TIME_TO_SEC(Time) TimeMinuend FROM temptbl_raceeventresult_step1 WHERE BIB = a.bib AND (Ord + 1) = a.Ord AND CategoryId = a.CategoryId))) TimeDerived,
SEC_TO_TIME(SUM(TIME_TO_SEC(Time) - (SELECT TIME_TO_SEC(Time) TimeMinuend FROM temptbl_raceeventresult_step1 WHERE BIB = a.bib AND (Ord + 1) = a.Ord AND CategoryId = a.CategoryId)) / a.Category) TotalPace
FROM temptbl_raceeventresult_step1 a
JOIN (SELECT #cat:=null) xyz
GROUP BY a.RunCatEventId, a.RunEventId, a.CategoryId, a.FullName, a.BIB
) g2
ON (g2.TimeDerived, g2.bib) <= (g1.TimeDerived, g1.bib) AND g1.Category = g2.Category
WHERE g2.Category = 5 AND g1.RunEventId = 3
GROUP BY g1.Name
,g1.BIB
,g1.TimeDerived
,g1.CategoryName
,g1.TotalPace
,g1.Category
ORDER BY g1.Category, rank

mysql get difference of two sum on the same table

how can i get the result in just one query instead of this one:
SELECT SUM(`quantity`) as type0 FROM `fruits_delivery`
WHERE `fid`='1001' AND `type`=0;
result_1 = type0 ;
SELECT SUM(`quantity`) as type1 FROM `fruits_delivery`
WHERE `fid`='1001' AND `type`=1;
result_2 = type1 ;
final_result = result_1 - result_2;
You should use this
SELECT sum(IF(`type`=0, `quantity`, 0))-sum(IF(`type`=1, `quantity`, 0))
AS `final_result`
FROM `fruits_delivery`
WHERE `fid` = '1001'
sqlfiddle
Old Answer
SELECT T1.result - T2.result AS `final_result`
FROM (SELECT Sum(`quantity`) AS result,
`fid`
FROM `fruits_delivery`
WHERE `fid` = '1001'
AND `type` = 0
LIMIT 1) AS T1
JOIN (SELECT Sum(`quantity`) AS result,
`fid`
FROM `fruits_delivery`
WHERE `fid` = '1001'
AND `type` = 1
LIMIT 1) AS T2
ON ( T1.fid = T2.fid )
SQLFiddle
Alternatively, you can also do it using CASE
SELECT SUM(CASE WHEN type = 0 THEN quantity ELSE 0 END) -
SUM(CASE WHEN type = 1 THEN quantity ELSE 0 END)
AS final_result
FROM fruits_delivery
WHERE fid = '1001'
SQLFiddle Demo