Teradata SQL MAX function and duplicate rows - sql

My original report returns 3 records for account ABC, 1 with an approved status and 2 with a suspended status. The only difference in these lines is the status and billing number. All other data is identical.
I'm trying to create a variation of this report that would return 1 line for Account ABC with a column that displays the count for approved accounts and another column with the count for suspended accounts.
In the new report, there would be an Approved Accounts column with a value of 1 and a Suspended Accounts column with a value of 2.
I'm using a MAX function to return only 1 line. The issue I'm having is that 2 records with the suspended status are identical except for the Billing Number.
If I remove the billing number from the SQL then the results only return 1 suspended and 1 approved account. I need the SQL to return 1 line with 1 in the approved column and 2 in the suspended column
Here is some sample data:
Acct# Bill# Name Location Status
ABC Bill1 ABC Co 123456 Approved
ABC Bill2 ABC Co 123456 Suspended
ABC Bill3 ABC Co 123456 Suspended
Any suggestions would be greatly appreciated. Thanks for your help.....

You need "conditional aggregation":
select Acct#, Name, Location,
sum(case when Status = 'Approved' then 1 else 0 end) as Approved,
sum(case when Status = 'Suspended' then 1 else 0 end) as Suspended
from ...
group by 1,2,3

Related

Select only one row when a certain condition is met?

ID
NAME
DATE
STATUS
1
Joe
01-22
Approved
1
Joe
01-22
Pending
2
Bill
02-22
Approved
2
Bill
02-22
Sent back
3
John
01-22
Approved
4
Bob
02-22
Pending
How do I only return one row per ID, placing priority on approved?
Example: for Id 1 I only want the row that is approved and not the one that is pending.
Some Id's may only have 1 record for example ID 4 has just one record and is pending.
What I want is:
IF status = approved and pending for the same Id then keep the approved record and not select the pending record
If status = pending then keep that record
This will preferentially select Approved, then Pending, then everything else. If you don't want "everything else" just filter in the WHERE clause.
select id,
name,
date,
status
from (
select *,
row_number() over
( partition by id
order by case when status = 'Approved' then 1
when status = 'Pending' then 2
else 3
end asc,
date
) as first_by_date_with_approved_precedence
from your_table
) tmp
where first_by_date_with_approved_precedence = 1
It could also be as easy as the following (provided status is not blank or null)
Select Top 1 with ties *
from YourTable
order by row_number() over (partition by id order by Status)
Results
ID NAME DATE STATUS
1 Joe 01-22 Approved
2 Bill 02-22 Approved
3 John 01-22 Approved
4 Bob 02-22 Pending

Simple nested query on the same table

So this is my table set up of 100k rows. I have around 30k rows which have the wrong dealer associated to it even though it refers to the same person but just a different bank designation. This happened due to a failure to port information accurately from a previous version of the database .
Table CustomerName
Name Bank Dealer SSN
John 1 ABC unique1
Mike 1 DEF unique2
Mike 2 wrong unique2
Mark 1 XYZ unique3
Mark 2 wrong unique3
Desired Table set up
Table CustomerName
Name Bank Dealer SSN
John 1 ABC unique1
Mike 1 DEF unique2
Mike 2 DEF unique2
Mark 1 XYZ unique3
Mark 2 XYZ unique3
I want to write a query which will target the rows (Bank 2 rows essentially) and change it to Bank 1 Dealer values. Is there a way to do it ? I'm using T-SQL ( SSMS 2016 )
EDIT :
SSN are like primary keys for the customer. every customer will have one ssn . the bank 2 is basically a delinquent account bank. A customer may or may not have a bank 2 account , but they'll have a bank 1 account. But my problem is that somehow the dealer didn't come through right for bank 2 and I need to update to the correct value
The question is which Dealer to use. Let me guess that it is the first one. You can use CTE and update to accomplish this:
with topudate as (
select cn.*,
max(case when bank = 1 then dealer end) over (partition by ssn) as dealer1
from customername cn
)
update toupdate
set dealer = dealer1
where dealer <> dealer1 or dealer is null;
If you have some other logic for getting the right name, then that would go in the case expression instead.
update bank2
set bank2.dealer = bank1.dealer
from CustomerName bank1
join CustomerName bank2
on bank2.SSN = bank1.SSN
and bank2.Bank = 2
and bank1.Bank = 1

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.

