SQL - Sum Aggregate function - sql

I am fairly new to SQL, so please bare that in mind.
I have have a table with data that is divided into two centers "Toronto & Montreal" for a total of 78 rows (39 per center), with multiple columns. I want to get the national total (sum) of X column for each respective center for a specific daterange (month). For example the Jan 2018 total of full time employees between Montreal + Toronto Centers combined. The logic statement for example would be to add Toronto + Montreal Jan 2018 results to yield me the national total. Although with my beginner skills I am having trouble writing a sql query that can be executed without syntax error.
select sum(fte), daterange, center
from (
select 'Toronto' as Center,
sum(fte) as total fte
from dbo.example
where daterange = '2015-11-01'
group by total fte
union
select 'Montreal' as Center,
sum(fte) as total fte
from dbo.example
where daterange = '2015-11-01'
group by total fte
)temptable
group by total fte
The above query is giving me a error "Incorrect syntax near 'fte'." fte is a column within my table.
Please advise me what I am doing wrong.
Cheers!

The query should look like this:
select Center,
sum(fte) as "[total fte]"
from dbo.example
where daterange = '2015-11-01'
and Center in ('Toronto','Montreal')
group by Center
Understanding that in the attribute Center exist these Strings.

select Center,
sum(convert(float,fte)) as total_fte
from dbo.example
where daterange = '2016-11-01'
and Center in ('Toronto','Montreal')
group by Center
Works ^ thanks everyone

Related

How to compare and find the highest average number of a value occurance in SQL for specific months?

I am fairly new to SQL and need help to find which customer has the highest average number of event occurring by month in the years (2019 - 2020) and which is the top 3 busy month every year?
Please note one customer can have multiple event_IDs.
Table Snippet:
event_ID
cust_ID
event_datetime
abc123
cus11
2019-03-13T00:00:00
abc124
cus12
2020-05-23T02:34:35
abc125
cus457
2018-12-12T22:12:23
abc126
cus11
2017-01-07T13:54:56
abc127
cus7897
2021-07-11T04:43:23
I need to find the customers having the highest average number of events in the respective month( cust with highest number of events on avg in 2019, 2020, 2021).
month
cust_ID
avg_num
1
cus11
9345.8
2
cus4563
11898.5
I have tried using CTE and window functions but couldn't figure out the logic to get to the result, any help is appreciated!
EDIT:
For clarification, my example is just a snippet of the table, the actual table has more than a few million rows, I need the customer who has the maximum number of events occurring on average over month 1,2,3,.. and avg_num will have the average value of the number of event for the cust_ID with max number of event-[ (num of event in 2019 + 2020 + 2021)/3 ]
Maybe something like this:
SELECT cust_id
, COUNT(*) AS number_of_events
, EXTRACT(YEAR FROM MAX(event_datetime)) last_year_for_cust_id
, EXTRACT(YEAR FROM MIN(event_datetime)) first_year_for_cust_id
, CAST(COUNT(*) AS DECIMAL) / (EXTRACT(YEAR FROM MAX(event_datetime)) - EXTRACT(YEAR FROM MIN(event_datetime)) )
FROM table_name
GROUP BY cust_id
ORDER BY cust_id; -- or something else
I didn't test it, no idea what brand of database you use and no DB<>fiddle was available.

How to add custom YoY field to output?

