SQL - Splitting / Prorating a metric - sql

I have a table where a household ID can have multiple customer ID's. But revenue is linked to household ID. So when looking at the table with both household ID and customer ID, revenue is double counted. Sample below.
HHID 123 has 3 customers, total revenue is only $900 for the household but if I sum grouped by HHID, it's $2700. Similarly, HHID 456 has 2 customers and HHID 789 has 1.
How do I create a column to split this revenue per customer ID. I can do this in multiple steps but I'm wondering if there is a way to do this in one query.
HH ID CUST ID REVENUE NEW_COL
123 5655 $900 $300
123 6678 $900 $300
123 8893 $900 $300
789 8988 $350 $350
456 2343 $400 $200
456 4555 $400 $200
I need the table to have both HH ID and CUST ID since some metrics are based on HH and some based on CUST (such as age). So I need to add a column like the above to the table so I can use it to sum revenue instead of the actual revenue column.
I'm on Teradata.

Related

updating transactions with preaggregated data

I have a transactions table. I need to update the table with a pre-aggregated value from another table and then roll these down to varying levels of granularity.
However, the final output is incorrect. Hoping someone here can help me figure out how to go about this.
Table A:
TransID BankName Location Region SaleType MonthlyPayment Weight
1 BOA Boston East F 3000 3
2 Mellon Pittsburgh East C 1000 3
3 BOA Boston East C 2000 2
4 BOA Boston East 1000 2
Table B
BanKname Location Region Sales
BOA Boston East 500
Mellon Pittsburgh East 1000
Desired Output structure
BankName Location Region SaleType AvgSales AvgMonthlyPayment
Issue is that when updating and doing the weighted average, each of the Boston transactions is getting the 500 sales. When added, total sales should be 1500 but is now 2500.
If I update Table A with Sales value from Table B, sales gets repeated for each saletype - so it throws off the final average sales.
update is this: (Added new column sales in A)
update a
set a.sales = b.sales
from tableA a join tableB b on a.bankname=b.bankname and
a.location=b.location and a.region = b.region
weighted average from A is calculated like this:
select bankname,location,region,saletype,
sum(case when sales is not null then sales*weight else 0
end)/sum(weight) as avgsales
, sum(case when monthlypayment is not null then monthlypayment*weight
else 0 end)/sum(weight) as avgmonthlyp
from tableA
group by bankname,location,region,saletype
For each saletype, the sales is updated with value thus increasing the final value by that fold.
How can I update sales so that BOA only gets 500 and Mellon only gets 1000 and the total # sales is at 1500?

Performing calculations based on dates in oracle

I have the following tables.
Accounts(account_number*,balance)
Transactions(account_number*,transaction_number*,date,amount,type)
Date is the date that the transaction happened. Amount is the amount of the transaction
and it can have a positive or a negative value, dependent of the type(Withdrawal -,Deposit +). I think the type is irrelevant here as the amount is already given in the proper way.
I need to write a query which points out the account_number of the accounts that have at least once had negative balance.
Here's some sample data from the Transactions table, ordered by account_number and date.
account_number transaction_number date amount type
--------------------------------------------------------------------
1 2 02/03/2013 -20000 withdrawal
1 3 03/15/2013 300 deposit
1 1 01/01/2013 100 deposit
2 1 04/15/2013 235236 deposit
3 1 06/15/2013 500 deposit
4 1 03/01/2013 10 deposit
4 2 04/01/2013 80 deposit
5 1 11/11/2013 10000 deposit
5 2 12/11/2013 20000 deposit
5 3 12/13/2013 -10002 withdrawal
6 1 03/15/2013 102300 deposit
7 1 03/15/2013 100 deposit
8 1 08/08/2013 133990 deposit
9 1 05/09/2013 10000 deposit
9 2 06/01/2013 300 deposit
9 3 10/11/2013 23 deposit
Something like this with an analytic to keep a running balance for an account:
SELECT DISTINCT account_number
FROM ( SELECT account_number
,SUM(amount)
OVER (PARTITION BY account_number ORDER BY date) AS running_balance
FROM transactions
) x
WHERE running_balance < 0
Explanation:
It is using an analytic function: the PARTITION BY breaks the table into groups identified by the account number. Within each group, the data is ordered by date. Then there is a walk through each element in the ordered group and the SUM function is applied (by default summing everything from the beginning of the group to the current row). This gives you a running balance. Just run the inner query on its own and take a look at the output, then read a bit about analytic queries. They are pretty cool.

How to join tables based on the dates

