Calculating a summary of previously calculated data - sql

Quick question about summary data:
I have the below code which will pull sales information and put it into a month/year grid, which is terrific (http://sqlfiddle.com/#!3/9d79e/1):
WITH
months AS (SELECT 1 AS mon UNION ALL SELECT mon + 1 FROM months WHERE mon < 12),
years AS (SELECT 2011 AS yr UNION ALL SELECT yr + 1 FROM years WHERE yr < 2015),
invoices AS (
SELECT CAST('2013-06-27' AS date) AS InvoiceDate, 40 AS MarginAmount
UNION
SELECT CAST('2013-07-29' AS date) AS InvoiceDate, 40 AS MarginAmount
UNION
SELECT CAST('2013-10-30' AS date) AS InvoiceDate, 40 AS MarginAmount
)
-- End data setup, real work begins here
SELECT * FROM
(
SELECT
months.mon, years.yr, COALESCE(SUM(inv.MarginAmount), 0) AS MarginAmount
FROM
months
CROSS JOIN years
LEFT OUTER JOIN invoices inv ON ( (YEAR(inv.InvoiceDate) = years.yr) AND (MONTH(inv.InvoiceDate) = months.mon) )
GROUP BY
months.mon, years.yr
) AS source
PIVOT
(
MAX(MarginAmount)
FOR yr in ([2011], [2012], [2013], [2014], [2015])
)
AS pvt
ORDER BY mon
I was wondering how I could change two things:
Replace the numbers 1 - 11 with the names of the months of the year and
Create a line at the bottom of the table summarizing the information above it, where the mon column would have the word 'Total'
Any help would be greatly appreciated
e.g The sum of all sales in 2012 would be displayed at the bottom of the 2012 column

Question 1. Replace numbers
To replace the numbers, you can for instance change this:
months AS (SELECT 1 AS mon UNION ALL SELECT mon + 1 FROM months WHERE mon < 12)
to
months AS (SELECT 1 AS mon, 'Jan' name UNION ALL SELECT mon + 1, months.name FROM months WHERE mon < 12)
Question 2. Grand totals
To create a bottom line with totals you can either use grouping sets (your query seems to be SQL Server, don't know whether SQL Server supports that, please specify):
group
by grouping sets
( ()
, (full list)
)
or add a union to the query:
with myresults as (the whole thing)
select 1 ordering
, myresults.columns-minus-total
, myresults.something subtotal
from myresults
union all
select 2 ordering
, myresults.columns-minus-total
, sum(something) grandtotal
from myresults
order
by 1
, ...other...
Complete example using Microsoft SQL Server 2008 R2
Original code was prettified and without dependencies on tables:
with months as
( select 1 as mon
, 'Jan' monname
union all
select 2
, 'Feb'
union all
select 3
, 'Mar'
union all
select 4
, 'Apr'
union all
select 5
, 'May'
union all
select 6
, 'Jun'
union all
select 7
, 'Jul'
union all
select 8
, 'Aug'
union all
select 9
, 'Sep'
union all
select 10
, 'Oct'
union all
select 11
, 'Nov'
union all
select 12
, 'Dec'
)
, years as
( select 2011 as yr
union all
select 2012
union all
select 2013
union all
select 2014
)
, invoices as
( select cast('2013-06-27' as date) as invoicedate
, 40 as marginamount
union
select cast('2013-07-29' as date) as invoicedate
, 40 as marginamount
union
select cast('2013-10-30' as date) as invoicedate
, 40 as marginamount
)
select *
from ( select months.mon
, years.yr
, coalesce(sum(inv.marginamount), 0) as marginamount
from months
cross
join years
left
outer
join invoices inv
on year(inv.invoicedate) = years.yr
and month(inv.invoicedate) = months.mon
group
by months.mon
, years.yr
) source
pivot ( max(marginamount)
for yr
in ( [2011], [2012], [2013], [2014], [2015]
)
) pvt
order
by mon
Adding the text and grand totals leads to:
with months as
( select 1 as mon
, 'Jan' monname
union all
select 2
, 'Feb'
union all
select 3
, 'Mar'
union all
select 4
, 'Apr'
union all
select 5
, 'May'
union all
select 6
, 'Jun'
union all
select 7
, 'Jul'
union all
select 8
, 'Aug'
union all
select 9
, 'Sep'
union all
select 10
, 'Oct'
union all
select 11
, 'Nov'
union all
select 12
, 'Dec'
)
, years as
( select 2011 as yr
union all
select 2012
union all
select 2013
union all
select 2014
)
, invoices as
( select cast('2013-06-27' as date) as invoicedate
, 40 as marginamount
union
select cast('2013-07-29' as date) as invoicedate
, 40 as marginamount
union
select cast('2013-10-30' as date) as invoicedate
, 40 as marginamount
)
select case
when mon is null
then 'Total'
else cast(mon as varchar)
end
, monname
, [2011]
, [2012]
, [2013]
, [2014]
, [2015]
from ( select months.mon
, months.monname
, years.yr
, coalesce(sum(inv.marginamount), 0) as marginamount
from months
cross
join years
left
outer
join invoices inv
on year(inv.invoicedate) = years.yr
and month(inv.invoicedate) = months.mon
group
by grouping sets
( (months.mon, months.monname, years.yr)
, (years.yr)
)
) source
pivot ( max(marginamount)
for yr
in ( [2011], [2012], [2013], [2014], [2015]
)
) pvt
order
by coalesce(mon, 100)

Related

convert column to row in oracle [duplicate]

This question already has answers here:
Using pivot on multiple columns of an Oracle row
(3 answers)
Closed 10 months ago.
I have a question, is there any method that convert colum to row.
for example,I have a table like this:
CREATE TABLE mytable(u_id, month, offer, revenue) as
SELECT 1, 'January', 'Offer_1', 45 FROM dual
UNION ALL
SELECT 1, 'February','Offer_2', 40 FROM dual
UNION ALL
SELECT 1, 'March' ,'Offer_1', 35 FROM dual
UNION ALL
SELECT 2, 'January' ,'Offer_2', 40 FROM dual
UNION ALL
SELECT 2, 'February','Offer_3', 40 FROM dual
UNION ALL
SELECT 2, 'March' ,'Offer_1', 50 FROM dual;
and my expected table is
(There should be one row per user)
u_id
january_offer
january_revenue
february_offer
february_revenue
march_offer
march_revenue
1
Offer_1
45
Offer_2
40
Offer_1
35
2
Offer_2
40
Offer_3
40
Offer_1
50
I tried:
SELECT t1.u_id,
t1.january_offer,
t1.january_revenue,
t2.february_offer,
t2.february_revenue,
t3.march_offer,
t3.march_revenue
FROM (SELECT u_id, offer AS january_offer,
revenue AS january_revenue
FROM mytable
WHERE month = 'January') t1
LEFT JOIN (SELECT u_id,
offer AS february_offer,
revenue AS february_revenue
FROM mytable t1
WHERE month = 'February') t2
ON t1.u_id = t2.u_id
LEFT JOIN (SELECT u_id, offer AS march_offer,
revenue AS march_revenue
FROM mytable t1
WHERE month = 'March') t3
ON t2.u_id = t3.u_id
but,real, I have lots of data and a long SQL script and this method aggravates my script.
This is what PIVOT is designed for:
SELECT *
FROM package
PIVOT (
MAX(offer) AS offer, MAX(revenue) AS revenue
FOR month IN ( 'January' AS january, 'February' AS feburary, 'March' AS march )
)
Which, for the sample data:
CREATE TABLE package (U_id, month, offer,revenue) AS
SELECT 1, 'January', 'offer_1', 45 FROM DUAL UNION ALL
SELECT 1, 'February', 'offer_2', 40 FROM DUAL UNION ALL
SELECT 1, 'March', 'offer_1', 35 FROM DUAL UNION ALL
SELECT 2, 'January', 'offer_2', 40 FROM DUAL UNION ALL
SELECT 2, 'February', 'offer_3', 40 FROM DUAL UNION ALL
SELECT 2, 'March', 'offer_1', 50 FROM DUAL;
Outputs:
U_ID
JANUARY_OFFER
JANUARY_REVENUE
FEBURARY_OFFER
FEBURARY_REVENUE
MARCH_OFFER
MARCH_REVENUE
1
offer_1
45
offer_2
40
offer_1
35
2
offer_2
40
offer_3
40
offer_1
50
db<>fiddle here
An alternative pattern that might be more efficient is to use a case expression:
SELECT t1.u_id
, CASE month WHEN 'January' then offer END AS january_offer
, CASE month WHEN 'January' then revenue END AS january_revenue
, CASE month WHEN 'February' then offer END AS february_offer
, ...
From there you can use an aggregate function to eliminate null rows:
SELECT u_id
, MAX(january_offer) AS january_offer
, MAX(january_revenue) AS january_revenue
, MAX(february_offer) AS february_offer
, ...
FROM (
SELECT t1.u_id
, CASE month WHEN 'January' then offer END AS january_offer
, CASE month WHEN 'February' then offer END AS february_offer
, ...
) AS t
GROUP BY u_id
In general, this kind of operation is better handled in the presentation layer of the application than in the database layer.
You can use conditional aggregation along with CASE..WHEN expressions such as
SELECT u_id,
MAX(CASE WHEN month = 'January' THEN offer END) AS january_offer,
MAX(CASE WHEN month = 'January' THEN revenue END) AS january_revenue,
MAX(CASE WHEN month = 'February' THEN offer END) AS february_offer,
MAX(CASE WHEN month = 'February' THEN revenue END) AS february_revenue,
MAX(CASE WHEN month = 'March' THEN offer END) AS march_offer,
MAX(CASE WHEN month = 'March' THEN revenue END) AS march_revenue
FROM t
GROUP BY u_id
or by using DECODE() function such as
SELECT u_id,
MAX(DECODE (month , 'January', offer)) AS january_offer,
MAX(DECODE (month , 'January', revenue)) AS january_revenue,
MAX(DECODE (month , 'February', offer)) AS february_offer,
MAX(DECODE (month , 'February', revenue)) AS february_revenue,
MAX(DECODE (month , 'March', offer)) AS march_offer,
MAX(DECODE (month , 'March', revenue)) AS march_revenue
FROM t
GROUP BY u_id
Demo

Create financial report with SQL

I want to create a financial report using a select statement for example: my start month is april 2000 and the end month is march 2001 how can I do that?
SELECT monthList.MonthName ,transcation.id,transaction.amount(
SELECT 10 ordby, 'January' MonthName
UNION SELECT 11, 'February'
UNION SELECT 12, 'March'
UNION SELECT 1, 'April'
UNION SELECT 2,'May'
UNION SELECT 3,'June'
UNION SELECT 4,'July'
UNION SELECT 5,'August'
UNION SELECT 6,'September'
UNION SELECT 7,'October'
UNION SELECT 8,'November'
UNION SELECT 9,'December') monthList
left JOIN (select YEAR(Date) [Year], MONTH(Date) [Month],DATENAME(MONTH,Date) [Month Name],sum(Amount)as amount
FROM transaction
where id=2 GROUP BY YEAR(Date), MONTH(Date),DATENAME(MONTH, Date) ) as t on t.[Month Name]=monthList.[Month Name])

How to convert column into rows in oracle 10g

Suppose I have the result of an Oracle sql query:
Month Date
----- -----
Jan 10
Jan 15
Jan 20
Feb 11
Feb 16
Feb 25
I want to display this data in the following format:
Jan Jan Jan Feb Feb Feb
10 15 20 11 16 25
How to write the query?
Using PIVOT:
SQL> WITH sample_data AS(
2 SELECT 'Jan' mnth, 10 dt FROM dual UNION ALL
3 SELECT 'Jan' mnth, 15 dt FROM dual UNION ALL
4 SELECT 'Jan' mnth, 20 dt FROM dual UNION ALL
5 SELECT 'Feb' mnth, 11 dt FROM dual UNION ALL
6 SELECT 'Feb' mnth, 16 dt FROM dual UNION ALL
7 SELECT 'Feb' mnth, 25 dt FROM dual
8 )
9 -- end of smaple_data mimicking real table
10 SELECT *
11 FROM
12 (SELECT dt, row_number() OVER(ORDER BY NULL) rn FROM sample_data
13 ) PIVOT (MAX(dt) FOR (rn)
14 IN (1 AS Jan_1, 2 AS jan_2, 3 AS Jan_3, 4 AS Feb_1, 5 Feb_2, 6 Feb_3));
JAN_1 JAN_2 JAN_3 FEB_1 FEB_2 FEB_3
---------- ---------- ---------- ---------- ---------- ----------
10 15 20 11 16 25
Under the hood PIVOT is same MAX + CASE. You can check it in 12c where Oracle added EXPAND_SQL_TEXT procedure to DBMS_UTILITY package.
SQL> VARIABLE c CLOB
SQL> BEGIN
2 dbms_utility.expand_sql_text(Q'[WITH sample_data AS(
3 SELECT 'Jan' mnth, 10 dt FROM dual UNION ALL
4 SELECT 'Jan' mnth, 15 dt FROM dual UNION ALL
5 SELECT 'Jan' mnth, 20 dt FROM dual UNION ALL
6 SELECT 'Feb' mnth, 11 dt FROM dual UNION ALL
7 SELECT 'Feb' mnth, 16 dt FROM dual UNION ALL
8 SELECT 'Feb' mnth, 25 dt FROM dual
9 )
10 -- end of smaple_data mimicking real table
11 SELECT *
12 FROM
13 (SELECT dt, row_number() OVER(ORDER BY NULL) rn FROM sample_data
14 ) PIVOT (MAX(dt) FOR (rn)
15 IN (1 AS Jan_1, 2 AS jan_2, 3 AS Jan_3, 4 AS Feb_1, 5 Feb_2, 6 Feb_3))]',:c);
16 END;
17 /
PL/SQL procedure successfully completed.
Now let's see what Oracle actually does internally:
SQL> set long 100000
SQL> print c
C
--------------------------------------------------------------------------------
SELECT "A1"."JAN_1" "JAN_1",
"A1"."JAN_2" "JAN_2",
"A1"."JAN_3" "JAN_3",
"A1"."FEB_1" "FEB_1",
"A1"."FEB_2" "FEB_2",
"A1"."FEB_3" "FEB_3"
FROM
(SELECT MAX(
CASE WHE N ("A2"."RN"=1)
THEN "A2"."DT"
END ) "JAN_1",
MAX(
CASE
WHEN ("A2"."RN"=2)
THEN " A2"."DT"
END ) "JAN_2",
MAX(
CASE
WHEN ("A2"."RN"=3)
THEN "A2"."DT"
END ) "JAN_3" ,
MAX(
CASE
WHEN ("A2"."RN"=4)
THEN "A2"."DT"
END ) "FEB_1",
MAX(
CASE
WHEN ("A2". "RN"=5)
THEN "A2"."DT"
END ) "FEB_2",
MAX(
CASE
WHEN ("A2"."RN"=6)
THEN "A2"."DT"
END ) "FEB_3"
FROM
(SELECT "A3"."DT" "DT",
ROW_NUMBER() OVER ( ORDER BY NULL) " RN"
FROM (
(SELECT 'Jan' "MNTH",10 "DT" FROM "SYS"."DUAL" "A10"
)
UNION ALL (SE LECT 'Jan' "MNTH",15 "DT" FROM "SYS"."DUAL" "A9")
UNION ALL
(SELECT 'Jan' "MNTH",20 "DT" FROM "SYS"."DUAL" "A8"
)
UNION ALL
(SELECT 'Feb' "MNTH",11 "DT" FROM " SYS"."DUAL" "A7"
)
UNION ALL
(SELECT 'Feb' "MNTH",16 "DT" FROM "SYS"."DUAL" "A6"
)
UNION ALL
(SELECT 'Feb' "MNTH",25 "DT" FROM "SYS"."DUAL" "A5"
)) "A3"
) "A2"
) " A1"
WITH dates( month, day ) AS (
SELECT 'Jan', 10 FROM DUAL UNION ALL
SELECT 'Jan', 15 FROM DUAL UNION ALL
SELECT 'Jan', 20 FROM DUAL UNION ALL
SELECT 'Feb', 11 FROM DUAL UNION ALL
SELECT 'Feb', 16 FROM DUAL UNION ALL
SELECT 'Feb', 25 FROM DUAL
),
ordered_dates( month, day, seq_no ) AS (
SELECT month,
day,
ROW_NUMBER() OVER ( PARTITION BY month ORDER BY day )
FROM dates
)
SELECT MAX( CASE WHEN month = 'Jan' AND seq_no = 1 THEN day END ) AS "Jan",
MAX( CASE WHEN month = 'Jan' AND seq_no = 2 THEN day END ) AS "Jan",
MAX( CASE WHEN month = 'Jan' AND seq_no = 3 THEN day END ) AS "Jan",
MAX( CASE WHEN month = 'Feb' AND seq_no = 1 THEN day END ) AS "Feb",
MAX( CASE WHEN month = 'Feb' AND seq_no = 2 THEN day END ) AS "Feb",
MAX( CASE WHEN month = 'Feb' AND seq_no = 3 THEN day END ) AS "Feb"
FROM ordered_dates;
Output:
Jan Jan Jan Feb Feb Feb
---------- ---------- ---------- ---------- ---------- ----------
10 15 20 11 16 25

