Subtotal levels for ROLLUP on four columns in Oracle SQL - sql

I'm trying to construct an Oracle SQL query using the ROLLUP operator. The query needs to summarize sales by year, quarter, store state, and store city over two years, with the result including subtotals for the two hierarchical dimensions of year/quarter and state/city. Here's my attempt thus far:
SELECT storestate, storecity, calyear, calquarter, SUM(sales) AS Sales
FROM store_dim, time_dim, sales_fact
WHERE sales_fact.storeid = store_dim.storeid
AND sales_fact.timenum = time_dim.timenum
AND (calyear BETWEEN 2011 AND 2012)
GROUP BY ROLLUP(calyear, calquarter, storestate, storecity);
I'm trying to figure out if, as it's currently written, the query is showing subtotals for the two hierarchies I'm looking for, rather than treating them as one big one. Attempting to map out the subtotal levels by hand didn't help, and I haven't been able to find any examples of a single ROLLUP with four columns from two dimensions, or an example of two ROLLUP operators in a single GROUP BY clause, like below:
GROUP BY ROLLUP(calyear, cal quarter), ROLLUP(storestate, storecity)
A breakdown of the subtotal levels produced by the two GROUP BY clauses would be hugely helpful.
Edit: I'm specifically to use ROLLUP here. GROUPING SETS would generally be the first choice for this kind of query otherwise.

Use grouping sets . . . and proper, explicit, standard join syntax:
select s.storestate, s.storecity, t.calyear, t.calquarter,
sum(sf.sales) AS Sales
from sales_fact sf join
store_dim s
on s.storeid = sf.storeid join
time_dim t
on sf.timenum = t.timenum
where calyear between 2011 and 2012
group by grouping sets ( (calyear, calquarter, storestate, storecity),
(calyear, calquarter), (storestate, storecity)
);

Related

How to SUM two different Amount_Eur from two different Type_Trans columns SQL

