Create SQL view column from result set - sql

I'm new to SQL and attempting to revise a Create View script to add a new column from a select statement result set I've googled this quite a bit but haven't seen a good example.
Here's the select statement:
select lease_id, year(posting_date) as years1, SUM(amount) as Annual
from la_tbl_lease_projection
group by year(posting_date), lease_id
order by lease_id
The complicating factor is this. The Annual column in the result set is the Annual sum of expenses for a lease_id. However, in the view I'm adding the column to, expenses are listed monthly. So lease_id 100001 has 12 lines in 2010, 2011, etc. I want the view to have the new column show the Annual amount on each of the 12 monthly line items. The new Annual column should be to the right of the amount column and each line should contain the sum of the amount column for that year. e.g.:
Lease_id Posting_Date Amount Annual
100001 2010-01-01 $25 $300
100001 2010-02-01 $25 $300
etc...............
The view I'm adding to is a reasonably complex join and union from multiple tables. Instead of creating a new table for my result set, I'd like to access it using a stored procedure, unless there's a better option. MSDN says temp tables and table variables don't work in views so that's not an option.
I think this can be done by something like "when years1 = years1 AND lease_id = lease_id then [Annual] = resultset total, but can't seem to visualize it. Thanks in advance for your input.

Since you were looking at MSDN, I'm assuming SQL Server for this answer;
To get a yearly column that's a by year sum of amounts, you can use SUM() OVER ();
SELECT *, SUM(Amount) OVER (PARTITION BY YEAR(Posting_Date)) Yearly
FROM la_tbl_lease_projection;
An SQLfiddle to test with.

I think a derived table would do the trick for you something like:
select blah, blah2, blah3, ..., a.annual
from
<Long complicated set of joins>
join
(select lease_id, year(posting_date) as years1, SUM(amount) as Annual
from la_tbl_lease_projection
group by year(posting_date), lease_id
order by lease_id) a
on sometable.lease_id = a.lease_id and year(sometable .posting_date) = a.years1
Where <complex where conditions>

Related

Calculating the percentage of different types of customer feedback in each quarter

The problem statement is: I have a table (order_t) which has customer feedback (one column) and quarter number (as another column).
Using a CTE, I need to calculate the percentage of number of customer feedback in each category as well as the total number of customer feedback in each quarter.
After this happens, I need the percentage of different types of customer feedback (like good, bad, ok, very good, very bad) but using CTE.
How can I solve this statement?
I try to solve customer feedback as
WITH total_feedback AS
(
SELECT *
COUNT(CUSTOMER_FEEDBACK), QUARTER NUMBER
FROM
table1
GROUP BY
2
)
But I'm unable to calculate the first half portion, i.e. percentage of different types of customer feedback in each quarter using CTE.
How can I do that?
Find the file of the data
What you could do, and I'll keep the example as close to the code you provided as possible, is the following - using 2 CTE's:
WITH total_feedback AS (
SELECT COUNT(CUSTOMER_FEEDBACK) AS total_feedback, QUARTER_NUMBER
FROM table1
GROUP BY 2
),
category_feedback AS (
SELECT COUNT(CUSTOMER_FEEDBACK) AS feedback_count, CUSTOMER_FEEDBACK, QUARTER_NUMBER
FROM table1
GROUP BY 2, 3
)
SELECT
category_feedback.CUSTOMER_FEEDBACK,
category_feedback.QUARTER_NUMBER,
(feedback_count / total_feedback.total_feedback) * 100 AS feedback_percentage
FROM category_feedback
INNER JOIN total_feedback
ON category_feedback.QUARTER_NUMBER = total_feedback.QUARTER_NUMBER

SQL Create Table by OrderID & Product Code between Ship & Return Date w Wkly Revenue