How to select month wise data for year from sql server

I have a user table where data is about 20 years old.
I want to fetch month wise data from CreatedOn column that is (2014-07-08 17:44:00) and if data is not available for any month then I want 0 for this month
Example
Month data year
jan 34 2014
feb 56 2014
march 0 2014
apr 23 2014
I am using the following query but it's not working:
with cte(monno , monname ) as(
select 1, 'Jan' union all
select 2, 'Feb' union all
select 3, 'Mar' union all
select 4, 'Apr' union all
select 5, 'May' union all
select 6, 'Jun' union all
select 7, 'Jul' union all
select 8, 'Aug' union all
select 9, 'Sep' union all
select 10, 'Oct' union all
select 11, 'Nov' union all
select 12, 'Dec'
)
SELECT DISTINCT monname
,monno
,count(CreatedOn) OVER (PARTITION BY datepart(year, CreatedOn),DATEPART(MONTH, CreatedOn))
FROM Contributors_tbl a
RIGHT JOIN cte b ON DATEPART(MONTH, CreatedOn) = b.monno
AND datepart(year, CreatedOn) = 2014
ORDER BY monno
Try this Way to find Month Number AND Month Name
CREATE TABLE #TempMonth
(
MonthNum int,
MonthNames varchar(50)
)
INSERT INTO #TempMonth
SELECT STR(MONTH(DATEADD(mm, number, GETDATE())), 2) AS MonthNum,
DATENAME(month, DATEADD(month, MONTH(DATEADD(mm, number, GETDATE())), 0) - 1) AS MonthNames
FROM master.dbo.spt_values
WHERE (name IS NULL) AND (number BETWEEN 0 AND 11) ORDER BY STR(MONTH(DATEADD(mm, number, GETDATE())), 2)
SELECT * FROM #TempMonth
select distinct MonthNames,MonthNum,
count(CreatedOn) over(partition by datepart(year,CreatedOn),DATEPART(MONTH,CreatedOn))
from Contributors_tbl a
right join #TempMonth b on DATEPART(MONTH,CreatedOn) = b.MonthNum and datepart(year,CreatedOn) = 2014
order by MonthNum
DROP Table #TempMonth
Try This
with cte(monno , monname ) as(
select 1, 'Jan' union all
select 2, 'Feb' union all
select 3, 'Mar' union all
select 4, 'Apr' union all
select 5, 'May' union all
select 6, 'Jun' union all
select 7, 'Jul' union all
select 8, 'Aug' union all
select 9, 'Sep' union all
select 10, 'Oct' union all
select 11, 'Nov' union all
select 12, 'Dec'
)
select monname,
monno,
coalesce(cnt,0) as cnt
from cte c
outer apply (
select count(*) as cnt
from Contributors_tbl
where CreatedOn >= DATEADD(mm,c.monno - 1,'20140101')
And CreatedOn < DATEADD(mm,c.monno,'20140101')
)t
order by monno

