SQL Calculate Percentage in Group By - sql

I have an SQL query that is used as the basis for a report. The report shows the amount of fuel used grouped by Year, Month and Fuel Type. I would like to calculate the percentage of the total for each fuel type, but I'm not having much luck. In order to calculate the percentage of the whole, I need to be able to get the total amount of fuel used regardless of the group it is in and I can't seem to figure out how to do this. Here is my query:
SELECT Year([DT1].[TransactionDate]) AS [Year], Month([DT1].[TransactionDate]) AS [Month], DT1.FuelType, Format(Sum(DT1.Used),"#.0") AS [Total Used],
FROM (SELECT TransactionDate, FuelType, Round([MeterAfter]-[MeterBefore],2) AS Used FROM FuelLog) AS DT1
WHERE (((DT1.TransactionDate) Between [Start Date] And [End Date]))
GROUP BY Year([DT1].[TransactionDate]), Month([DT1].[TransactionDate]), DT1.FuelType
ORDER BY Year([DT1].[TransactionDate]), Month(DT1.TransactionDate), DT1.FuelType;
I tried adding the following as a subquery but I get an error saying the subquery returns more than one result.
(SELECT Sum(Round([MeterAfter]-[MeterBefore],2)) AS Test
FROM Fuellog
WHERE Year([Year]) and Month([Month])
GROUP BY Year([TransactionDate]), Month([TransactionDate]))
Once I get the total of all fuel I will need to divide the amount of fuel used by the total amount of both fuel types. Should I be approaching this a different way?

Try this
SELECT A.[Year]
,A.[Month]
,A.[FuelType]
,A.[Total Used]
,(A.[Total Used] / B.[Total By Year Month]) * 100 AS Percentage
FROM
(
SELECT Year([DT1].[TransactionDate]) AS [Year]
, Month([DT1].[TransactionDate]) AS [Month]
, DT1.FuelType
, Format(Sum(DT1.Used),"#.0") AS [Total Used]
FROM (
SELECT TransactionDate
, FuelType
, Round([MeterAfter]-[MeterBefore],2) AS Used
FROM FuelLog
) AS DT1
WHERE (((DT1.TransactionDate) Between [Start Date] And [End Date]))
GROUP BY Year([DT1].[TransactionDate]), Month([DT1].[TransactionDate]), DT1.FuelType
ORDER BY Year([DT1].[TransactionDate]), Month(DT1.TransactionDate), DT1.FuelType
) A
INNER JOIN
(
SELECT Sum(Round([MeterAfter]-[MeterBefore],2)) AS [Total By Year Month]
, Year([TransactionDate]) AS [Year]
, Month([TransactionDate])) AS [Month]
FROM Fuellog
GROUP
BY Year([TransactionDate])
, Month([TransactionDate]))
) B
ON A.[Year] = B.[Year]
AND A.[Month] = B.[Month]

You need to join to the totals -- something like this (untested might have typos)
SELECT
Year([DT1].[TransactionDate]) AS [Year],
Month([DT1].[TransactionDate]) AS [Month],
DT1.FuelType,
Format(Sum(DT1.Used),"#.0") AS [Total Used],
(Sum(DT1.Used) / FT.Total) * 100 AS Percent
FROM (
SELECT
TransactionDate,
FuelType,
Round([MeterAfter]-[MeterBefore],2) AS Used
FROM FuelLog
) AS DT1
JOIN (
SELECT
Sum(Round([MeterAfter]-[MeterBefore],2)) AS Total
FuelType
FROM Fuellog
WHERE TransactionDate Between [Start Date] And [End Date]
GROUP BY FuelType
) FT ON DT1.FuelType = FT.FeulType
WHERE DT1.TransactionDate Between [Start Date] And [End Date]
GROUP BY Year([DT1].[TransactionDate]), Month([DT1].[TransactionDate]), DT1.FuelType, FT.Total
ORDER BY Year([DT1].[TransactionDate]), Month(DT1.TransactionDate), DT1.FuelType, FT.Total;

Related

How to select max date over the year function