Lo Folks o/
I apologize if I've titled this incorrectly or my terminology may be lacking as I am self-taught in writing SQL data queries; however, I am stuck on how to create one to produce data I need for a weekly rate of return review by product and order based on the orders' ship and return dates.
I have orders' line item detail to the product, qty, price etc. I am needing to group the data by the week start dates between the "ship" and "return" dates then calculate that week's revenue based on the line item's total over the number of weeks [and days in that week] the product is out.
I am also not sure if I even have the permissions to create a table, if that is necessary, nor where to begin to create this type of query.
Any help, direction or suggestions would be greatly appreciated.
Thanks all o/
My raw data looks like
And an excel view of my expected results
hmm ill take a stab - I am assuming you have an ORDERS o table (first image) and a RETURNS r table (second image). Also assuming you have the prodcode in your RETURNS table - maybe something like this:
WITH return_details as (
SELECT o.main_order, o.maincode, o.itemtotal,
r.ship_date, r.return_date,
DATE_TRUNC('WEEK', r.ship_date) as ship_week,
datediff(day, r.return_date, r.ship_date) as ship2return
FROM RETURNS r INNER JOIN ORDERS o ON
r.orderid = o.main_order AND r.prod_code = o.maincode
)
SELECT rd.main_order as order_id,
rd.maincode as prod_code,
rd.ship_week,
SUM(rd.itemtotal) as SUM_REVENUE,
SUM(rd.ship2return) as SUM_DAYSOUT,
AVG(rd.ship2return) as AVG_DAYSOUT
FROM return_details rd
GROUP BY order_id, prod_code, ship_week;

SQL - How can I sum up a column after the results have been grouped and filtered in the having clause?

Here is my current query: The objective is to find accounts that have received at least $500 in deposits within 30 days of their first deposit. Some accounts have been closed and re-opened, hence the first line of the 'WHERE' clause.
select Deposits.accountNumber,
min(Deposits.transDate) as "first deposit",
Deposits.transDate,
CAST(DATEADD(d,30,min(Deposits.transDate)) as date) as "30 days",
sum(Deposits.amount) as "sum",
Deposits.amount,
Members.accountOpenDate
from Deposits
inner join Members on Deposits.accountNumber = members.accountNumber
where Deposits.transDate >= members.accountOpenDate
and Deposits.accountNumber = 123456
group by Deposits.accountNumber
having Deposits.transDate between min(Deposits.transDate) and DATEADD('d',30,min(Deposits.transDate))
and sum(Deposits.amount) >= 500
The problem I am running into, is that the last line of the HAVING statement:
and sum(Deposits.amount) >= 500
is including all of the transactions for the account, as if there was no 'HAVING' clause. It is factoring in transactions that are excluded from the first line of the 'HAVING':
having Deposits.transDate between min(Deposits.transDate) and DATEADD('d',30,min(Deposits.transDate))
Here is what my data looks like (without grouping by account number):
accountNumber amount sum
123456 $100 $6,500
123456 $50 $6,500
123456 $50 $6,500
And here is what I am trying to get to:
accountNumber amount sum
123456 $100 $200
123456 $50 $200
123456 $50 $200
Thanks in advance. My DBMS is Intersystems-Cache. A link to their reference can be found Here.
You can try something like that:
select filtered.accountNumber,
min(filtered.transDate) as "first deposit",
filtered.transDate,
CAST(DATEADD(d,30,min(filtered.transDate)) as date) as "30 days",
sum(filtered.amount) as "sum",
filtered.amount,
filtered.accountOpenDate
from
(
select * from Deposits
inner join Members on Deposits.accountNumber = members.accountNumber
where Deposits.transDate >= members.accountOpenDate
and Deposits.accountNumber = 123456
having Deposits.transDate between min(Deposits.transDate) and DATEADD('d',30,min(Deposits.transDate))
) as filtered
group by filtered.accountNumber
having sum(filtered.amount) >= 500
With a query like that one you are first filtering your data applying the transDate condition then you can operate the filter on the sum of the amount
We need clarification:
1. Are the 3 transactions you show all within the 30 day window? If yes, then the total is less than $500. So, this account should be skipped.
2. Since $6500 is the total of all trans greater than the open date, why even calculate it? You only care about the 30 day window.
Besides that, I think the disconnect is the date calculation in the HAVING clause. You use MIN in the SELECT, but use a totally different aggregate date calculation in the HAVING. I think you should take the calculation out of the HAVING and make it part of the WHERE.
Of course, once you do that, you'll have to take the MIN out of the SELECT.

