It is possible that this has been answered somewhere already but I couldn't find it.
So would appreciate if someone could help me with this sql statement again.
This is the sql statement which I have so far:
SELECT * , Round( (Rate * TIME_TO_SEC( Total ) /3600 ) , 2) AS revenue
FROM (SELECT event.eventID, event.staffID, event.role, TIMEDIFF( Time, Pause )
AS Total,
CASE WHEN Position = 'Teamleader'
THEN (Teamleader)
WHEN Position = 'Waiter'
THEN (Waiter)
ELSE '0'
END AS Rate
FROM event, rates, eventoverview
WHERE Storno =0
AND event.eventID= eventoverview.eventID
AND event.clientid = rates.clientid
GROUP BY event.eventID, event.clientID)q1
GROUP BY q1.staffID
The table I am getting is now giving me a total rate per staff and event.
But what I would like to achieve is a sum of those rates per staff.
So basically a sum of the revenue.
Hope someone can help me. Thanks in advance
You can enclose your query in a subquery and do that in the outer query like this:
SELECT *,
SUM(revenue)
FROM
(
SELECT * ,
Round( (Rate * TIME_TO_SEC( Total ) /3600 ) , 2) AS revenue
FROM
(
SELECT
event.eventID,
event.staffID,
event.role,
TIMEDIFF( Time, Pause ) AS Total,
CASE WHEN Position = 'Teamleader' THEN (Teamleader)
WHEN Position = 'Waiter' THEN (Waiter)
ELSE '0'
END AS Rate
FROM event
INNER JOIN rates ON event.clientid = rates.clientid
INNER JOIN eventoverview ON event.eventID = eventoverview.eventID
WHERE Storno =0
GROUP BY event.eventID, event.clientID
)q1
GROUP BY q1.staffID
) AS t
GROUP BY staffID;
Note that: You might get inconsistent data, due to the use of SELECT * with GROUP BY staffID only, the columns that are not in the GROUP BY clause need to be enclosed with an aggregate function otherwise mysql will get an arbitrary value for it. This is not recommended and it it is not the standard way to do so.
Related
I was on the "hospital_payment_data" table.
I want to call up the data of the number of data, the cache_account_received sum, and the total_medical_bills sum, and then bring up the mount sum value from the cash_recipit_rowtable to express. What should I do?
hospital_payment_data
cash_receipt_row
I want result
However, sending the following queries results in the following:
SELECT
COUNT(*) as total,
SUM(cash_amount_received) AS sum_cash_amount_received,
COUNT(
IF(total_medical_bills >= 100000 AND
cash_amount_received , total_medical_bills, NULL)
) as obligatory_issue,
SUM(
IF(total_medical_bills >= 100000 AND
cash_amount_received , cash_amount_received, NULL)
) as sum_obligatory_issue,
SUM(amount) AS sum_amount
FROM (
SELECT total_medical_bills, cash_amount_received, amount
FROM hospital_payment_data, cash_receipt_row
) AS a
wrong result
Try this.
SELECT
COUNT(*) as total,
SUM(cash_amount_received) AS sum_cash_amount_received,
COUNT(
IF(total_medical_bills >= 100000 AND
cash_amount_received , total_medical_bills, NULL)
) as obligatory_issue,
SUM(
IF(total_medical_bills >= 100000 AND
cash_amount_received , cash_amount_received, NULL)
) as sum_obligatory_issue,
SUM(amount) AS sum_amount
FROM (
SELECT total_medical_bills, cash_amount_received, amount
FROM hospital_payment_data, cash_receipt_row
WHERE hospital_payment_data.id = cash_receipt_row.id
) AS a
Never use commas in the FROM clause. Always use proper, explicit, standard, readable JOIN syntax.
You can also simplify your counting logic in MySQL. There is no need for IF() or a subquery:
SELECT COUNT(*) as total,
SUM(cash_amount_received) AS sum_cash_amount_received,
SUM( total_medical_bills >= 100000 AND
obligatory_issue <> 0
) as obligatory_issue,
SUM(CASE WHEN total_medical_bills >= 100000
THEN cash_amount_received
END) as sum_obligatory_issue,
SUM(amount) AS sum_amount
FROM hospital_payment_data hpd JOIN
cash_receipt_row crr
ON hpd.id = crr.id;
You'll notice that where conditional logic is needed, then this uses the standard SQL construct, CASE, rather than IF.
I'm trying to make a SQL query on some flights (called legs). The goal is to know how many flights are on time, how many have between 5 and 15 mins of delay and how many more than 15.
Using subqueries, I managed to get a first result :
SELECT
count(*) as 'leg total',
leg2.l2count as 'less than 15min delay',
round(leg2.l2count / count(*) * 100, 2) as 'less than 15min delay percentage',
leg3.l3count as 'more than 15min delay',
round(leg3.l3count / count(*) * 100, 2) as 'more than 15min delay percentage',
count(*) - leg2.l2count - leg3.l3count as 'on time',
round((count(*) - leg2.l2count - leg3.l3count) / count(*) * 100, 2) as 'on time percentage'
FROM TBL_leg leg -- previsional dates
JOIN TBL_flight_reports fr ON leg.id = fr.leg_ops_id, -- realized dates
(
SELECT count(l2.id) as l2count
FROM TBL_leg l2
JOIN TBL_flight_reports fr2 ON l2.id = fr2.leg_ops_id
WHERE (
timediff(fr2.arrival_date_block, l2.to_date_time) > SEC_TO_TIME(5*60) AND
timediff(fr2.arrival_date_block, l2.to_date_time) < SEC_TO_TIME(15*60)
)
OR (
timediff(fr2.departure_date_block, l2.start_date_time) > SEC_TO_TIME(5*60) AND
timediff(fr2.departure_date_block, l2.start_date_time) < SEC_TO_TIME(15*60)
)
) leg2, -- delays between threshold and 15min
(
SELECT count(l3.id) as l3count
FROM TBL_leg l3
JOIN TBL_flight_reports fr3 ON l3.id = fr3.leg_ops_id
WHERE (
timediff(fr3.arrival_date_block, l3.to_date_time) > SEC_TO_TIME(15*60)
)
OR (
timediff(fr3.departure_date_block, l3.start_date_time) > SEC_TO_TIME(15*60)
)
) leg3 -- delays of more than 15min
;
This query seems to be fine.
Now, i'm trying to sort my results : in my TBL_leg table, there is an airplane_id column and I want to group my results by it. The goal being to have my delays by airplane.
The issue is getting my grouping in my subqueries. I'm missing some logic right there.
Also, if you have some better solution for my main issue (my current query), feel free :)
Regards
Make sure each sub query is grouped by the airplane id and add the airplane id to the select of the sub query and then join by the airplane id.
e.g. 2nd leg:
left join (
SELECT l2.airplane_id, count(l2.id) as l2count
FROM TBL_leg l2
JOIN TBL_flight_reports fr2 ON l2.id = fr2.leg_ops_id
WHERE (
timediff(fr2.arrival_date_block, l2.to_date_time) > SEC_TO_TIME(5*60) AND
timediff(fr2.arrival_date_block, l2.to_date_time) < SEC_TO_TIME(15*60)
)
OR (
timediff(fr2.departure_date_block, l2.start_date_time) > SEC_TO_TIME(5*60) AND
timediff(fr2.departure_date_block, l2.start_date_time) < SEC_TO_TIME(15*60)
)
GROUP BY l2.airplane_id
) leg2 ON leg.airplane_id = leg2.airplane_id
Group the total query on airplane_id as well.
I have an data set that simulates the rate of return for a trading account. There is an entry for each day showing the balance and the open equity. I want to calculate the yearly, or quarterly, or monthly change and percent gain or loss. I have this working for daily data, but for some reason I can't seem to get it to work for yearly data.
The code for daily data follows:
SELECT b.`Date`, b.Open_Equity, delta,
concat(round(delta_p*100,4),'%') as delta_p
FROM (SELECT *,
(Open_Equity - #pequity) as delta,
(Open_Equity - #pequity)/#pequity as delta_p,
(#pequity:= Open_Equity)
FROM tim_account_history p
CROSS JOIN
(SELECT #pequity:= NULL
FROM tim_account_history
ORDER by `Date` LIMIT 1) as a
ORDER BY `Date`) as b
ORDER by `Date` ASC
Grouping by YEAR(Date) doesn't seem to make the desired difference. I have tried everything I can think of, but it still seems to return daily rate of change even if you group by month or year, etc. I think I'm not using windowing correctly, but I can't seem to figure it out. If anyone knows of a good book about this sort of query I'd appreciate that also.
Thanks.sqlfiddle example
Using what Lolo contributed, I have added some code so the data comes from the last day of the year, instead of the first. I also just need the Open_Equity, not the sum.
I'm still not certain I understand why this works, but it does give me what I was looking for. Using another select statement as a from seems to be the key here; I don't think I would have come up with this without Lolo's help. Thank you.
SELECT b.`yyyy`, b.Open_Equity,
concat('$',round(delta, 2)) as delta,
concat(round(delta_p*100,4),'%') as delta_p
FROM (SELECT *,
(Open_Equity - #pequity) as delta,
(Open_Equity - #pequity)/#pequity as delta_p,
(#pequity:= Open_Equity)
FROM (SELECT (EXTRACT(YEAR FROM `Date`)) as `yyyy`,
(SUBSTRING_INDEX(GROUP_CONCAT(CAST(`Open_Equity` AS CHAR) ORDER BY `Date` DESC), ',', 1 )) AS `Open_Equity`
FROM tim_account_history GROUP BY `yyyy` ORDER BY `yyyy` DESC) p
CROSS JOIN
(SELECT #pequity:= NULL) as a
ORDER BY `yyyy` ) as b
ORDER by `yyyy` ASC
Try this:
SELECT b.`Date`, b.Open_Equity, delta,
concat(round(delta_p*100,4),'%') as delta_p
FROM (SELECT *,
(Open_Equity - #pequity) as delta,
(Open_Equity - #pequity)/#pequity as delta_p,
(#pequity:= Open_Equity)
FROM (SELECT YEAR(`Date`) `Date`, SUM(Open_Equity) Open_Equity FROM tim_account_history GROUP BY YEAR(`Date`)) p
CROSS JOIN
(SELECT #pequity:= NULL) as a
ORDER BY `Date` ) as b
ORDER by `Date` ASC
I have to do a query to get the total cost of previous month and compared to current month to calculate the percentage difference.
this is the script:
create table #calc
(
InvoiceDate Date,
TotalCost decimal (12,2)
)
insert into #calc values ('2013-07-01', 9470.36)
insert into #calc values ('2013-08-01', 11393.81)
and this is the query:
select InvoiceDate,
TotalCost,
PrevTotalCost,
(CASE WHEN (PrevTotalCost = 0)
THEN 0
ELSE (((TotalCost - PrevTotalCost) / PrevTotalCost) * 100.0)
END) AS PercentageDifference
from (
select a.InvoiceDate, a.TotalCost,
isnull((select b.TotalCost
from #calc b
where InvoiceDate = (select MAX(InvoiceDate)
from #calc c
where c.InvoiceDate < a.InvoiceDate)), 0) as PrevTotalCost
from #calc a) subq
Is there a more efficient way to do it for cgetting the previous month?
Using a ranking function to put more burden on sorts than table scans seems the fastest when using no indexes. The query below processed 6575 records in under a second:
SELECT
Main.InvoiceDate,
Main.TotalCost,
PreviousTotalCost=Previous.TotalCost,
PercentageDifference=
CASE WHEN COALESCE(Previous.TotalCost,0) = 0 THEN 0
ELSE (((Main.TotalCost - Previous.TotalCost) / Previous.TotalCost) * 100.00)
END
FROM
(
SELECT
InvoiceDate,
TotalCost,
OrderInGroup=ROW_NUMBER() OVER (ORDER BY InvoiceDate DESC)
FROM
Test
)AS Main
LEFT OUTER JOIN
(
SELECT
InvoiceDate,
TotalCost,
OrderInGroup=ROW_NUMBER() OVER (ORDER BY InvoiceDate DESC)
FROM
Test
)AS Previous ON Previous.OrderInGroup=Main.OrderInGroup+1
Using nested looping as the case when getting the previous invoice cost in a select subquery proves the slowest - 6575 rows in 30 seconds.
SELECT
X.InvoiceDate,
X.TotalCost,
X.PreviousTotalCost,
PercentageDifference=
CASE WHEN COALESCE(X.PreviousTotalCost,0) = 0 THEN 0
ELSE (((X.TotalCost - X.PreviousTotalCost) / X.PreviousTotalCost) * 100.00)
END
FROM
(
SELECT
InvoiceDate,
TotalCost,
PreviousTotalCost=(SELECT TotalCost FROM Test WHERE InvoiceDate=(SELECT MAX(InvoiceDate) FROM Test WHERE InvoiceDate<Main.InvoiceDate))
FROM
Test AS Main
)AS X
Your query processed 6575 records in 20 seconds with the biggest cost coming from the nested loops for inner join
select InvoiceDate,
TotalCost,
PrevTotalCost,
(CASE WHEN (PrevTotalCost = 0)
THEN 0
ELSE (((TotalCost - PrevTotalCost) / PrevTotalCost) * 100.0)
END) AS PercentageDifference
from (
select a.InvoiceDate, a.TotalCost,
isnull((select b.TotalCost
from Test b
where InvoiceDate = (select MAX(InvoiceDate)
from #calc c
where c.InvoiceDate < a.InvoiceDate)), 0) as PrevTotalCost
from Test a) subq
Using indexes would be a big plus unless you are required to use temp tables.
Hope this helps :)
SELECT
`current`.`InvoiceDate`,
`current`.`TotalCost`,
`prev`.`TotalCost` AS `PrevTotalCost`,
(`current`.`TotalCost` - `prev`.`TotalCost`) AS `CostDifference`
FROM dates `current`
LEFT JOIN
dates `prev`
ON `prev`.`InvoiceDate` <= DATE_FORMAT(`current`.`InvoiceDate` - INTERVAL 1 MONTH, '%Y-%m-01');
Screenshot of the results I got: http://cl.ly/image/0b3z2x1f2H1n
I think this might be what you're looking for.
Edit: I wrote this query in MySQL, so it's possible you may need to alter a couple minor syntax things for your server.
Im trying to calculate the amount of money won by all the offspring of a male race horse (Sire) over a time period. Listed by the Sire with the most amount of money won.
I run the query and get the result Im after with one problem, I cant display the sires name, only their ID.
SELECT `horses`.`SireID` AS `SireID` , `horses`.`HorseName` AS `Sire Name`,
COUNT( `runs`.`HorsesID` ) AS `Runs` ,
COUNT(
CASE WHEN `runs`.`Finish` =1
THEN 1
ELSE NULL
END ) AS `Wins` ,
CONCAT( FORMAT( (
COUNT(
CASE WHEN `runs`.`Finish` =1
THEN 1
ELSE NULL
END ) / COUNT
( `runs`.`TrainersID` ) ) *100, 0 ) , '%'
) AS `Percent` ,
FORMAT( SUM( `runs`.`StakeWon` ) , 0 ) AS `Stakes`
FROM runs
INNER JOIN horses ON runs.HorsesID = horses.HorsesID
INNER JOIN races ON runs.RacesID = races.RacesID
WHERE `races`.`RaceDate` >= STR_TO_DATE( '2012,07,01', '%Y,%m,%d' )
AND `races`.`RaceDate` < STR_TO_DATE( '2012,07,01', '%Y,%m,%d' ) + INTERVAL 1
MONTH
AND `horses`.`SireID` <> `horses`.`HorsesID`
GROUP BY `horses`.`SireID`, `horses`.`HorseName`
ORDER BY SUM( `runs`.`StakeWon` ) DESC
Take a record in the horse table for example, a horse has a horsesID and they also have a sireID (their father). The sireID has an equivalent horsesID in another record in the same table as it is also a horse
Basically I need to map the horseName to the sireID.
I thought a self join would work.
`AND `horses`.`SireID` <> `horses`.`HorsesID``
but it doesn't return the correct Sire name corresponding to the SireID.
You can do a JOIN on the table itself. Here's a simpler example:
SELECT Horses.HorseID, Horses.HorseName, Horses.SireID, b.HorseName as SireName
FROM Horses
LEFT JOIN Horses b ON (Horses.SireID = b.HorseID)
You can probably figure out how to add the conditions from here.
join horses sires on sires.HorsesID = horses.SireID