I'm attempting to determine the YoY growth by month, 2017 to 2018, for number of Company bookings per property.
I've tried casting and windowed functions but am not obtaining the correct result.
Example Table 1: Bookings
BookID Amnt BookType InDate OutDate PropertyID Name Status
-----------------------------------------------------------------
789555 $1000 Company 1/1/2018 3/1/2018 22111 Wendy Active
478141 $1250 Owner 1/1/2017 2/1/2017 35825 John Cancelled
There are only two book types (e.g., Company, Owner) and two Book Status (e.g., Active and Cancelled).
Example Table 2: Properties
Property ID State Property Start Date Property End Date
---------------------------------------------------------------------
33111 New York 2/3/2017
35825 Michigan 7/21/2016
The Property End Date is blank when the company still owns it.
Example Table 3: Months
Start of Month End of Month
-------------------------------------------
1/1/2018 1/31/2018
The previous developer created this table which includes a row for each month from 2015-2020.
I've tried many various iterations of my current code and can't even come close.
Desired Outcome
I need to find the YoY growth by month, 2017 to 2018, for number of Company bookings per property. The stakeholder has requested the output to have the below columns:
Month Name Bookings_Per_Property_2017 Bookings_Per_Property_2018 YoY
-----------------------------------------------------------------------
The number of Company bookings per property in a month should be calculated by counting the total number of active Company bookings made in a month divided by the total number of properties active in the month.
Here is a solution that should be close to what you need. It works by:
LEFT JOINing the three tables; the important part is to properly check the overlaps in date ranges between months(StartOfMonth, EndOfMonth), bookings(InDate, OutDate) and properties(PropertyStartDate, PropertyEndDate): you can have a look at this reference post for general discussion on how to proceed efficiently
aggregating by month, and using conditional COUNT(DISTINCT ...) to count the number of properties and bookings in each month and year. The logic implicitly relies on the fact that this aggregate function ignores NULL values. Since we are using LEFT JOINs, we also need to handle the possibility that a denominator could have a 0 value.
Notes:
you did not provide expected results so this cannot be tested
also, you did not explain how to compute the YoY column, so I left it alone; I assume that you can easily compute it from the other columns
Query:
SELECT
MONTH(m.StartOfMonth) AS [Month],
COUNT(DISTINCT CASE WHEN YEAR(StartOfMonth) = 2017 THEN b.BookID END)
/ NULLIF(COUNT(DISTINCT CASE WHEN YEAR(StartOfMonth) = 2017 THEN p.PropertyID END), 0)
AS Bookings_Per_Property_2017,
COUNT(DISTINCT CASE WHEN YEAR(StartOfMonth) = 2018 THEN b.BookID END)
/ NULLIF(COUNT(DISTINCT CASE WHEN YEAR(StartOfMonth) = 2018 THEN p.PropertyID END), 0)
AS Bookings_Per_Property_2018
FROM months m
LEFT JOIN bookings b
ON m.StartOfMonth <= b.OutDate
AND m.EndOfMonth >= b.InDate
AND b.status = 'Active'
AND b.BookType = 'Company'
LEFT JOIN properties p
ON m.StartOfMonth <= COLAESCE(p.PropertyEndDate, m.StartOfMonth)
AND m.EndOfMonth >= p.PropertyStartDate
GROUP BY MONTH(m.StartOfMonth)

sql group by sum of all sums

I have a query (formatted for Oracle):
select sum(inv.quantity * inv.price), spn.salesperson_name
from invoice inv
inner join salesperson spn on spn.spn_id = inv.spn_id
where inc.invoice_date between to_date('05/01/2017', 'MM/dd/YYYY') and to_date('05/31/2017', 'MM/dd/YYYY')
group by spn.salesperson_name
To add up invoices for the month of May. The result is similar to:
$446,088.62 Bob
$443,439.29 Sally
$275,097.00 Tom
$95,170.00 George
$53,150.00 Jill
But, I need to divide each sum to the sum of the sums ($1,312,944.91), so that the result is:
$446,088.62 34% Bob
$443,439.29 34% Sally
$275,097.00 21% Tom
$95,170.00 7% George
$53,150.00 4% Jill
(The sum of the percentage column should be 100%)
Is there a way to accomplish this in the query?
When functions exist that do exactly what you need, it is best to use those functions. In this case, the SQL Standard analytic function RATIO_TO_REPORT (which is implemented at least in Oracle and SQL Server) does exactly what you need. https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions124.htm
Specifically, the select clause could be:
select sum(inv.quantity * inv.price) AS TOTAL_REVENUE -- use column aliases!
, ratio_to_report(sum(inv.quantity * inv.price)) over () AS RATIO,
, spn.salesperson_name
from ....... (rest of your query goes here)
Note that this solution, like the Accepted Answer, will show the ratio as a decimal, not as a percentage (and not rounded). If you need to attach a percentage sign, you will need to convert to string... and if so, the following trick (it is a trick!) will give you what you need:
to_char( ratio_to_report(.....), 'fm99L', 'nls_currency = %' ) AS RATIO, .....
The L element in to_char is for currency symbol; you define the currency symbol to be the percent sign.
Just use analytic functions:
select spn.salesperson_name, sum(inv.quantity * inv.price),
sum(inv.quantity * inv.price) / sum(sum(inv.quantity * inv.price)) over () as ratio
from invoice inv inner join
salesperson spn
on spn.spn_id = inv.spn_id
where inc.invoice_date between date '2017-05-01' and date '2017-05-31'
group by spn.salesperson_name;

SSRS Report Multi Parameters (start date,end date, MeterId, Displayby)