select and delete query based on older entries

I have an Excel sheet that is pushing data to an Access database using ADO. It is essentially putting invoices into a database. Sometimes I will revise my invoice and therefore the database will end up with the same invoice twice. I need to make a select and delete query that will find duplicates based on the invoice number, and delete the older version of the invoice (older record), for a simple example:
id invoice# total item datestamp
1 1234 456.29$ shoes 06/06/2016 03:51
2 1234 78.58$ boots 06/06/2016 03:51
3 1234 22.74$ scarf 06/06/2016 03:51
4 1234 539.34$ shoes 06/07/2016 12:44
4 1234 66.24$ pants 06/07/2016 12:44
As you can see row 4 and 5 are my new invoice for this customer. I want every previous order of the same invoice # to be deleted. Please note: they are not actually duplicates, only the invoice number is duplicated. The query needs to see dupliactes based on invoice number and criteria sees dates older than the most recent date.
At that point it is way beyond me. I would appreciate the help.
Consider using a correlated aggregate subquery in WHERE clause:
DELETE *
FROM InvoiceTable
WHERE NOT datestamp IN
(SELECT Max(datestamp)
FROM InvoiceTable sub
WHERE sub.InvoiceNumber = InvoiceTable.InvoiceNumber)
As I said, try being conservative and not deleting. Instead, select rows that are based on the maximum date stamp for a given invoice number:
SELECT
invoices.id, invoices.invoice, invoices.total, invoices.item, invoices.datestamp
FROM
invoices
INNER JOIN
(SELECT
id, MAX(datestamp) AS maxdate
FROM
invoices
GROUP BY
id) lastinv
ON invoices.id = lastinv.id AND
invoices.datestamp = lastinv.maxdate
This is untested code, but should, pretty much do what you want. All you have to do is mangle it into Microsoft Access, as this is T-SQL.

Two tables with no direct relationship

