T-SQL query to select last 3 months of data, last years month, averages of this month and average of all months - sql

I have a table with columns Category, Date, Monthly_Revenue.
I need a query that will select Todays_Month, Last_Month, 2 months prior, Last_years_Month, average of today's month, average of all months.
This query is needed grouped by category.
Example :
Category | Sept, 2012 | Aug, 2012| Jul, 2012 | Sept, 2011 | Average of Sept | Avg all Mo
Being fairly new to SQL I still haven't got it yet. I figured see if somebody out there could take a crack at it. Thanks.
Sample data
'Burger' '9/1/2012' '500'
'Fries' '10/1/2012 '300'
'Burger' '6/1/2011' '250'

you need something along these lines .Not the optimum solution but will give you a start
.This is a static solution but it looks like you may want a dynamic solution
*not tested
SELECT
Category
,[Sep 2012]=SUM(CASE WHEN YEAR(TranDate)= YEAR(GETDATE()) AND MONTH(TranDate)= MONTH(GETDATE()) THEN Amount ELSE NULL END)
,[Aug 2012]=SUM(CASE WHEN YEAR(TranDate)= YEAR(DATEADD(month,-1,GETDATE())) AND MONTH(TranDate)= MONTH(DATEADD(month,-1,GETDATE())) THEN Amount ELSE NULL END)
,[Jul 2012]=SUM(CASE WHEN YEAR(TranDate)= YEAR(DATEADD(month,-2,GETDATE())) AND MONTH(TranDate)= MONTH(DATEADD(month,-2,GETDATE())) THEN Amount ELSE NULL END)
,[AVG Sep 2012]=AVG(CASE WHEN YEAR(TranDate)= YEAR(GETDATE()) AND MONTH(TranDate)= MONTH(GETDATE()) THEN Amount ELSE NULL END)
,[AVG 12 months]=AVG(CASE WHEN TranDatee > CAST(DATEADD(year,-1,GETDATE()) AS DATE) THEN Amount ELSE NULL END)/12
FROM Table1
GROUP BY Category,Amount

Related

Total hours worked for employees in 2018 and 2019

I am new to stackoverflow and new to sql. I have employee timesheets which has a unique id and hours works by employees. I was wondering if theres a way to calculate the sum of the hours for each employee in 2018.
I dont know if this query is too basic but what i have so far is this:
select distinct PersonId, SUM(reghours) as '2018'
from TimeSheetsView
where left(yearweek,4)='2018'
group by PersonId, reghours
If you wanted to sum up both 2018 and 2019 in their own columns you could use a case statement to target those specific records in 2018 and 2019 placing them in their own column. You don't need a distinct with the group by either and like Mitch said you don't need that reghours it will split aggregation.
In the THEN piece it will sum up that field and ELSE is 0 so it won't obviously sum up any other rows that don't meet that condition.
Select PersonId
, SUM(CASE WHEN left(yearweek,4)='2018' THEN reghours ELSE 0 END) as '2018_RegHours'
, SUM(CASE WHEN left(yearweek,4)='2019' THEN reghours ELSE 0 END) as '2019_RegHours'
from TimeSheetsView
where left(yearweek,4) IN ('2018', '2019')
group by PersonId

Combine different results of "group by" queries in the same table

I need to make some comparation between 2 years: sales by product, sales by category, etc.
How can I have this in one table having 3 columns:
first column = product, category, etc
second column = sales in 2021
third column = sales in 2022
Sample of queries that must be combined in one single table as the one below
select product_code, sum(amount)
from product
where year = '2021'
group by product_code
select product_code, sum(amount)
from product
where year = '2022'
group by product_code
select category_code, sum(amount)
from category
where year = '2021'
group by category_code
select category_code, sum(amount)
from category
where year = '2022'
group by category_code
Please, see the final table
[1]: https://i.stack.imgur.com/smF7h.png
NOTE!
If for instance in 2021 there was no "product D", it will be 0 for "Sales_2021" or the "product A" is no longer present in 2022, it will be 0 for "Sales_2022".
Thank you
You need two things here:
Conditional aggregation (a CASE expression inside the aggregation function) in order to get 2021 and 2022 in one go.
A union of two intermediate result sets (product figures UNION ALL category figures).
And as any table - and a query result is again a table - is unordered, we need an ORDER BY at last to get products first and categories second and also the products ordered alphabetically and the categories, too.
The complete query:
select category_or_product, sales_2021, sales_2022
from
(
select
product_code as category_or_product,
sum(case when year = 2021 then amount else 0 end) as sales_2021,
sum(case when year = 2021 then amount else 0 end) as sales_2022,
1 as product_first
from product
group by product_code
union all
select
category_code as category_or_product,
sum(case when year = 2021 then amount else 0 end) as sales_2021,
sum(case when year = 2021 then amount else 0 end) as sales_2022,
2 as product_first
from category
group by category_code
) unioned
order by product_first, category_or_product;

