I want to get a particular value from 3 different tables. Each table has the same structure but contains data for a different period of a year.
Temp_Table_Jun (Contains data for June month)
---------------
CustNo CustName Revenue
1000 John 5.55
Similary I have two more tables
Temp_table_Apr
Temp_table_May
Now I run a query
select sum(Revenue)Rev_June from Temp_Table_Jun where CustNo='1000'
to get the results for June. Now my problem is I want to get the revenue details for all the month in a single query.
I need something like,(THIS IS WRONG AND DOESN'T WORK)
select Rev_June,Rev_Apr,Rev_May,((Rev_June+Rev_Apr+Rev_May)/3)Avg_3_Mon from
(
select sum(Revenue)Rev_June from Temp_Table_Jun where CustNo='1000',
select sum(Revenue)Rev_Apr from Temp_Table_Apr where CustNo='1000',
select sum(Revenue)Rev_May from Temp_Table_May where CustNo='1000'
)
How can this be achieved? I am using Oracle 10g.
To get the data you can do it the following way. Oracle 10g does not have a PIVOT but you can use CASE statements to replicate the functionality:
SELECT sum(case when month = 'June' then Rev END) June
, sum(case when month = 'May' then Rev END) May
, sum(case when month = 'April' then Rev END) April
, avg(Rev) as Average
FROM
(
SELECT sum(revenue) Rev, 'June' as Month from rev_june where cust_no = '1000'
union all
SELECT sum(revenue) Rev, 'April' from rev_apr where cust_no = '1000'
union all
SELECT sum(revenue) Rev, 'May' from rev_may where cust_no = '1000'
) x
See SQL Fiddle with Demo
Or you can do the following:
SELECT June, April, May, (June + April + May)/3 as Average
FROM
(
select
(SELECT sum(revenue) from rev_june where cust_no = '1000') as June
, (SELECT sum(revenue) from rev_apr where cust_no = '1000') as April
, (SELECT sum(revenue) from rev_may where cust_no = '1000') as May
from dual
) x
See SQL Fiddle with Demo
The following might work:
select Rev_June, Rev_Apr, Rev_May,
(Rev_June + Rev_Apr + Rev_May) / 3 Avg_3_Mon
from (
(select sum(Revenue) from Temp_Table_Jun where CustNo='1000') as Rev_June,
(select sum(Revenue) from Temp_Table_Apr where CustNo='1000') as Rev_Apr,
(select sum(Revenue) from Temp_Table_May where CustNo='1000') as Rev_May
from dual
)
I don't know if it works in Oracle 10g, but a UNION query roughly like the following would normally work in databases I've worked with:
select sum(Revenue) Rev_June from Temp_Table_Jun where CustNo='1000'
UNION
select sum(Revenue) Rev_Apr from Temp_Table_Apr where CustNo='1000'
UNION
select sum(Revenue) Rev_May from Temp_Table_May where CustNo='1000'
I'm not crysal clear about punctuation - do you need a semi-colon at the end etc? - but that might get you started.
I think I would do it slightly differently because each query must have the same structure for a UNION query to work:
select sum(Revenue) Revenue_Sum, 'Jun' Month from Temp_Table_Jun where CustNo='1000'
UNION
select sum(Revenue) Revenue_Sum, 'Apr' Month from Temp_Table_Apr where CustNo='1000'
UNION
select sum(Revenue) Revenue_Sum, 'May' Month from Temp_Table_May where CustNo='1000'
Now, that doesn't quite get the average sum and the 3 columns you're looking for, but perhaps you could create a VIEW with something like this UNION query and then use a GROUP BY query on that VIEW to aggregate the data.
Related
I have a table with the order lines which show the Booking Amount and the booked date, but the revenue is recognised over 3 months (so 1/3 in the booked month and a further 1/3 in each of the next 2 months).
I need to create a query that would show the total revenue recognised in each month.
Is there an analytic function that could work this out? as at the moment I have cobbled together 3 joined queries that give the number but in 3 seperate columns, where I need it in one column:
select TRUNC(OM.BOOKING_DATE, 'MONTH') as Month
, SUM(OM.BOOKED_VALUE)/3 as Month_1
, M2.Month_2
, M3.Month_3
from ORDERS.OM,
(select TRUNC(ADD_MONTHS(OM.BOOKING_DATE,1), 'MONTH') as Month
, SUM(OM.BOOKED_VALUE)/3 as Month_2
from ORDERS.OM
GROUP By TRUNC(ADD_MONTHS(OM.BOOKING_DATE,1), 'MONTH')) M2,
(select TRUNC(ADD_MONTHS(OM.BOOKING_DATE,2), 'MONTH') as Month
, SUM(OM.BOOKED_VALUE)/3 as Month_3
from ORDERS.OM
GROUP By TRUNC(ADD_MONTHS(OM.BOOKING_DATE,2), 'MONTH')) M3
WHERE TRUNC(OM.BOOKING_DATE, 'MONTH') = M2.MONTH
AND TRUNC(OM.BOOKING_DATE, 'MONTH') = M3.MONTH
GROUP By TRUNC(OM.BOOKING_DATE, 'MONTH'), M2.Month_2, M3.Month_3
Order by 1 DESC
Triple every row and sum
select t.Month, SUM(t.Val) as Value
from ORDERS.OM
cross join lateral (select TRUNC(OM.BOOKING_DATE, 'MONTH') as Month, OM.BOOKED_VALUE/3.0 as Val from dual union all
select TRUNC(ADD_MONTHS(OM.BOOKING_DATE,1), 'MONTH'), OM.BOOKED_VALUE/3.0 from dual union all
select TRUNC(ADD_MONTHS(OM.BOOKING_DATE,2), 'MONTH'), OM.BOOKED_VALUE/3.0 from dual ) t
group by t.Month
In this great article, I found the way to convert Year into Decade, but it looks too verbose to me!
Is there better way to do this?
#standardSQL
WITH data AS (
SELECT '1921' AS YEAR UNION ALL
SELECT '1932' UNION ALL
SELECT '1943' UNION ALL
SELECT '1954' UNION ALL
SELECT '1985' UNION ALL
SELECT '2006' UNION ALL
SELECT '2017' UNION ALL
SELECT '2018'
)
SELECT
YEAR,
CASE
WHEN YEAR LIKE "192%" THEN "20S"
WHEN YEAR LIKE "193%" THEN "30S"
WHEN YEAR LIKE "194%" THEN "40S"
WHEN YEAR LIKE "195%" THEN "50S"
WHEN YEAR LIKE "196%" THEN "60S"
WHEN YEAR LIKE "197%" THEN "70S"
WHEN YEAR LIKE "198%" THEN "80S"
WHEN YEAR LIKE "199%" THEN "90S"
WHEN YEAR LIKE "200%" THEN "2000S"
WHEN YEAR LIKE "201%" THEN "2010S"
END AS DECADES
FROM data
-- ORDER BY YEAR
To "extract" Decade from Year - REGEXP_REPLACE function can be used as in example below
#standardSQL
WITH data AS (
SELECT '1921' AS YEAR UNION ALL
SELECT '1932' UNION ALL
SELECT '1943' UNION ALL
SELECT '1954' UNION ALL
SELECT '1985' UNION ALL
SELECT '2006' UNION ALL
SELECT '2017' UNION ALL
SELECT '2028'
)
SELECT
YEAR,
REGEXP_REPLACE(YEAR, r'(?:19)(\d)\d|(20\d)\d', '\\1\\20s') AS DECADES
FROM data
-- ORDER BY YEAR
Need Suggestion to make it dynamic On Dates.
Expected:
Date, Total Sellers, Sellers From Previous Date
Currently:
Data in table(active_seller_codes): date, seller_code
Queries:
-- Date Wise Sellers Count
select date,count(distinct seller_code) as Sellers_COunt
from active_seller_codes where date between '2016-12-15' AND '2016-12-15'
-- Sellers from previous Days
select date,count(distinct seller_code) as Last_Day_Seller
from active_seller_codes
where date between '2016-12-15' AND '2016-12-15'
and seller_code IN(
select seller_code from active_seller_codes
where date between '2016-12-14' AND '2016-12-14'
)
group by 1
Database Using: Vertica
Reading attentively, you seem to want one row in the report, with the data from the search date in the first two columns and the data of the day before the search date in the third and fourth column, like so:
sales_date|sellers_count|prev_date |prev_sellers_count
2016-12-15| 8|2016-12-14| 5
The solution could be something like this (without the first Common Table Expression, which, in my case, contains the data, but in your case, the data would be in your active_seller_codes table.
WITH
-- initial input
(sales_date,seller_code) AS (
SELECT DATE '2016-12-15',42
UNION ALL SELECT DATE '2016-12-15',43
UNION ALL SELECT DATE '2016-12-15',44
UNION ALL SELECT DATE '2016-12-15',45
UNION ALL SELECT DATE '2016-12-15',46
UNION ALL SELECT DATE '2016-12-15',47
UNION ALL SELECT DATE '2016-12-15',48
UNION ALL SELECT DATE '2016-12-15',49
UNION ALL SELECT DATE '2016-12-14',42
UNION ALL SELECT DATE '2016-12-14',44
UNION ALL SELECT DATE '2016-12-14',46
UNION ALL SELECT DATE '2016-12-14',48
UNION ALL SELECT DATE '2016-12-14',50
UNION ALL SELECT DATE '2016-12-13',42
UNION ALL SELECT DATE '2016-12-13',43
UNION ALL SELECT DATE '2016-12-13',44
UNION ALL SELECT DATE '2016-12-13',45
UNION ALL SELECT DATE '2016-12-13',46
UNION ALL SELECT DATE '2016-12-13',47
UNION ALL SELECT DATE '2016-12-13',48
UNION ALL SELECT DATE '2016-12-13',49
)
,
-- search argument this, in the real query, would come just after the WITH keyword
-- as the above would be the source table
search_dt(search_dt) AS (SELECT DATE '2016-12-15')
,
-- the two days we're interested in, de-duped
distinct_two_days AS (
SELECT DISTINCT
sales_date
, seller_code
FROM active_seller_codes
WHERE sales_date IN (
SELECT search_dt FROM search_dt -- the search date
UNION ALL SELECT search_dt - 1 FROM search_dt -- the day before
)
)
,
-- the two days we want one above the other,
-- with index for the final pivot
vertical AS (
SELECT
ROW_NUMBER() OVER (ORDER BY sales_date DESC) AS idx
, sales_date
, count(DISTINCT seller_code) AS seller_count
FROM distinct_two_days
GROUP BY 2
)
SELECT
MAX(CASE idx WHEN 1 THEN sales_date END) AS sales_date
, SUM(CASE idx WHEN 1 THEN seller_count END) AS sellers_count
, MAX(CASE idx WHEN 2 THEN sales_date END) AS prev_date
, SUM(CASE idx WHEN 2 THEN seller_count END) AS prev_sellers_count
FROM vertical
;
sales_date|sellers_count|prev_date |prev_sellers_count
2016-12-15| 8|2016-12-14| 5
I have two queries
1)
select Year , Month, Sum(Stores) from ABC ;
2)
select Year, Month , Sum(SalesStores) from DEF ;
I want a result like :
**Year, Month , Sum(Stores), Sum(SalesStores)**
How can I do it ?
I tried union & Union all
select Year , Month, Sum(Stores) from ABC union
select Year, Month , Sum(SalesStores) from DEF ;
I see only 3 columns in the output
Year, Month Sum(Stores).
Here are the tables :
Year, Month Stores
Year Month SalesStores
Is there a way I can see the result in the format I would like to see ?
Since I don't know their relationship, I prefer to use UNION ALL.
SELECT Year,
Month,
MAX(TotalStores) TotalStores,
MAX(TotalSalesStores) TotalSalesStores
FROM
(
SELECT Year, Month,
SUM(Stores) TotalStores,
NULL TotalSalesStores
FROM ABC
UNION ALL
SELECT Year, Month,
NULL TotalStores,
SUM(SalesStores) TotalSalesStores
from DEF
) a
GROUP BY Year, Month
You can UNION them in the following fashion:
SELECT Year , Month, Sum(Stores) As Stores, NULL As SalesStores from ABC
UNION
SELECT Year , Month, NULL As Stores, Sum(Stores) As SalesStores from ABC
Or use UNION ALL if your logic allows it.
Try:
SELECT Year, Month, SUM(TotalStores) as TotalAllStores, SUM(TotalSalesStore) as TotalAllSalesStore
FROM
(
SELECT Year , Month, Sum(Stores) as TotalStores, 0 as TotalSalesStore from ABC union
UNION ALL
SELECT Year, Month , 0 as TotalStores, Sum(SalesStores) as TotalSalesStore from DEF
) SalesByYearMonth
GROUP BY Year, Month
I would use FULL OUTER JOIN thus:
SELECT ISNULL(x.[Year], y.[Year]) AS [Year],
ISNULL(x.[Month], y.[Month]) AS [Month],
x.Sum_Stores,
y.Sum_SalesStores
FROM (select Year , Month, Sum(Stores) AS Sum_Stores from ABC ...) AS x
FULL OUTER JOIN (select Year, Month , Sum(SalesStores) AS Sum_SalesStores from DEF ...) AS y
ON x.[Year] = y.[Year] AND x.[Month] = y.[Month]
I have a table which has a table like this.
Month-----Book_Type-----sold_in_Dollars
Jan----------A------------ 100
Jan----------B------------ 120
Feb----------A------------ 50
Mar----------A------------ 60
Mar----------B------------ 30
and so on
I have to calculate the expected sales for each month and book type based on the last 2 months sales.
So for March and type A it would be (100+50)/2 = 75
For March and type B it is 120/1 since no data for Feb is there.
I was trying to use the lag function but it wouldn't work since there is data missing in a few rows.
Any ideas on this?
Since it plans to ignore missing values, this should probably work. Don't have a database to test it on at the moment but will give it another go in the morning
select
month,
book_type,
sold_in_dollars,
avg(sold_in_dollars) over (partition by book_type order by month
range between interval '2' month preceding and interval '1' month preceding) as avg_sales
from myTable;
This sort of assumes that month has a date datatype and can be sorted on... if it's just a text string then you'll need something else.
Normally you could just use rows between 2 preceding and 1 preceding but but this will take the two previous data points and not necessarily the two previous months if there are rows missing.
You could work it out with lag but it would be a bit more complicated.
As far as I know, you can give a default value to lag() :
SELECT Book_Type,
(lag(sold_in_Dollars, 1, 0) OVER(PARTITION BY Book_Type ORDER BY Month) + lag(sold_in_Dollars, 2, 0) OVER(PARTITION BY Book_Type ORDER BY Month))/2 AS expected_sales
FROM your_table
GROUP BY Book_Type
(Assuming Month column doesn't really contain JAN or FEB but real, orderable dates.)
What about something like (forgive the sql server syntax, but you get the idea):
Select Book_type, AVG(sold_in_dollars)
from MyTable
where Month in (Month(DATEADD('mm'-1,GETDATE)),Month(DATEADD('mm'-2,GETDATE)))
group by booktype
A partition outer join can help create the missing data. Create a set of months and join those values to each row by the month and perform the join once for each book type. I created the months January through April in this example:
with test_data as
(
select to_date('01-JAN-2010', 'DD-MON-YYYY') month, 'A' book_type, 100 sold_in_dollars from dual union all
select to_date('01-JAN-2010', 'DD-MON-YYYY') month, 'B' book_type, 120 sold_in_dollars from dual union all
select to_date('01-FEB-2010', 'DD-MON-YYYY') month, 'A' book_type, 50 sold_in_dollars from dual union all
select to_date('01-MAR-2010', 'DD-MON-YYYY') month, 'A' book_type, 60 sold_in_dollars from dual union all
select to_date('01-MAR-2010', 'DD-MON-YYYY') month, 'B' book_type, 30 sold_in_dollars from dual
)
select book_type, month, sold_in_dollars
,case when denominator = 0 then 'N/A' else to_char(numerator / denominator) end expected_sales
from
(
select test_data.book_type, all_months.month, sold_in_dollars
,count(sold_in_dollars) over
(partition by book_type order by all_months.month rows between 2 preceding and 1 preceding) denominator
,sum(sold_in_dollars) over
(partition by book_type order by all_months.month rows between 2 preceding and 1 preceding) numerator
from
(
select add_months(to_date('01-JAN-2010', 'DD-MON-YYYY'), level-1) month from dual connect by level <= 4
) all_months
left outer join test_data partition by (test_data.book_type) on all_months.month = test_data.month
)
order by book_type, month