I have 2 tables with no relation between them. I want to display the data in tabular format by month. Here is a sample output:
There are 2 different tables
1 for income
1 for expense
Problem is that we have no direct relation between these. The only commonality between them is month (date). Does anyone have a suggestion on how to generate such a report?
here is my union queries:
SELECT TO_DATE(TO_CHAR(PAY_DATE,'MON-YYYY'), 'MON-YYYY') , 'FEE RECEIPT', NVL(SUM(SFP.AMOUNT_PAID),0) AMT_RECIEVED
FROM STU_FEE_PAYMENT SFP, STU_CLASS SC, CLASS C
WHERE SC.CLASS_ID = C.CLASS_ID
AND SFP.STUDENT_NO = SC.STUDENT_NO
AND PAY_DATE BETWEEN '01-JAN-2014' AND '31-DEC-2014'
AND SFP.AMOUNT_PAID >0
GROUP BY TO_CHAR(PAY_DATE,'MON-YYYY')
UNION
SELECT TO_DATE(TO_CHAR(EXP_DATE,'MON-YYYY'), 'MON-YYYY') , ET.DESCRIPTION, SUM(EXP_AMOUNT)
FROM EXP_DETAIL ED, EXP_TYPE ET, EXP_TYPE_DETAIL ETD
WHERE ET.EXP_ID = ETD.EXP_ID
AND ED.EXP_ID = ET.EXP_ID
AND ED.EXP_DETAIL_ID = ETD.EXP_DETAIL_ID
AND EXP_DATE BETWEEN '01-JAN-2014' AND '31-DEC-2014'
GROUP BY TO_CHAR(EXP_DATE,'MON-YYYY'), ET.DESCRIPTION
ORDER BY 1
Regards:
In order to do this you probably want to make the Income and Expenses into separate sub-queries.
I have taken the two parts of your union query and separated them into sub-queries, one called income and one called expense. Both sub-queries summarise the data over the month period as before, but now you can use a JOIN on the Months to allow the data from each sub-query to be connected. Note: I have used an OUTER JOIN, because this will still join month where there is no income, but there is expense and vice versa. This will require some manipulation, because you probably are better off returning a set of zeros for the month if no transaction occur.
In the top level SELECT, replace the use of *, with the correct listing of fields required. I simply used this to show that each field can be reused from the sub-query in the outer query, by referring to the alias as the table name.
SELECT Income.*, Expenses.*
FROM (SELECT TO_DATE(TO_CHAR(PAY_DATE,'MON-YYYY'), 'MON-YYYY') as Month, 'FEE RECEIPT', NVL(SUM(SFP.AMOUNT_PAID),0) AMT_RECIEVED
FROM STU_FEE_PAYMENT SFP, STU_CLASS SC, CLASS C
WHERE SC.CLASS_ID = C.CLASS_ID
AND SFP.STUDENT_NO = SC.STUDENT_NO
AND PAY_DATE BETWEEN '01-JAN-2014' AND '31-DEC-2014'
AND SFP.AMOUNT_PAID >0
GROUP BY TO_CHAR(PAY_DATE,'MON-YYYY') Income
OUTER JOIN (SELECT TO_DATE(TO_CHAR(EXP_DATE,'MON-YYYY'), 'MON-YYYY') as Month, ET.DESCRIPTION, SUM(EXP_AMOUNT)
FROM EXP_DETAIL ED, EXP_TYPE ET, EXP_TYPE_DETAIL ETD
WHERE ET.EXP_ID = ETD.EXP_ID
AND ED.EXP_ID = ET.EXP_ID
AND ED.EXP_DETAIL_ID = ETD.EXP_DETAIL_ID
AND EXP_DATE BETWEEN '01-JAN-2014' AND '31-DEC-2014'
GROUP BY TO_CHAR(EXP_DATE,'MON-YYYY'), ET.DESCRIPTION) Expenses
ON Income.Month = Expenses.Month
There are still many calculations that you will have to insert, to get your final result, which you will have to work on separately. The resulting query to perform what you expect above will likely be a lot longer than this, I am just trying to show you the structure.
However the final tricky part for you is going to be the BBF. Balance Bought Forward. SQL is great a joining tables and columns, but each row is treated and handled separately, it does not read and value from the previous row within a query and allow you to manipulate that value in the next row. To do this you need another sub-query to SUM() all the changes from a point in time up until the start of the month. Financial products normally store Balance at points in time, because it is possible that not all transaction are accurately recorded and there needs to be a mechanism to adjust the Balance. Using this theory, you you need to write your sub-query to summarise all changes since the previous Balance.
IMO Financial applications are inherently complex, so the solution is going to take some time to mould into the right one.
Final Word: I am not familiar with OracleReports, but there may be something in there which will assist with maintaining the BBF.
sqlite> create table Income(Month text, total_income real);
sqlite> create table Expense(Month text, total_expense real);
sqlite> insert into Income values('Jan 2014', 9000);
sqlite> insert into Income values('Feb 2014', 6000);
sqlite> insert into Expense values('Jan 2014', 9000);
sqlite> insert into Expense values('Feb 2014', 18000);
sqlite> select Income.Month, Income.total_income, Expense.total_expense, Income.total_income - Expense.total_expense as Balance from Income, Expense where Income.Month == Expense.Month
Jan 2014|9000.0|9000.0|0.0
Feb 2014|6000.0|18000.0|-12000.0