Oracle sql: Order by with GROUP BY ROLLUP - sql

I'm looking everywhere for an answer but nothing seems to compare with my problem. So, using rollup with query:
select year, month, count (sale_id) from sales
group by rollup (year, month);
Will give the result like:
YEAR MONTH TOTAL
2015 1 200
2015 2 415
2015 null 615
2016 1 444
2016 2 423
2016 null 867
null null 1482
And I would like to sort by total desc, but I would like year with biggest total to be on top (important: with all records that compares to that year), and then other records for other years. So I would like it to look like:
YEAR MONTH TOTAL
null null 1482
2016 null 867
2016 1 444
2016 2 423
2015 null 615
2015 2 415
2015 1 200
Or something like that. Main purpose is to not "split" records comparing to one year while sorting it with total. Can somebody help me with that?

Try using window function max to get max of total for each year in the order by clause:
select year, month, count(sale_id) total
from sales
group by rollup(year, month)
order by max(total) over (partition by year) desc, total desc;

Hmmm. I think this does what you want:
select year, month, count(sale_id) as cnt
from sales
group by rollup (year, month)
order by sum(count(sale_id)) over (partition by year) desc, year;
Actually, I've never use window functions in an order by with a rollup query. I wouldn't be surprised if a subquery were necessary.

I think you need to used GROUPING SETS and GROUP_ID's. These will help you determine a NULL caused by a subtotal. Take a look at the doc: https://docs.oracle.com/cd/B19306_01/server.102/b14223/aggreg.htm

Related

SQL How to take the minium for multiple fields?

Consider the following data set that records the product sold, year, and revenue from that particular product in thousands of dollars. This data table (YEARLY_PRODUCT_REVENUE) is stored in SQL and has many more rows.
Year | Product | Revenue
2000 Table 100
2000 Chair 200
2000 Bed 150
2010 Table 120
2010 Chair 190
2010 Bed 390
Using SQL, for every year I would like to find the product that has the maximum revenue.
That is, I would like my output to be the following:
Year | Product | Revenue
2000 Chair 200
2010 Bed 390
My attempt so far has been this:
SELECT year, product, MIN(revenue)
FROM YEARLY_PRODUCT_REVENUE
GROUP BY article, month;
But when I do this, I get multiple-year values for distinct products. For instance, I'm getting the output below which is an error. I'm not entirely sure what the error here is. Any help would be much appreciated!
Year | Product | Revenue
2000 Table 100
2000 Bed 150
2010 Table 120
2010 Chair 190
You don't mention the database so I'll assume it's PostgreSQL. You can do:
select distinct on (year) * from t order by year, revenue desc
You want filtering rather than aggregation. We can use window functions (which most databases support) to rank yearly product sales, and then retain only the top selling product per year.
select *
from (
select r.*, rank() over(partition by year order by revenue desc) rn
from yearly_product_revenue r
) r
where rn = 1;
Here is a shorter solution if your database support the standard WITH TIES clause:
select *
from yearly_product_revenue r
order by rank() over(partition by year order by revenue desc)
fetch first row with ties

How to get monthwise sum from table?

Table Transaction(Id, DateTime, Debit, Credit)
I want a monthwise sum of Debit and Credit.
What is a good option to retrieve monthwise result?
Sample Output:
Month Id Debit Credit
January 1 200 70
January 2 400 80
February 1 400 90
February 2 300 50
Try this below script with GROUP BY function. I have added YEAR in consideration other wise same month from different year will count as same month.
SELECT YEAR(DateTime),
MONTH(DateTime),
Id,
SUM(Debit) total_debit,
SUM(Credit) total_credit
FROM your_table
GROUP BY YEAR(DateTime), MONTH(DateTime), Id
Apply Group by clause to SQL Query
group by month(DateTime),Year(DateTime)

Hive: error calculating SUM then MAX of grouped items

I would like to run a query that calculates maximum money spent for each month of each credit card. For each credit card, I will need to calculate the sum of money spent each month. I have a table containing transactions of credit cards credit_transact:
processdate timestamp ""
cardno_hash string ""
amount int ""
year int ""
month int ""
Made-up sample data:
card year month amount
a123 2016 12 23160
a123 2016 10 287
c123 2016 11 5503
c123 2016 11 4206
I would like:
card year month amount
a123 2016 12 23160
c123 2016 11 9709
One important thing is year and month are partition columns.
I have tried a subquery like below:
USE credit_card_db;
SELECT sum_amount_transact.cardno_hash, sum_amount_transact.year, sum_amount_transact.month, MAX(sum_amount_transact.sum_amount)
FROM
(
SELECT cardno_hash, year, month, SUM(amount) AS sum_amount FROM credit_transact
GROUP BY cardno_hash, year, month
) AS sum_amount_transact
GROUP BY sum_amount_transact.cardno_hash, sum_amount_transact.year;
However, the following error is shown:
java.lang.Exception: org.apache.hive.service.cli.HiveSQLException: Error while compiling statement: FAILED: SemanticException Line 0:-1 Invalid column reference 'month'
The following subquery worked fine and returned results as expected:
SELECT cardno_hash, year, month, SUM(amount) AS sum_amount FROM credit_transact
GROUP BY cardno_hash, year, month
The result is:
card year month amount
a123 2016 12 23160
a123 2016 10 287
c123 2016 11 9709
Would very much appreciate if anyone can help with this problem.
I can't quite tell what you really want, but I'm pretty sure you want row_number(). I think you want the maximum month per year:
SELECT ct.*
FROM (SELECT cardno_hash, year, month, SUM(amount) AS sum_amount,
ROW_NUMBER() OVER (PARTITION BY cardno_hash, year ORDER BY SUM(amount) DESC) as seqnum
FROM credit_transact
GROUP BY cardno_hash, year, month
) ct
WHERE seqnum = 1;

