SQL inner query trying to use alias in the where clause - sql

I have a join of 2 tables, that represent a list of payments that contracts have done.
Sample Query: (https://www.db-fiddle.com/f/iXGxgDTopsBBgXGUJsXpa/13)
That sample data consist of 5 contracts, some of them are running behind in payments, so I want to get the list of contracts that havent done a payment in the last 7 days, considering the current date to be: 9 of may of 2021.
For the example, contracts 121, 300, 321 and 400 have made a payment in the last 7 days, so any records from them should not appear in the final query. However:
Contract 321 despite of a payment in the last 7 days they had a reversal that was the total of the credits made by them in the last 7 days, this is equivalent to 0 payments, so I want this contract to appear in my final query.
Contract 121, I dont want to appear in the final result becuase despite of the reversal the is a total credits of 20 (100 credit - 80 reversal)
Contract 400 I want to appear in my results because one of the rows has as codename Special Delete.
In the fiddle I was able to create the query that Filters all records with payments in the last 7 days, but I need help adding the extra filtering:
If any contract that appear there if the sum of the credits and debits is 0, then appear it should appear in the final result (as it is like no payments have been send) this will be the case for the contract 321.
If the credits are positive but one of the rows has as codename "SpecialDelete" then display it in the final result (this is the case for the contract 400)
Total Debits against total credits greater than 0
I will be using this query with AWS Athena
I am guessing the part I need to ammend is (WHERE Payments.ContractID NOT IN ....):
SELECT PaymentID,
Payments.ContractID,
PaymentDate,
Credit,
Debit,
Code,
CodeName,
amount,
city
FROM Payments
LEFT JOIN Info ON Info.ContractID = Payments.ContractID
WHERE Payments.ContractID NOT IN (
SELECT Payments.ContractID
FROM Payments
WHERE PaymentDate >= '20210501'
)
ORDER BY PaymentDate DESC
;

you guess is correct, Here is what you need (if I didn't miss anything):
SELECT p.ContractID,PaymentDate,Credit,Debit,Code,CodeName,amount,city
FROM Payments p
LEFT JOIN Info ON Info.ContractID = p.ContractID
WHERE p.ContractID NOT IN (
SELECT p2.ContractID
FROM Payments p2
WHERE p2.PaymentDate >= '20210501'
group by p2.ContractID
having sum(p2.credit - p2.debit) > 0
) or codename = 'Special Delete'
ORDER BY PaymentDate DESC;

Related

MSAccess: list last date paid and sum of all payments

There are 2 tables: TestService and TestPayment, related by ServiceID. The contents of these 2 tables are:
In all there are 3 services and 3 Fees. Each service has multiple payments associated with it; Service 1111 has 2 payments, Service 1112 has 3 payments and Service 1113 has 3 payments. Each payment has an associated DatePaid.
I want a query to show:
For each service, the sum of total payments received for that service, AND the date of the last payment made for that service
To do this I created 3 queries:
TestQPaymentByVHC#: This sums all the payments for each ServiceID
TestQLastInsPayment: This retrieves the date of the last payment for each ServiceID
TestQCPA: This should list all ServiceID’s (one record per ServiceID) with the sum of all payments received (From TestQPaymentByVHC#) and the date of the last payment received for each ServiceID (From TestQLastInsPayment)
Here is the problem:
If TestQLastInsPayment is:
SELECT TOP 1 TestPayment.ServiceID, Last(TestPayment.DatePaid) AS LastOfDatePaid, TestPayment.Amount
FROM TestPayment RIGHT JOIN TestService ON TestPayment.ServiceID = TestService.ServiceID
GROUP BY TestPayment.ServiceID, TestPayment.Amount
ORDER BY Last(TestPayment.DatePaid) DESC;
Then TestQCPA lists the date of the last payment for each ServiceID ONLY for ONE of the ServiceID’s:
If I change TestQLastInsPayment to:
SELECT TestPayment.ServiceID, Last(TestPayment.DatePaid) AS LastOfDatePaid, TestPayment.Amount
FROM TestPayment RIGHT JOIN TestService ON TestPayment.ServiceID = TestService.ServiceID
GROUP BY TestPayment.ServiceID, TestPayment.Amount
ORDER BY Last(TestPayment.DatePaid) DESC;
Then TestQCPA lists all dates of payment for each Service ID and each date a payment was received, and it duplicates records for each ServiceID such that each ServiceID is listed multiple times, one record for each date that a payment was received:
I am doing all this in the GUI and posting the SQL code.
How can I get TestQCPA to list ONLY one line per ServiceID, with the sum of all payments received for that ServiceID, but still have the DatePaid show the last date of payment for each ServiceID?
As I understand the request, the below query should provide the requested information. Max is used instead of last due to how access stores dates as seconds since 00:00:00 1/1/1900.
SELECT TestPayment.ServiceID, Max(TestPayment.DatePaid) AS MaxOfDatePaid, Sum(TestPayment.Amount) AS SumOfAmount
FROM TestPayment INNER JOIN TestService ON TestPayment.ServiceID = TestService.ServiceID
GROUP BY TestPayment.ServiceID
ORDER BY Max(TestPayment.DatePaid);
To include all the fields in your question:
SELECT svc.CPT, svc.Units, svc.Fee, svc.[Patient#], sum(pmt.amount) as [Sum of Amount Paid], max(pmt.datepaid) as [Date of Last Receipt], svc.serviceid
FROM testservice AS svc LEFT JOIN testpayment AS pmt ON svc.serviceid = pmt.serviceid
GROUP BY svc.serviceid, svc.CPT, svc.Units, svc.Fee, svc.[Patient#]
The LEFT JOIN is used because I assume that it is possible that TestService will contain a service for which no payments have yet been received and you said you want to see "for each service, the sum of total payments received for that service".
Thanks for all tips. Turns out problem was I was using LAST(DatePaid). Access does not seem to like LAST function with dates. When I changed to MAX(DatePaid) it all worked.

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.

osclass Counting number of Sales of specifed id products

I have this table item_log:
fk_i_item_id product amount currency status
$sales = $conn->osc_dbFetchResult("SELECT COUNT(status) FROM %st_item_log WHERE fk_i_item_id = '%s' AND status = 'COMPLETED'", DB_TABLE_PREFIX,osc_logged_user_id());
echo $sales['COUNT(status)']
I want to count total number of sales of an product in the same echo.
ex
***********************************************************
fk_i_item_id product amount currency status
***********************************************************
20 Book 1 10 USD COMPLETED
21 Book 2 12 USD COMPLETED
20 Book 1 10 USD COMPLETED
23 Book 3 11 USD COMPLETED
I want an query to count the number or records.
*******************************************************************
fk_i_item_id product amount currency status Sales
*******************************************************************
20 Book 1 10 USD COMPLETED 2
21 Book 2 12 USD COMPLETED 1
23 Book 3 11 USD COMPLETED 1
You already appear to know how to use aggregate functions such as count(), albeit over the entire table.
It's also possible to use these aggregate functions over groups of rows within the table. For example, to get the number of rows for each item ID, it's a simple matter of:
select item_id,
count(*)
from some_table
group by item_id
So all you really need to do is use group by to specify a finer level of grouping since, without that, it will group over all the selected rows.
With regard to your desired output, it would probably make more sense to sum the amount (so that id 20 has an amount of 20 rather than 10) though this may well be complicated by the fact you appear to allow multiple currencies.
I'm not going to tell you how to fix that other than to state that you may need to convert the amounts to a baseline currency before summing them.
So, as a first cut, I'd be looking at something like:
select fk_i_item_id,
max(product) as product,
sum(amount) as amount,
max(currency) as currency,
max(status) as status,
count(*) as sales
from st_item_log
where status = 'COMPLETED'
group by fk_i_item_id
Note the use of the "dummy" max aggregate function on the fields you're not grouping by. This is to ensure that the rows still group on the item ID even if they have different product descriptions, currencies, or status values (though the last is impossible given the where clause).

To calculate % in hive query

with the below query i can able to get the approved transaction for per client on per day basis.
select
q1.client_id,
q1.receive_day,
count(q1.client_id) as cnt
from
(select * from sale where response=00) q1
group by
q1.client_id, q1.receive_day
I want to get the approval %, i.e. the approval_per, is 100*(count(client_id)/response), while count(client_id) is the number of clients for the approved transaction.
Response is a count of whole response including all the values (approved and not approved) . I can get the response by select count(response) from sale , but how to make it here for calculating % in the same query is the problem am facing now. I tried out some options as it didn't work , reached user group.
so my expected output format is client_id,receive_day,count(client_id),approval_per.
Any of your help are really appreciated
Thanks & Regards,
dti
You could simply add another subquery which calculates that count. Also for the query you have now it seems unnecessary to have that subquery (q1).
I also make the assumption that you want your percentage should be the percentage of transactions each client is responsible for. I.e. number of transactions for given client divided by number of total transactions.
SELECT
s.client_id,
s.receive_day,
count(s.client_id) as cnt,
100 * (count(s.client_id) / q1.total)
FROM
sale s,
(select count(*) total from sale) q1
WHERE
response = 00
GROUP BY
s.client_id, s.receive_day

SQL for statement of accounts

I would like to thank in advance for any help.
My problem relates to two tables in MySQL (Now switching to postgresql). The tables are related to a ticketing database.
a) booking. It has four columns ccode,date,time,amount
b) account It has three columns ccode,date,amount
The booking table has ticket bookings and account table has advances and payments received.
I have to prepare a statement of account based on ccode (customer code).
The statement shows columns as below
*Ccode Type Date time amount balance*
- the report in sorted on ccode and then on date (account table row appears first)
- Type column displays B or A depending on record type
- Time column is present only in booking table
- Report has a running balance for each row
- At the end for a customercode, the totals of amount and balance is displayed
I have had success, so far in creating a join as below. (and after dicussion below, have been able to generate TYPE column using IF)
SELECT booking.cname, booking.bdate, booking.btime, booking.rate, booking.ID,
IF(booking.btime IS NOT NULL, "B", "A") AS type, account.cname, account.date,
account.amount, account.ID
FROM booking
LEFT JOIN account ON booking.bdate = account.date AND booking.cname=account.cname AND
booking.rate = account.amount
UNION
SELECT booking.cname, booking.bdate, booking.btime, booking.rate, booking.ID,
IF(booking.btime IS NOT NULL, "B", "A") AS type, account.cname, account.date,
account.amount, account.ID
FROM booking
RIGHT JOIN account ON booking.bdate = account.date AND booking.cname=account.cname AND
booking.rate = account.amount
It displays all the records. A report can be generated using this table.
But is there a way to display the formatted report just by SQL.
I can change the order of columns and even add or remove existing ones as long as Record type is known and a running balance is displayed against each record.
A SAMPLE REPORT ---- REPORT A
CODE DATE TYPE AMOUNT BALANCE TIME
A1 02/19/2011 A 50 50
A1 02/20/2011 B 35 15 1230
A1 02/21/2011 A 40 55
A1 02/21/2011 B 20 35 1830
optional > TOTAL Account = 90 Booking = 55 Balance = 35
A SAMPLE REPORT ---- REPORT B
CODE AMOUNT BOOKED AMOUNT PAID BALANCE
A1 50 50 0
A1 35 15 20
A1 40 55 -15
A1 20 35 -15
this is a weekly statement version of REPORT A.
the reason is i can add where and between to get only records in a given week.
and since it is a weekly report, running balance is just omitted.
It is report grouped for all entries with customercode A1 present
in booking and account tables.
thanx
Since your data is not normalized for this, you pay the price in query complexity, as shown below:
SELECT ccode, date, time, type, amount,
(SELECT SUM(amount) AS balance
FROM numbered AS n
WHERE numbered.rownum <= n.rownum AND numbered.ccode = n.ccode) AS balance
FROM (SELECT sorted.*, #rownum := #rownum + 1 AS rownum
FROM (SELECT *
FROM (SELECT ccode, date, time, 'B' AS type, amount
FROM booking
UNION
SELECT ccode, date, "0000" AS time, 'A' AS type, -amount
FROM account) AS unsorted
ORDER BY ccode, date, time, type) AS sorted) AS numbered
The idea here is that you first need to get your booking (debits) and account (credits) lined up as in the "unsorted" statement above. Then, you need to sort them by date and time as in the "sorted" statement. Next, add row numbers to the results as in the "numbered" statement. Finally, select all that data along with a sum of amounts with row number less than or equal to the current row number that matches your ccode.
In the future, please consider using a transaction table of some sort which holds all account balance changes in a single table.
I have found the answer.
It is to use cummulative sql statement to find a running balance