I am trying to select the max date over the year, but it is not working. Any ideas on what to do?
SELECT a.tkinit [TK ID],
YEAR(a.tkeffdate) [Rate Year],
max(a.tkeffdate) [Max Date],
tkrt03 [Standard Rate]
FROM stageElite.dbo.timerate a
join stageElite.dbo.timekeep b ON b.tkinit = a.tkinit
WHERE a.tkinit = '02672'
and tkeffdate BETWEEN '2014-01-01' and '12-31-2014'
GROUP BY a.tkinit,
tkrt03,
a.tkeffdate
Perhaps you only want it by year and not rolled up by calendar date. For SQL server you can try this.
SELECT
…
MaxDate = MAX(a.tkeffdate) OVER (PARTITION BY a.tkinit, YEAR(a.tkeffdate)))
…
Or you could modify the query above to group by the year instead of date-->
GROUP BY a.tkinit,
tkrt03,
YEAR(a.tkeffdate)
You seem to want only one row and all the columns. Use ORDER BY and TOP:
SELECT TOP (1) tr.tkinit as [TK ID],
YEAR(tr.tkeffdate) as [Rate Year],
a.tkeffdate as [Max Date],
tkrt03 as [Standard Rate]
FROM stageElite.dbo.timerate tr JOIN
stageElite.dbo.timekeep tk
ON tk.tkinit = tr.tkinit
WHERE tr.tkinit = '02672' AND
tr.tkeffdate >= '2014-01-01' AND
tr.tkeffdate < '2015-01-01'
ORDER tr.tkeffdate DESC;
Note that I also fixed your date comparisons and table aliases.

How can I join 2 table together?

I'm trying to create a join table with 2 existing tables. something like below:
This is the first table queries and looks like this
https://ibb.co/sg2MXKf
SELECT
DATEPART( week, dbo.Income.IncomeDate ) AS [Week Income],
DATEPART( YEAR, dbo.Income.IncomeDate ) AS [Year],
SUM ( dbo.Income.CardAmount ) AS [Total Card],
SUM ( dbo.Income.CashAmount ) AS [Total Cash],
SUM ( dbo.Income.TipsAmount ) AS [Total Tip],
SUM ( dbo.Income.SalaryAmount ) AS [Total Salary],
SUM ( dbo.Income.Adjustment ) AS [Total Adjustment]
FROM
dbo.Income
GROUP BY
DATEPART( week, dbo.Income.IncomeDate ),
DATEPART( YEAR, dbo.Income.IncomeDate )
ORDER BY
DATEPART(YEAR, dbo.Income.IncomeDate )
And this is the second table queries and looks like this
https://ibb.co/z8sRwpT
SELECT
DATEPART( wk, dbo.Transactions.PaymentMadeOn ) AS [Week],
COUNT (DATEPART( wk, dbo.Transactions.PaymentMadeOn )) AS [Expenses Count],
DATEPART( YEAR, dbo.Transactions.PaymentMadeOn ) AS [Year],
SUM ( dbo.Transactions.PaymentAmount ) AS [Total]
FROM
dbo.Transactions
GROUP BY
DATEPART( wk, dbo.Transactions.PaymentMadeOn ),
DATEPART( YEAR, dbo.Transactions.PaymentMadeOn )
ORDER BY
DATEPART( YEAR, dbo.Transactions.PaymentMadeOn )
What I expected is something this. Both table 1 and 2 combined, and the total expenses added.
https://ibb.co/0DbZLYV
As commented by SO folks, we cannot access the images that describe your expected results. However we understand that you are looking to JOIN the results of both queries that you are showing.
Here is how to do it : you turn each query into a subquery, and you JOIN them together on their common key fields ; in your use case, this must be Year and Week. The ORDER BY clause needs to be moved to the outer query. In the SELECT, WHERE and ORDER BY clauses, you can freely access all the fields from the subqueries, using the aliases that you defined (here A and B).
Sample code (you will have to adapt the SELECT, I cannot tell what you want it to look like) :
SELECT
A.[Week Income],
A.[Year],
A.[Total] - B.[Total Salary] AS [Balance]
...
FROM (
SELECT
DATEPART( week, dbo.Income.IncomeDate ) AS [Week Income],
DATEPART( YEAR, dbo.Income.IncomeDate ) AS [Year],
SUM ( dbo.Income.CardAmount ) AS [Total Card],
SUM ( dbo.Income.CashAmount ) AS [Total Cash],
SUM ( dbo.Income.TipsAmount ) AS [Total Tip],
SUM ( dbo.Income.SalaryAmount ) AS [Total Salary],
SUM ( dbo.Income.Adjustment ) AS [Total Adjustment]
FROM
dbo.Income
GROUP BY
DATEPART( week, dbo.Income.IncomeDate ),
DATEPART( YEAR, dbo.Income.IncomeDate )
) AS A
LEFT JOIN (
SELECT
DATEPART( wk, dbo.Transactions.PaymentMadeOn ) AS [Week],
COUNT (DATEPART( wk, dbo.Transactions.PaymentMadeOn )) AS [Expenses Count],
DATEPART( YEAR, dbo.Transactions.PaymentMadeOn ) AS [Year],
SUM ( dbo.Transactions.PaymentAmount ) AS [Total]
FROM
dbo.Transactions
GROUP BY
DATEPART( wk, dbo.Transactions.PaymentMadeOn ),
DATEPART( YEAR, dbo.Transactions.PaymentMadeOn )
) AS B ON A.[Week Income] = B.[Week] AND A.[Year] = B.[Year]
ORDER BY
A.[Year],
A.[Week Income]