Sql query for aggregation

Let consider the below table structure
Product Year Month Price
A 2011 01 23
A 2011 02 34
.......
.....
A 2011 12 54
B 2011 01 13
B 2011 02 12
.......
.....
B 2011 12 20
From this table i need to aggregate the value for every 3 months ie..,
Product Year Month Price
A 2011 1-3 45
A 2011 4-6 23
A 2011 7-9 45
A 2011 10-12 16
A 2012 1-3 12
.......
.......
Can anybody tell me how to do this calculation using sql query...
Thanks in Advance !!!
Try this. Use Case statement to group the month Quarter wise then find the sum of price
SELECT product,
[year],
CASE
WHEN ( [month] ) IN( '01', '02', '03' ) THEN '1-3'
WHEN ( [month] ) IN( '04', '05', '06' ) THEN '4-6'
WHEN ( [month] ) IN( '07', '08', '09' ) THEN '7-9'
WHEN ( [month] ) IN( '10', '11', '12' ) THEN '10-12'
END [Month],
Sum(Price)
FROM tablename
GROUP BY product,
[year],
CASE
WHEN ( [month] ) IN( '01', '02', '03' ) THEN '1-3'
WHEN ( [month] ) IN( '04', '05', '06' ) THEN '4-6'
WHEN ( [month] ) IN( '07', '08', '09' ) THEN '7-9'
WHEN ( [month] ) IN( '10', '11', '12' ) THEN '10-12'
END
Note : By looking at your month data it looks like its a varchar column but you can change it to TINYINT
Try using CASE in GROUP BY clause:
...
GROUR BY [Year], CASE WHEN Month in (1,2,3) THEN '1-3'
WHEN Month in (4,5,6) THEN '4-6'
...
END
Considering Month is stored as varchar(), you can write as:
Select Product,
Year,
[MonthRange] as [Month],
Sum(Price)
From (
select Product,
Year,
case when Month in ('01','02','03') then '[1-3]'
when Month in ('04','05','06') then '[4-6]'
when Month in ('07','08','09') then '[7-9]'
when Month in ('10','11','12') then '[10-12]'
end as [MonthRange],
Price
from #test) as T
Group by Product,Year,[MonthRange]
DEMO
select Product, [year], case when [month] between 1 and 3 then '01-03' else case when [month] between 4 and 6 then '04-06' else case when [month] between 7 and 9 then '07-09' else '10-12' end end end, sum([price])
from Table1
group by Product, [year], case when [month] between 1 and 3 then '01-03' else case when [month] between 4 and 6 then '04-06' else case when [month] between 7 and 9 then '07-09' else '10-12' end end end
Above sql query will give you the required results, if you don not use leading zeros which I used in month labels then you will not get result sorted by month.
Use this query.
CREATE table #test
(
product VARCHAR(10),
year int,
month int,
price int
)
INSERT INTO #test
SELECT 'A', 2011, 01, 23 UNION
SELECT 'A', 2011, 02, 65 UNION
SELECT 'A', 2011, 03, 45 UNION
SELECT 'B', 2011, 04, 34 UNION
SELECT 'B', 2011, 05, 67 UNION
SELECT 'B', 2011, 06, 34 UNION
SELECT 'B', 2011, 07, 87 UNION
SELECT 'B', 2011, 08, 2 UNION
SELECT 'B', 2011, 09, 345 UNION
SELECT 'B', 2011, 10, 9 UNION
SELECT 'B', 2011, 11, 293 UNION
SELECT 'B', 2011, 12, 23
SELECT product, [year], [MONTH], SUM(price)
FROM
(
SELECT product, [year], CASE WHEN [MONTH] IN (01,02,03) THEN '1-3'
WHEN [MONTH] IN (04,05,06) THEN '4-6'
WHEN [MONTH] IN (07,08,09) THEN '7-9'
WHEN [MONTH] IN (10, 11, 12) THEN '10-12'
END AS [Month],
price
FROm #Test
)AS A
group BY product, [year], [Month]