SQL help to display no. of openings for all branches for each month of a year

Hi I need to generate a SSRS report to show how many centers got opened for each month in a calendar year under each branch. report will have 13 columns, first column being all the branches in each row and remaining 12 columns will have months of an year as header. I'm trying to get a result of each branch having no. of openings per month, so I can feed SSRS to display in tabular format. If a branch doesnt have any openings for any month, I need to display 0.
Branch table
=============
Branchid
Branchname
CenterOpen table
================
CenterOpenID
BranchID
CenterOpenDate
below is the SQL I had written
WITH months(MonthNumber) AS (
SELECT
1
UNION ALL
SELECT
MonthNumber + 1
FROM
months
WHERE
MonthNumber < 12
),
cteBranch(BranchID, BranchName, TargetOpenDate, Month, Count) as (
SELECT
B.BranchID,
B.BranchName,
CS.TargetOpenDate,
MONTH(CS.TargetOpenDate) as Month,
count(Month(CS.TargetOpenDate)) as Count
FROM
Branch B
left join goal.CenterOpenSchedule CS ON CS.BranchID = B.BranchID
GROUP BY
B.BranchID,
B.BranchName,
CS.TargetOpenDate,
MONTH(CS.TargetOpenDate)
)
select
*
from
months
cross join cteBranch
order by
BranchID asc,
MonthNumber asc
If I use cross join, months are repeating for each branch, how to resolve this? your help is highly appreciated.
Not sure which database you are on.
There are different ways to extract month/year from date.
Based on your example SQL, I'm going to use MONTH()
select branchName,
count(case when month(centerOpenDate) = 1 then branchId end) Jan_Count
...
...
count(case when month(centerOpenDate) = 12 then branchId end) Dec_Count
from Branch b
join CenterOpen co
on (b.BranchId = co.BranchId)
where year(centerOpenDate) = <your year filter>
group by branchName
This will take care of your below requirements:
" first column being all the branches in each row and remaining 12 columns will have months of an year as header."
and also -
"If a branch doesnt have any openings for any month, I need to display 0."
Your question is not explicit, but you seem to want a single year -- so you need to filter on the year.
The rest is basically conditional aggregation:
select b.branchName,
sum(case when month(co.centerOpenDate) = 1 then 1 else 0 end) as jan,
sum(case when month(co.centerOpenDate) = 2 then 1 else 0 end) as feb,
. . .
sum(case when month(co.centerOpenDate) = 12 then 1 else 0 end) as dec
from Branch b join
CenterOpen co
on b.BranchId = co.BranchId
where year(co.centerOpenDate) = #year
group by b.branchName

Dynamically SELECT a column based on value of row at first of month

The following query:
SELECT Confirmed, Interim, Declared, Date
FROM Interest_Hist
WHERE Date BETWEEN '2019-08-01' AND '2019-12-04'
ORDER BY Date ASC
Returns the following sample data:
Confirmed Interim Declared Date
Y 0.314 0.0788 2019-08-01
0.317 0 2019-08-02
...
0.245 0 2019-08-31
0.222 0.219 2019-09-01
0.198 0 2019-09-02
...
Y 0.50 0.454 2019-12-01
0.51 0 2019-12-02
0.52 0 2019-12-03
0.53 0 2019-12-04
Where on the first of the month, Confirmed = Y, I need to return the Declared column for that month.
Note, Confirmed = Y will only exist on the first of the month. That column is blank in all other cases
Otherwise, I need to return each Interim column for the month.
Thus far, I have been able to return the SUM of either column, but not the individual values.
SELECT
CASE WHEN SUM(CASE WHEN IRc_Confirmed = 'Y' THEN 1 ELSE 0 END) = 0
THEN Interim
ELSE Declared
END AS Rate
FROM Fund_Interest
WHERE Date BETWEEN '2019-08-01' AND '2019-12-04'
GROUP BY
DATEADD(month, DATEDIFF(month, 0, Date), 0), Interim, Declared
ORDER BY
DATEADD(month, DATEDIFF(month, 0, Date), 0)
The expected output given the data at the top is as follows
0.0788
0
...
0
0.222
0.198
...
0.454
0
0
0
Find all the year months where the first day is Y:
SELECT year([date]) as yr, month([date]) as mo
FROM fund_interest
WHERE DAY([date]) = 1 and confirmed = 'Y'
This gives you a list of years and months where there is a Y on the first eg Aug 2019
Now make it a cte and left join it back to your data on year and month, and where the join succeeds return declared else interim:
WITH x AS(
SELECT year([date]) as yr, month([date]) as mo
FROM fund_interest
WHERE DAY([date]) = 1 and confirmed = 'Y'
)
SELECT
CASE WHEN x.yr IS NOT NULL THEN f.declared ELSE f.interim END AS something
FROM
fund_interest f
LEFT OUTER JOIN x ON x.yr = year(f.[date]) AND x.mo = month(f.[date])
All of the rows of different days from Aug 2019 and Dec 2019 will succeed in the join. They will have a NOT NULL yr value and hence the declared will show. For all Sep 2019 rows there is no match in the join (Sep 2019 is not returned by the query in the CTE), yr is null, interim shows instead
For a better idea of what is going on do a SELECT *
If you want to use just a single column the EOMONTH function could be used to return a consistent date every month. Replace MONTH with EOMONTH. Remove calls to YEAR from the query
Do not use reserved words like DATE as column names, by the way
You can use a CTE to group by month and year and then join to your original table (Interest_Hist) on the month and year parts of your date field. You can then select the Interim or Declared value using a simple case statement
;WITH CTE AS
(
SELECT DATEPART(month, DateFld) Mnth, DATEPART(year, DateFld) Yr,
MAX(Confirmed) ConfirmedVal
FROM Interest_Hist
GROUP BY DATEPART(month, DateFld), DATEPART(year, DateFld)
)
SELECT
CASE WHEN c.ConfirmedVal= 'Y' THEN interest.Declared ELSE interest.Interim END
FROM Interest_Hist interest
INNER JOIN CTE c ON
DATEPART(month, interest.DateFld) = c.Mnth AND
DATEPART(year, interest.DateFld) = c.Yr
You can see the query in action here
This took me way longer than it probably should have.
SELECT IIF( MAX(Confirmed) OVER(PARTITION BY CONVERT(VARCHAR(6), Date, 112)) = 'Y', Declared, Interim) Interest_Rate
FROM Interest_Hist
WHERE DateBETWEEN '01-AUG-2019' AND '04-DEC-2019'
ORDER BY Date

