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

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.

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;

How to get the asked columns for each customers

I have this table called table a
I need to get the CustomerID, sum(Income) of 2015, sum(Income) of 2016, did he ever bought productId A (boolean), is the total sum(income)> 1000 (boolean), number of total InvoiceID
all that in one query and the results should be with 1 row per customer.
please help I don't even know how to start!
This is basically conditional aggregation:
select customerid,
sum(case when extract(year from date) = 2015 then sales end) as sales_2015,
sum(case when extract(year from date) = 2016 then sales end) as sales_2016,
max( product = 'A' ) as ever_bought_a,
sum(income) > 1000 as sum_exceeds_1000,
count(*) as num_invoices
from t
group by customerid;
You haven't specified a database, so this is really psuedocode. You'll need to adapt it for your particular database.

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

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

MDX Count over time (years - not within a year)

I'd like to be able to rollup the count of commitments to a product over years -
The data for new commitments in each year looks like this:
Year | Count of new commitments | (What I'd like - count of new commitments to date)
1986 4 4
1987 22 26
1988 14 40
1989 1 41
I know that within a year you can do year to date, month to date etc, but I need to do it over multiple years.
the mdx that gives me the first 2 columns is (really simple - but I don't know where to go from here):
select [Measures].[Commitment Count] on 0
, [Date Dim].[CY Hierarchy].[Calendar Year] on 1
from [Cube]
Any help would be great
In MDX something along the line:
with member [x] as sum(
[Date Dim].[CY Hierarchy].[Calendar Year].members(0) : [Date Dim].[CY Hierarchy].currentMember,
[Measures].[Commitment Count]
)
select [x] on 0, [Date Dim].[CY Hierarchy].[Calendar Year] on 1 from [Cube]
Use a common table expression:
with sums (year,sumThisYear,cumulativeSum)
as (
select year
, sum(commitments) as sumThisYear
, sum(commitments) as cumulativeSum
from theTable
where year = (select min(year) from theTable)
group by year
union all
select child.year
, sum(child.commitments) as sumThisYear
, sum(child.commitments) + parent.cumulativeSum as cumulativeSum
from sums par
JOIN thetable Child on par.year = child.year - 1
group by child.year,parent.cumulativeSum
)
select * from sums
There's a bit of a "trick" in there grouping on parent.cumulativeSum. We know that this will be the same value for all rows, and we need to add it to sum(child.commitments), so we group on it so SQL Server will let us refer to it. That can probably be cleaned up to remove what might be called a "smell", but it will work.
Warning: 11:15pm where I am, written off the top of my head, may need a tweak or two.
EDIT: forgot the group by in the anchor clause, added that in