COMMISSION table
PRODUCT_ID DATE COMMISSION
1 20110101 27.00
1 20120101 28.00
1 20130705 30.00
2 20110101 17.00
2 20120501 16.00
2 20130101 18.00
...
ORDER table
PRODUCT_ID DATE PRICE
1 20110405 2500
2 20130402 3000
2 20130101 1900
Desired output
PRODUCT_ID DATE PRICE COMMISSION
1 20110405 2500 27.00
2 20130402 3000 16.00
2 20130101 1900 18.00
Commission table records commission % based on the product id and date.
Order table is basically a record of orders placed on a particular date,
I'd like to join two tables and bring the appropriate commission based on the date of the order. For example, you can see that the first order's commission is 27.00 as the date for the product_id 1 falls between 20110101 and 20120101.
How do I do this? Seems like a simple 1 to n relationship but I can't figure it out.
Try
SELECT o.*,
(
SELECT TOP 1 commission
FROM commission
WHERE product_id = o.product_id
AND date <= o.date
ORDER BY date DESC
) commission
FROM [order] o
Here is SQLFiddle demo

Combining two tables in a query and creating new columns from that

I'm having issues with a query that I'm not ENTIRELY sure can be done with the way the database is set up. Basically, I'll be using two different tables in my query, let's say Transactions and Ticket Prices. They look like this (With some sample data):
TRANSACTIONS
Transation ID | Ticket Quantity | Total Price | Salesperson | Ticket Price ID
5489 250 250 Jim 8765
5465 50 150 Jim 1258
7898 36 45 Ann 4774
Ticket Prices
Ticket Price ID | Quantity | Price | Bundle Name
8765 1 1 1 ticket, $1
4774 12 15 5 tickets, $10
1258 1 3 1 ticket, $3
What I'm aiming for is a report, that breaks down each salesperson's sales by bundle type. The resulting table should be something like this:
Sales Volume/Salesperson
Name | Bundle A | Bundle B | Bundle C | Total
Jim 250 0 50 300
Ann 0 36 0 36
I've been searching the web, and it seems the best way of getting it like this is using various subqueries, which works well as far as getting the column titles properly displayed, but it doesn't work as far as the actual numerical totals. It basically combines the data, giving each salesperson a total readout (In this example, both Jim and Ann would have 250 sales in Bundle A, 36 in Bundle B, etc). Is there any way I can write a query that will give me the proper results? Or even something at least close to it? Thanks for any input.
You can use the PIVOT statement in Oracle to do this. A query might look something like this:
WITH pivot_data AS (
SELECT t.salesperson,p.bundle_name,t.ticket_quantity
FROM ticket_prices p, transactions t
where t.ticket_price_id = p.ticket_price_id
)
SELECT *
FROM pivot_data
PIVOT (
sum(ticket_quantity) --<-- pivot_clause
FOR bundle_name --<-- pivot_for_clause
IN ('1 ticket, $1','5 tickets, $10', '1 ticket, $3' ) --<-- pivot_in_clause
);
which would give you results like this:

Creating a Summary Tracking Report from Details

I need to create a summary monthly tracking report from detailed data. A sample of the data is as follows:
Company | Country | Join Date
Company A | USA | 1/1/2011
Company B | Ireland | 5/5/2011
Company C | Italy | 7/11/2011
Company D | Germany | 6/14/2011
I need to create a report that would give me the number of members that joined in a given month from a given country, in the format below:
Country 1 | Total (January) | Total (Feb) | Total (Mar, etc) |Sum (Monthly Totals)
Country 2 | Total (January) | Total (Feb) | Total (Mar, etc) |Sum (Monthly Totals)
Country 3 | Total (January) | Total (Feb) | Total (Mar, etc) |Sum (Monthly Totals)
At the bottom of each column I would need the sum for each month for all countries. Also, this report would need to be a rolling report, so when the user generates it, it will provide the most recent information.
You're going to want to do this in two parts.
First, you're going to want to get the relevant data from the database. Probably best accomplished by a statement such as:
SELECT country, year(join_date) as year, month(join_date) as month, count(*)
FROM trackingTable
WHERE join_date between :start_date and :end_date
GROUP BY country, year(join_date), month(join_date)
ORDER BY country, year, month
For your given data, this will generate the following sample:
Country Year Month Count
==================================
Germany 2011 6 1
Ireland 2011 5 1
Italy 2011 7 1
USA 2011 1 1
Second (and I'm assuming that you're creating/formatting the report in an outside language), read through the data sequentially. Given the ORDER BY, each country will be a separate sequence. Psuedo-code for your needs:
for each row in set {
if different country {
total up row, start new line
}
add month cell to column;
add month cell to month grand total;
}
total up grand total row, print/save