How do I add two count columns to a result set when one count is not restricted by the arguments in the WHERE clause?

I was trying to write an SQL query that would return a set of data with a couple of count rows tacked on. In this case I want to return a list of FRUIT that are ROTTEN in the year 2018. I'd then like to tack on a column that counts the number of ROTTEN FRUIT found in the year 2018. Then another column that counts the total number of FRUIT rows, by type, for the year 2018.
So given the following table
FRUIT DEFECT YEAR ...
------------------------------
APPLE ROTTEN 2017
APPLE ROTTEN 2018
APPLE ROTTEN 2018
APPLE BUGS 2018
APPLE ROTTEN 2018
APPLE BUGS 2018
APPLE BITTEN 2018
APPLE BITTEN 2017
ORANGE BITTEN 2018
ORANGE ROTTEN 2018
I'd like to get the following result,
FRUIT DEFECT YEAR DEFECTCOUNT FRUITCOUNT
----------------------------------------------------
APPLE ROTTEN 2018 3 6
ORANGE ROTTEN 2018 1 2
but the problem is when I limit the where statement by searching for a specific DEFECT, I can't get the total for the FRUIT type for that year.
Here is my query so far
SELECT DISTINCT FRUIT
, Defect
, YEAR([Date]) As [YR]
, COUNT(Defect) AS [DEFECTCOUNT] -- This returns correctly
--, COUNT(*) AS [FRUITCOUNT] -- does return the correct number
FROM [dbo].[A_DETAIL_REPOS] dat
WHERE YEAR(dat.[Date]) >= '2018'
AND YEAR(dat.[Date]) <= '2018'
AND dat.Defect = 'ROTTEN'
GROUP BY FRUIT, Year([Date]), Defect
ORDER BY YEAR([Date])
Thank you for the help,
USE conditional COUNT() to get the rotten count.
SELECT FRUIT
--, Defect you only want 'ROTTEN' so you dont need this one
, YEAR([Date]) As [YR]
, COUNT( CASE WHEN Defect = 'ROTTEN' THEN 1 END ) AS [DEFECTCOUNT]
, COUNT(*) AS [FRUITCOUNT]
FROM [dbo].[A_DETAIL_REPOS] dat
WHERE YEAR(dat.[Date]) = '2018'
GROUP BY YEAR([Date]), FRUIT
You want conditional aggregation. However, I want to encourage you to use date comparisons for the filtering:
SELECT FRUIT, YEAR([Date]) As [YR],
SUM(CASE WHEN Defect = 'ROTTEN' THEN 1 ELSE 0 END) as num_rotten,
COUNT(*) as num_total
FROM [dbo].[A_DETAIL_REPOS] dat
WHERE r.[Date] >= '2018-01-01' AND
r.[Date] < '2019-01-01'
AND dat.Defect = 'ROTTEN'
GROUP BY FRUIT, Year([Date])
ORDER BY YEAR([Date]);
Direct date comparisons make it easier for the optimizer to produce the best query plan. In particular, it allows the use of an index, if appropriate.