Here is the table:
SELECT
*
FROM
Fact_Transactions;
Here is my code to only select two columns as an example:
SELECT
type_trans,
SUM(Amount_Eur) AS Total_Ins
FROM
fact_transactions
WHERE
type_trans IN ('CARD-INCOMING', 'BANK-INCOMING')
GROUP BY
type_trans;
Now, I want to `SUM`` the total.
Thanks in advance!
I tried to sum two amounts from different columns (Card-Incoming and Bank-Incoming)
I tried to reproduce the scenario in my environment
IN SQL there is a CUBE function
The CUBE operator generates multiple grouping sets inside a GROUP BY.
CUBE generates subtotals across all column combinations specified in GROUP BY.
Code Example:
SELECT
coalesce([Type_T rans],'Total') as [Type_T rans],
SUM(Amount_Eur) AS Total_Ins
FROM
fact_transactions
WHERE
[Type_T rans] IN ('CARD-INCOMING', 'BANK-INCOMING')
GROUP BY CUBE ([Type_T rans]);
Output:

Difference between HAVING and WHERE in SQL

I've seen in other questions that the difference between HAVING and WHERE in SQL is that HAVING is used post-aggregation whereas WHERE is used pre-aggregation. However, I am still unsure about when to use pre-aggregation filtering or post-aggregation filtering.
As a concrete example, why don't these two queries yield the same result (the second sums quantity prematurely in a way that squashes the GROUP BY call)?
Using WHERE to obtain number of condo sales of each real estate agent.
SELECT agentId, SUM(quantity) total_sales
FROM sales s, houses h
WHERE s.houseId = h.houseId AND h.type = "condo"
GROUP BY agentId
ORDER BY total_sales;
Attempted use of HAVING to obtain the same quantity as above.
SELECT agentId, SUM(quantity) total_sales
FROM sales s, houses h
GROUP BY agentId
HAVING s.houseId = h.houseId AND h.type = "condo"
ORDER BY total_sales;
Note: these were written/tested/executed in sqlite3.
The simple way to think about it is to consider the order in which the steps are applied.
Step 1: Where clause filters data
Step 2: Group by is implemented (SUM / MAX / MIN / ETC)
Step 3: Having clause filters the results
So in your 2 examples:
SELECT agentId, SUM(quantity) total_sales
FROM sales s, houses h
WHERE s.houseId = h.houseId AND h.type = "condo"
GROUP BY agentId
ORDER BY total_sales;
Step 1: Filter by HouseId and Condo
Step 2: Add up the results
(number of houses that match the houseid and condo)
SELECT agentId, SUM(quantity) total_sales
FROM sales s, houses h
GROUP BY agentId
HAVING s.houseId = h.houseId AND h.type = "condo"
ORDER BY total_sales;
Step 1: No Filter
Step 2: Add up quantity of all houses
Step 3: Filter the results by houseid and condo.
Hopefully this clears up what is happening.
The easiest way to decide which you should use is:
- Use WHERE to filter the data
- Use HAVING to filter the results of an aggregation (SUM / MAX / MIN / ETC)
WHERE filters rows from the database. Then, if the query has aggregation, aggregation is ran based on the aggregate functions and GROUP BY clause in the query. After that point, HAVING is applied to filter the grouping results. The only filtering that HAVING allows is filtering on GROUP BY columns or calculated aggregates.
I must assume that you're using MySQL for your example query since, as other answers have noted, your HAVING clause doesn't make sense and MySQL has some default behaviors which are occasionally problematic and confusing.
First, learn to use proper, explicit, standard JOIN syntax.
Second, your query should look like:
SELECT s.agentId, SUM(s.quantity) as total_sales
FROM sales s JOIN
houses h
ON s.houseId = h.houseId
WHERE h.type = 'condo'
GROUP BY s.agentId
ORDER BY total_sales;
Your version of the query should generate an error in any reasonable database, because the HAVING clause has columns that are neither GROUP BY keys nor aggregation functions.
Additional notes:
The delimiter for a string is single quotes. If you use double quotes, things may not work as you expect.
You should qualify all column references, especially when your query references more than one table.
JOIN conditions belong in the ON clause, not in a WHERE clause.
Filtering on h.type after the aggregation makes no sense. If it did work, the sum() would include non-condos because the filtering is happening too late.

SQL months_between grouping issue

First post; go easy on me.
Relatively new to SQL (anything beyond simple queries really), but attempting to learn more complex functions in an effort to take advantage of superior server resources. My issue:
I would like to use a SUM function to aggregate cash flows across a very large variety of sources. I would like to see these cash flows along a monthly time period. Because the cash flows start at different times, I would like to season them so that they are all aligned. My current code:
select
months_between(A.reporting_date, B.start_date) as season,
sum(case when A.current_balance is null then B.original_balance
else A.current_balance end) as cashflow
from dataset1 A, dataset2 B
group by season
order by season
Now, executing the code like this generates an error message that states that A.reporting_date and B.start_date must be GROUPED or part of an AGGREGATE function.
The problem is, if I add them to the GROUP BY statement, while it generates output without error, I get cash flow sums that are essentially Cartesian crosses with all the grouped variables.
So long story short, is there any way for me to get cash flow sums grouped by only the season? If so, any ideas how to do it?
Thank you.
Most databases don't allow using column aliases defined previously, in where, group by and order by clauses.
For your query you should use months_between(A.reporting_date, B.start_date) instead of the alias season in group by and order by.
Also your query will return a cross product, as a join condition isn't specified.
select
months_between(A.reporting_date, B.start_date) as season,
sum(case when A.current_balance is null then B.original_balance
else A.current_balance end) as cashflow
from dataset1 A
JOIN dataset2 B ON --add a join condition
group by months_between(A.reporting_date, B.start_date)
order by months_between(A.reporting_date, B.start_date)

How to GROUP BY on Oracle?

I need help with sql oracle, my group by doesnt work and i'm working on a shell so i don't have any help.
Can someone tell me how to group this next request by noArticle.
SELECT Article.noArticle, quantite
FROM Article LEFT JOIN LigneCommande ON Article.noArticle = LigneCommande.noArticle
GROUP BY Article.noArticle
/
Thank you
To tie things up, this is the correct SQL.
SELECT Article.noArticle, sum(quantite)
FROM Article LEFT JOIN LigneCommande ON Article.noArticle = LigneCommande.noArticle
GROUP BY Article.noArticle
You are grouping by a column and then you attempt to use the quantite field which is not group-level, it is record-level. Group by is aggregation and you have to use aggregate columns (the columns you are grouping by or aggregate functions on columns, like sum, avg, count, max or min). You need to aggregate your record-level fields to be able to use them in your projection (select clause). To name an example, your attempt was like trying to get the hair color of American women (of course, there are many American women and they might have different hair color, so it is unnatural and un-wise to attempt to get the value of hair color from the set of American women). Your fixed query is as follows:
SELECT Article.noArticle, sum(quantite)
FROM Article LEFT JOIN LigneCommande ON Article.noArticle = LigneCommande.noArticle
GROUP BY Article.noArticle
For my situation i need the summation of the quantite so in order to make it work i added SUM(quantite) and then i grouped by noArticle

MS Access 2010 report using two different tables

I am trying to display total of each stock with their description in a report. I have got 2 queries but do not know how to combine them. First query
SELECT
stock_partno, SUM(stock_qty) AS TotalStock
FROM
stock
GROUP BY
stock_partno;
Second query
SELECT DISTINCT
Stock.stock_PartNo, parts.parts_Desc
FROM
parts
INNER JOIN
stock
ON
parts.Parts_partno = Stock.stock_PartNo;
How do I combine both these queries so that they can display a report with total stock of each Part with their description?
To be able to select the parts_Desc column, add it to the GROUP BY clause. That will maintain the same grouping as in the first query (because each part number has just one description).
SELECT
SUM(stock.stock_qty) AS TotalStock,
Stock.stock_PartNo, parts.parts_Desc
FROM
parts
INNER JOIN
stock
ON
parts.Parts_partno = Stock.stock_PartNo;
GROUP BY
Stock.stock_partno, parts.parts_Desc;