SQL accumulate of query with sum

I have this query in SQL:
select cast(faturas.datatotal as date) as Dia, faturas.sumF, credito.sumC, isnull(sumF,0)-isnull(sumC,0) as Total
from
(SELECT SUM([Line Amount]) as sumF, [Posting Date] as datatotal
FROM [CMW$Sales Invoice Line]
where [CMW$Sales Invoice Line].[Posting Date] >= '2017-01-01'
group by [CMW$Sales Invoice Line].[Posting Date]) faturas
full outer join
(SELECT SUM(Amount) as sumC, [Posting Date]
FROM [CMW$Sales Cr_Memo Line]
where [CMW$Sales Cr_Memo Line].[Posting Date] >= '2017-01-01'
group by [CMW$Sales Cr_Memo Line].[Posting Date]) credito
on faturas.datatotal=credito.[Posting Date]
I need to calculate the cumulative "Total" in this same query. How can I get this?
I solved my problem with this:
sum(isnull(sumF,0)-isnull(sumC,0)) over(order by faturas.datatotal rows unbounded preceding) as Acumulado
Thanks

How to do join for my sitaution

i have two select statement from two different table and the common join field a datefield
one date field name is JobFinishedDate and it is from MyJobs table and another date field name is createddate and it is from DailyFinishJobsHistory table
here is my two independent sql
sql 1
SELECT CONVERT(varchar,createddate,101) as [Date],
SUM([No of Jobs]) as [No of Jobs],
SUM([Turnaround Time]) as [Turnaround Time],
SUM([One Day Per]) as [One Day Per],
ROUND((SUM([No of Jobs]) * SUM([Turnaround Time])),2) as [TOTAL hours]
from DailyFinishJobsHistory d
WHERE CONVERT(varchar,createddate,112)>='20131015' AND CONVERT(varchar,createddate,112)<='20131021'
group by createddate
sql 2
Select
convert(varchar,JobFinishedDate,112) as JobFinishedDate
, Count(*) [Number of techs]
From
(
select
convert(varchar,JobFinishedDate,112) JobFinishedDate,Specialist
from MyJobs
where convert(varchar,JobFinishedDate,112)>='20131015'
and convert(varchar,JobFinishedDate,112) <='20131021'
and JobState='FINISHED'
group by convert(varchar,JobFinishedDate,112) , Specialist
) t1
Group By
JobFinishedDate
now i have to join. i tried like this way but right syntax is not coming to my mind to join this way.
SELECT CONVERT(varchar,createddate,101) as [Date],
SUM([No of Jobs]) as [No of Jobs],
SUM([Turnaround Time]) as [Turnaround Time],
SUM([One Day Per]) as [One Day Per],
ROUND((SUM([No of Jobs]) * SUM([Turnaround Time])),2) as [TOTAL hours],
(
Select
convert(varchar,JobFinishedDate,112) as JobFinishedDate
, Count(*) [Number of techs]
From
(
select
convert(varchar,JobFinishedDate,112) JobFinishedDate,Specialist
from bbajobs
where convert(varchar,JobFinishedDate,112)>='20131015'
and convert(varchar,JobFinishedDate,112) <='20131021'
and JobState='FINISHED'
group by convert(varchar,JobFinishedDate,112) , Specialist
) t1
Group By
JobFinishedDate
) a
from DailyFinishJobsHistory d
WHERE CONVERT(varchar,createddate,112)>='20131015' AND CONVERT(varchar,createddate,112)<='20131021'
group by createddate
so please help me bit to build the join. thanks
EDIT
i tried this script also but [Number of techs] is getting NULL
SELECT CONVERT(varchar,createddate,101) as [Date],
SUM([No of Jobs]) as [No of Jobs],
SUM([Turnaround Time]) as [Turnaround Time],
SUM([One Day Per]) as [One Day Per],
ROUND((SUM([No of Jobs]) * SUM([Turnaround Time])),2) as [TOTAL hours],
(
SELECT
--CONVERT(varchar,JobFinishedDate,112) as JobFinishedDate,
COUNT(*) [Number of techs]
From
(
SELECT CONVERT(varchar,JobFinishedDate,112) JobFinishedDate,
Specialist
FROM bbajobs
WHERE d.createddate=JobFinishedDate AND
JobState = 'FINISHED'
GROUP BY CONVERT(varchar,JobFinishedDate,112), Specialist
) t1
GROUP BY JobFinishedDate
) [Number of techs]
FROM DailyFinishJobsHistory d
WHERE CONVERT(varchar,createddate,112) >= '20131015' AND CONVERT(varchar,createddate,112) <= '20131021'
GROUP BY createddate
Something like this should do the trick:
SELECT *
FROM
(
SELECT CONVERT(varchar,createddate,112) as [Date],
SUM([No of Jobs]) as [No of Jobs],
SUM([Turnaround Time]) as [Turnaround Time],
SUM([One Day Per]) as [One Day Per],
ROUND((SUM([No of Jobs]) * SUM([Turnaround Time])),2) as [TOTAL hours]
FROM DailyFinishJobsHistory
WHERE CONVERT(varchar,createddate,112) >= '20131015'
AND CONVERT(varchar,createddate,112) <= '20131021'
GROUP BY createddate
) A
JOIN
(
SELECT
JobFinishedDate,
COUNT(*) [Number of techs]
From
(
SELECT CONVERT(varchar,JobFinishedDate,112) JobFinishedDate
FROM MyJobs
WHERE CONVERT(varchar,JobFinishedDate,112) >= '20131015'
AND CONVERT(varchar,JobFinishedDate,112) <='20131021'
AND JobState = 'FINISHED'
) t1
GROUP BY JobFinishedDate
) B
ON B.JobFinishedDate = A.[Date]
See joining two select statements for a simpler example.