Counting unique combinations up until a date - per month

I am looking into a table with transaction data of a two-sided platform, where you have buyers and sellers. I want to know the total amount of unique combinations of buyers and sellers. Let's say, Abe buys from Brandon in January, that's 1 combination. If Abe buys with Cece in February, that makes 2, but if Abe then buys from Brandon again, it's still 2.
My solution was to use the DENSE_RANK() function:
WITH
combos AS (
SELECT
t.buyerid, t.sellerid,
DENSE_RANK() OVER (ORDER BY t.buyerid, t.sellerid) AS combinations
FROM transactions t
WHERE t.transaction_date < '2018-05-01'
)
SELECT
MAX(combinations) AS total_combinations
FROM combos
This works fine. Each new combo gets a higher rank, and if you select the MAX of that result, you know the amount of unique combos.
However, I want to know this total amount of unique combos on a per month basis. The problem here is that if I group per transaction month, it only counts the unique combos in that month. In the example of Abe, it would be a unique combo in January, and then another combo in the next month, because that's how grouping works in SQL.
Example:
transaction_date buyerid sellerid
2018-01-03 3828 219
2018-01-08 2831 123
2018-02-10 3828 219
The output of DENSE_RANK() named combinations over all these rows is:
transaction_date buyerid sellerid combinations
2018-01-03 3828 219 1
2018-01-08 2831 123 2
2018-02-10 3828 219 2
And therefore, when selecting the MAX combinations you know the amount of unique buyer/seller combos, which is here.
However, I would like to see a running total of unique combos up until each start of the month, for all months until now. But, when we group on month, it would go like this:
transaction_date buyerid sellerid month combinations
2018-01-03 3828 219 jan 1
2018-01-08 2831 123 jan 2
2018-02-10 3828 219 feb 1
While I actually would want an output like:
month total_combinations_at_month_start
jan 0
feb 2
mar 2
How should I solve this? I've tried to find help on all kinds of window functions, but no luck until now. Thanks!
Here is one method:
WITH combos AS (
SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY sellerid, buyerid ORDER BY t.transaction_date) as combo_seqnum,
ROW_NUMBER() OVER (PARTITION BY sellerid, buyerid, date_trunc('month', t.transaction_date) ORDER BY t.transaction_date) as combo_month_seqnum
FROM transactions t
WHERE t.transaction_date < '2018-05-01'
)
SELECT 'Overall' as which, COUNT(*)
FROM combos
WHERE combo_seqnum = 1
UNION ALL
SELECT to_char(transaction_date, 'YYYY-MM'), COUNT(*)
FROM combos
WHERE combo_month_seqnum = 1
GROUP BY to_char(transaction_date, 'YYYY-MM');
This puts the results in separate rows. If you want a cumulative number and number per month:
SELECT to_char(transaction_date, 'YYYY-MM'),
SUM( (combo_month_seqnum = 1)::int ) as uniques_in_month,
SUM(SUM( (combo_seqnum = 1)::int )) OVER (ORDER BY to_char(transaction_date, 'YYYY-MM')) as uniques_through_month
FROM combos
GROUP BY to_char(transaction_date, 'YYYY-MM')
Here is a rextester illustrating the solution.

Getting the max from two combined columns

I'm trying to get the value from all accounts in use, using the combination of two columns (Year and month) to get the right period.
The data table looks like this:
Account
Year
Month
Value
1000
2015
1
11501
1000
2016
1
11111
1000
2016
10
11610
1000
2017
1
11701
2000
2014
12
22222
2000
2017
1
21701
3000
2015
1
33333
4000
2016
1
44444
Table: AcBal
I've tried to make an query, but somehow, I cant quite get there...
Select Account,
Year,
Month,
MAX(((Year*100)+Month)) AS YearPeriod,
Value
from AcBal
where YearPeriod <= 201601
group by Account, Year, Month, Value
order by Account, Year
If I use "where year <= 2017", then I get a result, but with multiple hits for each accout. I only want one result for each account.
Wanted result:
Account
Year
Month
Value
1000
2016
1
11111
2000
2014
12
22222
3000
2015
1
33333
4000
2016
1
44444
How can I achieve that?
You could use TOP (1) WITH TIES and ROW_NUMBER() OVER() like the following query
Select TOP (1) WITH TIES
Account, [Year], [Month], [Year]*100+[Month] AS YearPeriod , Value
from AcBal
where [Year]*100+[Month] <=201601
ORDER BY ROW_NUMBER() OVER(PARTITION BY Account ORDER BY [Year]*100 +[Month] DESC)
Demo link: http://rextester.com/DUPJ25770
Use HAVING:
Select Account, Year, Month, MAX(((Year*100)+Month)) AS YearPeriod , Value
from AcBal
group by Account, Year, Month, Value
Having MAX(((Year*100)+Month)) <=201601
order by Account, Year