Record has multiple statuses that gets rechecked. Only want records that meet a certain criteria

I have a table like below
Account number | Last Name | Status | date
111 doe acknowledged 04-11-2013
111 doe acknowledged 05-01-2013
111 doe paid 05-10-2013
123 smith acknowledged 05-15-2013
123 smith acknowledged 05-22-2013
145 walter paid 05-23-2013
There are names and account numbers that holder the same information but just have different statuses and dates.
I am trying to get the most recent date and compare it to the current date. So for today I would compare doe with 5-10, smith with 5-22 and walter with 5-23...
Now an account can get rechecked multiple times and it will only stop getting rechecked once it has been paid. So smith would be the only one to get recheck at a later date.
I am wanting to find all of the records that have an acknowledged status. I do not want any of these to be paid.
So far in my code I able to get the max date for a record, but it brings back the acknowledged and the paid record since they are both distinct. I only want records that have not been paid and that are still acknowledged.
You seem to want the most recent acknowledged status for accounts that are not paid. Here is a query for that:
select AccountNumber, Name,
max(date)
from t
group by AccountNumber, Name
having sum(case when status = 'Paid' then 1 else 0 end) = 0
You only have the two different statuses in your question. If you had more and you wanted just the acknowledged max date, then you would do:
select AccountNumber, Name,
max(case when status = 'Acknowledged' then date end)
from t
group by AccountNumber, Name
having sum(case when status = 'Paid' then 1 else 0 end) = 0
To get the most recent status, you can use row_number() to enumerate the rows:
select AccountNumber, Name,
max(case when status = 'Acknowledged' then date end),
max(case when seqnum = 1 then status end) as MostRecentStatus
from (select t.*,
row_number() over (partition by AccountNumber, Name order by date desc) as seqnum
from t
) t
group by AccountNumber, Name
having sum(case when status = 'Paid' then 1 else 0 end) = 0

sql query to link two tables

I have a table called users where the employee data are stored.
Also I have another table payment_details where employee's payment related data are stored
the two tables are as follows.
this table is users
sr_no emp_no username payment
1 1001 leroy <null>
2 1003 harry <null>
3 1004 Tom <null>
4 1008 Jon <null>
This table below is payment_details
sr_no name number month status date
43 Jon 1008 January paid 5/16/2012
44 Jon 1008 January balance 5/16/2012
45 Harry 1003 January paid 5/16/2012
46 Tom 1004 January paid 5/16/2012
47 leroy 1001 January paid 5/16/2012
48 Jon 1008 January paid 5/16/2012
49 Harry 1003 January paid 5/16/2012
50 Jon 1008 February balance 5/16/2012
51 leroy 1001 February paid 5/16/2012
52 Jon 1008 February paid 5/16/2012
53 Tom 1004 February balance 5/16/2012
My question here is to update "users" table payment column to "paid" when the status of his/her is all paid in payment_details table
You can either do this: http://www.sqlfiddle.com/#!3/db13f/18
update users set payment = 'paid'
from
(
select number
from payment_details
group by number
having sum(case when status = 'paid' then 1 end)
= count(*)
) as x
where x.number = users.emp_no;
Or this: http://www.sqlfiddle.com/#!3/db13f/19
update users
set payment = x.upd
from
(
select u.emp_no,
case when sum(case when d.status = 'paid' then 1 end) = count(*) then
'paid'
else
null
end as upd
from users u
left join payment_details d
on d.number = u.emp_no
group by u.emp_no
) as x
where x.emp_no = users.emp_no;
Their difference is how many rows it updates. On the second query, it updates all users, regardless if the user has a paid all status('paid') or not(null); on the first query, it updates only those who are paid.
The advantage of the second query, is when you change one of the all 'paid' status on payment_detail of a given user to 'not paid' for example, it can revert back the user's payment status to null
UPDATE order_details
SET payment= 'paid'
WHERE not EXISTS (SELECT 1
FROM payment_details
WHERE payment_details.emp_no= order_details.emp_no
AND payment_details.status <> 'paid'
)
There also simple way to get the value of particulars table into variable and update the tabe as below:
declare #bb varchar(50)
select #bb= status from payment_details where name=#name and id=#id
update uuser set payment = #bb
where name = #name and id=#id