In my SSRS report there are 4 parameters StartDate, EndDate, MeterId, & DisplayBy
Start Date: datetime datatype
EndDate : datetime datatype
MeterId : is a drop down list and this will populate based on SQL query
DisplayBy: is a drop down list and this has the following values (Hour,day,Month & year)
The Database that stores hourly values for Meters, the following are the DB table columns: (MeterId,ReadingDate,Hours,Quantity,Price)
When I select the startdate, end date and the meter Id and display i want to show report based on the startdate & enddate and then by display values.
If the display is hour, the we got display all the 24 hour values for the MeterId,Quantity, Price for the date range.
If the display is day, we got display total quantity and total price for the MeterId for that date range.
If the display is Month, we got display total quantity and total price for the MeterId for that date range.
If the display is Year, we got display total quantity and total price for the MeterId for that date range. Say for example If i select start date as 1-1-2016 and end date as 12-31-2016. My result should show 12 rows for each month with their total Quantity, Total price for that particular MeterID.
my DB table stores all the hourly values i know how to show the values on screen if the user selects the display dropdown as hour. But, dont know how to show the result for day/month/year or how to group it. Do I need to use "case" statement and if so what should i need to give on display parameters.
Please suggest your idea...
Row Grouping:
SELECT I.CustomerName, I.ReadingDate, I.IntegratedHour, I.IntegratedUsage, I.IntegratedGeneration, DATEPART(dd, I.ReadingDate) AS [Reading Day], DATEPART(mm,
I.ReadingDate) AS [Reading Month], DATEPART(yyyy, I.ReadingDate) AS [Reading Year]
FROM IntegratedHour_MV90 AS I INNER JOIN
CustRptMeterExtract AS CT ON CT.CustomerName = I.CustomerName
WHERE (I.ReadingDate >= #StartDate) AND (I.ReadingDate <= #EndDate) AND (I.CustomerName IN (#FacilityName))
Expected Result:
SSRS Current Output: Doesnot match
Depending on your layout you could set row grouping to an expression something like this
=SWITCH
(
Parameters!ReportBy.Value=1, Fields!Hour.Value,
Parameters!ReportBy.Value=2, Fields!Day.Value,
Parameters!ReportBy.Value=3, Fields!Month.Value,
Parameters!ReportBy.Value=4, Fields!Year.Value,
True, 0)
This assumes you have already have the hours/days/months/years in your dataset, if not then you would have to replace the field references with expressions to return the relevant month etc.
Based on what I can see above you'll need to add a grouping level for Customer before the group expression. Also, you Quantity expression should be a sum something like this
=SUM(FIelds!IntegratedGeneration.Value)
You may still have a problem though. I'm assuming Price is a unit price, so it does not make sense to sum that too. To get round this, you should calculate the LineValue (Qty * Price) in your dataset then change the price expression to be something like
=(SUM(FIelds!LineValue.Value)/SUM(Fields!IntegratedGeneratio‌​n.Value))
and this will give you the average price.
However, this may be slow and personally I would do the work in your dataset. Again assuming you have the months, years in your table then you could do something like this.
--DECLARE #ReportBy int = 1 -- uncomment for testing
select
MeterID, Price
, CASE #ReportBy
WHEN 1 THEN [Month]
WHEN 2 THEN [Year]
ELSE NULL
END AS GroupByColumn
INTO #t
from dbo.MyDataTable
SELECT
GroupByColumn
, SUM(Price) as Price
FROM #t
Group BY GroupByColumn
Order by GroupByColumn
This assumes your report parameter is called ReportBy, if not just swap the name out.

SQL Query for Normalized Sales

I need to write an SQL query that solves this problem:
"Get the top 10 departments overall ranked by total sales normalized by the size
of the store where the sales were recorded."
Normalizing the sales means to divide the number of sales by the size of the store per sale. So in other words I need a query that returns the top 10 departments with the greatest sum of WeeklySales/size for every sale by that department. Eg: (week1sales/size1) + (week2sales/size2) + ...
Here is the data in the database where bolded attributes are keys.
-Holidays (WeekDate, IsHoliday)
-Stores (Store, Type, Size)
-TemporalData (Store, WeekDate, Temperature, FuelPrice, CPI, UnemploymentRate)
-Sales (Store, Dept, WeekDate, WeeklySales)
(WeekDate is the date for the first day of the week. WeeklySales is an integer for the number of sales that week.)
The main issue I'm having with writing this query is that I'm having troubles figuring out how to find the sum of all sales by each department. How would keep track of the total normalized sales for each department in a query and then add them all together? Also this query will have to run in SQLite3 if that makes any difference.
Edit: Explained normalized in this context.
Your question isnt clear but for one single week you need something like this
SELECT *
FROM (
SELECT Sa.Store, Sa.Dept, SUM(WeeklySales) / St.Size as normalized
FROM Sales Sa
JOIN Stores St
ON Sa.Store = St.Store
WHERE Sa.WeekDate = #date#
GROUP BY Sa.Store, Sa.Dept
) AS T
ORDER BY normalized DESC
LIMIT 10
If you want the comulative for all weeks
SELECT *
FROM (
SELECT Sa.Store, Sa.Dept, SUM(WeeklySales) / St.Size as normalized
FROM Sales Sa
JOIN Stores St
ON Sa.Store = St.Store
GROUP BY Sa.Store, Sa.Dept
) AS T
ORDER BY normalized DESC
LIMIT 10