SQL statement using WHERE from a GROUP or RANK

I have a sales snapshot with about 35,000 rows. Let's call the columns:
Sales Rep | Account ID | Total Contract Value | Date
I need to group everything by Sales Rep and then from there, select that Sales Rep's top 35 accounts based off of Total Contract Value where the Total Contract Value is >= $10,000 for the Month (Date) of January 2013.
So for example, say John Doe had 294 accounts in this table from January, I only want to see his top 35 accounts >= $10,000 , same for Jane Doe, etc. etc. It's very important that the query be as efficient in it's resource usage as possible.
Thoughts?
The answer is already in your title, partition by SalesRep and AccountID and Rank by Total Contact Value.
A SQL Server solution will look like:
DECLARE #minimumValue decimal(20,2) = 10000
DECLARE #numberOfAccounts int = 35
DECLARE #from datetime = '1/1/2013'
DECLARE #till datetime = DATEADD(MONTH, 1, #from)
SELECT
[sub].[Sales Rep],
[sub].[Rank],
[sub].[Account ID],
[sub].[Total Contract Value]
FROM
(
SELECT
[Sales Rep],
[Account ID],
[Total Contract Value],
DENSE_RANK() OVER (PARTITION BY [Sales Rep] ORDER BY [Total Contract Value] DESC) AS [Rank]
FROM [Sales]
WHERE
[Total Contract Value] >= #minimumValue
AND [Date] > #from
AND [Date] < #till
) AS [sub]
WHERE [sub].[Rank] <= #numberOfAccounts
ORDER BY
[Sales Rep] ASC,
[Rank] ASC
Here is a (simple) Sql Fiddle.
For this, you want to use a function called row_number():
select ss.*
from (select ss.*, row_number() over (partition by salesrep order by ContractValue desc) as seqnum
from snapshot ss
where TotalContractValue >= 10000 and date between '2013-01-01' and '2013-01-31'
) ss
where seqnum <= 35
You don't specify the database you are using. In databases that don't have row_number(), there are alternatives that are less efficient.