Select top balance per branch, only ONE per branch - sql

I have a database based on a bank, each branch having a Unique branch ID.
I am trying to create a query showing the top balance from the savings accounts at each branch. Only showing ONE row per branch ID.
I have this query which shows the top balances of savings accounts but I cannot figure out how to have this unique per branch ID.
select max(a.balance) as balance, b.bid, c.pname.firstname, c.pname.middleinitial, c.pname.lastname
from brancht b
join accountt a on b.bid=a.bid
join customeraccountt ca on ca.accnum = a.accnum
join customert c on c.custid = ca.custid
where acctype='Savings'
group by b.bid, c.pname.firstname, c.pname.middleinitial, c.pname.lastname
order by balance desc, b.bid
/
The results for this query returns this:
BALANCE BID PNAME.FIRSTNAME PNAME.MIDDLEINITIAL PNAME.LASTNAME
14050 101 Kornelia J Oconnor
13000 101 Myra D Johnson
9850 105 Lucie M Crosby
9050 105 Simon R Patrick
Another part of the query would be to also show their limit of overdraft on their current accounts (if they have one) if it's possible to have that in the same query?
Hopefully this is enough information.

Could you please try using ROW_NUMBER function as below. In the sub-query a ROW_NUMBER is assigned to each row based on balance partitioned by Branch. Row with maximum balance for a particular branch will be assigned 1 and so on ; Then you filter only those records having row_number -1 ; Each branch will have only one record (maximum balance) with ROW_NUMBER=1
select * from
(select balance, b.bid, c.pname.firstname, c.pname.middleinitial, c.pname.lastname,
row_number() over (partion by b.bid order by balance desc) as rn
from brancht b
join accountt a on b.bid=a.bid
join customeraccountt ca on ca.accnum = a.accnum
join customert c on c.custid = ca.custid
where acctype='Savings'
group by b.bid, c.pname.firstname, c.pname.middleinitial, c.pname.lastname
) where rn=1

Related

Count current job with a partition

The next code makes a join between users and payment, to get the last payment.
The query should work if the payment table did not contain duplicated rows with the same max_date as the following one.
Something to notice, is that the row is not completely duplicated, sometimes contains little changes. But we do not care if we select the 'right' one, we only need it to be one, no matter which one of those is.
user_ID | Payment | date | product | credit_card
1 300 1/1/2020 A No
1 300 1/1/2020 Null | No
1 300 1/1/2021 A Yes
1 300 1/1/2021 Null | Yes
This causes the second inner join to duplicate rows because it makes a match twice with the maxDate which is 1/1/2021
SELECT a.*, c.*
FROM users a
INNER JOIN payments c
ON a.id = c.user_ID
INNER JOIN
(
SELECT user_ID, MAX(date) maxDate
FROM payments
GROUP BY user_ID
) b ON c.user_ID = b.user_ID AND
c.date = b.maxDate
I'm looking for a way to select only the first match of the maxDate. Any clue is welcome, thank in advance for any help.
You should be using window functions for this. That would be:
SELECT u.*, p.*
FROM users u JOIN
(SELECT p.*,
ROW_NUMBER() OVER (PARTITION BY p.user_id ORDER BY p.date DESC) as seqnum
FROM payments p
) p
ON p.user_ID = u.id AND p.seqnum = 1;
This returns one row, but which row is arbitrary.
Note the use of meaningful table aliases in the query -- u for users and p for `payments. Don't use meaningless letters. They just make the query hard to read -- and to maintain.

MS ACCESS / SQL: Select maximum count per person, per variable

In MS Access, I've joined two tables, one table is a list of sales and the city they took place (Sales), and another is a table of persons and the sales their participated in (SalePersons).
When joining the two tables, you can see that the combined table details many sales per person across many cities. My goal is obtain the most-frequented city for sales per each person.
For example, Customer 1 might have 2 sales in Baltimore, 1 sale in New York, and 3 Washington; customer 2 might have 3 sales in Washington, 4 sale in Wichita, and 1 sale in New York. The table needs to have only "Washington" listed for Customer 1, and only "Wichita" listed for Customer 2. If there's a tie, I'd like to list all the tied cities.
So far, I only have the initial join working.
SELECT SalePersons.PersonID, Count(Sales.SaleNum) AS CountOfSaleNum, Sales.CITY
FROM Sales INNER JOIN SalePersons ON Sales.SaleNum = SalePersons.SaleNum
GROUP BY SalePersons.PersonID, Sales.CITY;
But, as you might guess, this join will only give me the count of sales per city, per person across all cities. I need to retrieve only the 1 most-frequented city person.
I thought I could make this a subquery and wrap all this all under a Select MAX(CountOfSaleNum) clause, but that didn't work. I still have much to learn.
Thank you in advance! I don't know what I'd do without this site sometimes.
You can use window functions:
SELECT sp.*
FROM (SELECT sp.PersonID, COUNT(*) AS CountOfSaleNum, s.CITY,
ROW_NUMBER() OVER (PARTITION BY sp.PersonID ORDER BY COUNT(*) DESC) as seqnum
FROM Sales s INNER JOIN
SalePersons sp
ON s.SaleNum = sp.SaleNum
GROUP BY sp.PersonID, s.CITY
) sp
WHERE seqnum = 1;
In MS Access, you are stuck with a more complicated query:
SELECT sp.PersonID, COUNT(*) AS CountOfSaleNum, s.CITY
FROM Sales as s INNER JOIN
SalePersons as sp
ON s.SaleNum = sp.SaleNum
GROUP BY sp.PersonID, s.CITY
HAVING s.City = (SELECT TOP 1 s2.City
FROM Sales as s2 INNER JOIN
SalePersons as sp2
ON s2.SaleNum = sp2.SaleNum
WHERE sp2.PersonID = sp.PersonId
GROUP BY sp2.PersonId, s2.City
ORDER BY COUNT(*) DESC, s2.City
);

Using an aggregate function in an in line select statement

T-SQL I am joining a services table to a payments table. I am using MAX, AVG for payments_rec'd and allowed_ amounts. I need Balance by last line number per service from the PayApp table. Sometimes payments are listed and then subtracted so the MIN balance doesn't work. I'm thinking of an inline select statement but cannot use an aggregate function inline.
SELECT DISTINCT [CDCLSVC].[RECNUM]
,[CDCLSVC].[ID]
,[CDCLSVC].[CLIENT_ID]
,[CDCLIENT].[CASE_NUM]
,[CDCLSVC].[UNIT_ID]
,[CDCLSVC].[SUB_UNIT_ID]
,[CDCLSVC].[SVC_ID]
,[CDCLSVC].[EMP_ID]
,[CDCLSVC].[BEG_DATE]
,UPPER([CAEMP].[SORT_NAME]) as Employee
,ISNULL([CDCLSVC].[EXTENDED_PRICE],0) As ExtendedPrice
,ISNULL([CDCLSVC].[BALANCE],0) As Balance
,ISNULL(MAX([CDPAYAPP].[ALLOWED_AMT]),0) AS AllowedAmount
,ISNULL(MAX([CDPAYAPP].[ADJ_AMT]),0)As AdjustedAmount
,ISNULL(SUM([CDPAYAPP].[PAY_APPLIED_AMT]),0)As PaymentApplied
,ISNULL(MAX([CDPAYAPP].[WRITE_OFF_AMT]),0)AS WriteOff
,ISNULL(MIN([CDPAYAPP].[SVC_BALANCE]),0) AS SvcBalance
,UPPER([CDPLACE].[DESC]) as Location
FROM [AnaDEV].[dbo].[CDCLSVC]
INNER JOIN [CAEMP] ON [CDCLSVC].[EMP_ID] = [CAEMP].[ID]
INNER JOIN [CDCLIENT] ON [CDCLSVC].[CLIENT_ID] = [CDCLIENT].[ID]
INNER JOIN [CDPLACE] ON [CDCLSVC].[PLACE_ID] = [CDPLACE].[ID]
INNER JOIN [CDPAYAPP] ON [CDPAYAPP].[CLSVC_ID] = [CDCLSVC].[ID]
WHERE [CDCLSVC].[BEG_DATE] between '2015-07-01' and DATEADD(DAY,-
(DATEPART(DAY, getdate())),GETDATE())
GROUP BY CDCLSVC.RECNUM,CDCLSVC.ID,CDCLSVC.CLIENT_ID,
CDCLIENT.CASE_NUM,CDCLSVC.UNIT_ID, CDCLSVC.SUB_UNIT_ID,
CDCLSVC.SVC_ID,CDCLSVC.EMP_ID, CDCLSVC.BEG_DATE, CAEMP.SORT_NAME,
CDCLSVC.EXTENDED_PRICE,CDCLSVC.BALANCE, [CDPLACE].[DESC]
ORDER BY [CDCLIENT].[CASE_NUM], [CDCLSVC].[ID]
I have a table of services(CDCLSVC) for a small medical clinic. Each service has many payments/adjustments(PAYAPP). So I have a one to many relationship. I also have a look-up table of Clinicians and another for Clients. The goal is to group the services by Clinician, then Client and have one row per service. This was easy aggregating the PAYAPP table using SUM, MIN, MAX. The problem was the Balance in the PAYAPP table was like a checkbook and I just needed the last entry.
PAYAPP
ROWNUM SVC PRICE ADJUSTMENT WRITE-OFF PAYMENTS BALANCE
1 001 $100 $25 $75
2 001 $100 $10 $65
3 001 $100 $50 $15
4 001 $100 $15 $0
EACH SERVICE MAX(PRICE) SUM(ADJUSTMENT) MAX(WRITE-OFF) SUM(PAYMENT)
The problem was getting the final BALANCE which I did by a sub query after the left outer join.
SELECT CDCLSVC.ID AS SERVICE_ID
--,CDPAYAPP.[ID] AS CDPAYAPP_ID
,CDCLSVC.[CLIENT_ID]
,CDPAYAPP.[CLSVC_ID]
,ISNULL(CDCLSVC.[EXTENDED_PRICE],0) AS EXTENTED_PRICE
,ISNULL(CDCLSVC.[BALANCE],0) AS BALANCE
,ISNULL(MAX(CDPAYAPP.[ALLOWED_AMT]),0) AS AllowedAmt
,ISNULL(MAX(CDPAYAPP.[ADJ_AMT]),0) AS AdjAmt
,ISNULL(MAX(CDPAYAPP.[WRITE_OFF_AMT]),0)AS WriteOff
,ISNULL(SUM(CDPAYAPP.[PAY_APPLIED_AMT]),0)AS AppliedAmt
,ISNULL(TBL1.SVC_BALANCE,0) AS SVC_BALANCE
,CDCLSVC.[EMP_ID]
,CDCLSVC.[PLACE_ID]
,CDCLSVC.[BEG_DATE]
,CDCLSVC.[UNIT_ID]
,CDCLSVC.[SUB_UNIT_ID]
FROM [AnaDEV].[dbo].[CDCLSVC]
LEFT OUTER JOIN CDPAYAPP
ON CDCLSVC.ID = CDPAYAPP.CLSVC_ID
LEFT OUTER JOIN
(SELECT SVC_BALANCE
,CLSVC_ID
FROM CDPAYAPP
WHERE CDPAYAPP.RECNUM IN
(SELECT MAX([RECNUM])
FROM [AnaDEV].[dbo].[CDPAYAPP]
GROUP BY CLSVC_ID)) AS TBL1
ON TBL1.CLSVC_ID = CDPAYAPP.CLSVC_ID
WHERE [CDCLSVC].[BEG_DATE] between '2015-07-01' and DATEADD(DAY,-(DATEPART(DAY, getdate())),GETDATE())
GROUP BY CDCLSVC.ID,CDCLSVC.[CLIENT_ID],CDPAYAPP.CLSVC_ID,CDCLSVC.
[EXTENDED_PRICE],CDCLSVC.[BALANCE],CDCLSVC.[EMP_ID]
,CDCLSVC.[BEG_DATE],TBL1.SVC_BALANCE, CDCLSVC.PLACE_ID
,CDCLSVC.[UNIT_ID] ,CDCLSVC.[SUB_UNIT_ID]
ORDER BY CDCLSVC.BEG_DATE DESC -- CHECKING THE WHERE CLAUSE

Select sum and inner join

I have two tables
Bills: id amount reference
Transactions: id reference amount
The following SQL query
SELECT
*,
(SELECT SUM(amount)
FROM transactions
WHERE transactions.reference = bils.reference) AS paid
FROM bills
GROUP BY id HAVING paid<amount
was meant to some rows from table Bills, adding a column paid with the sum of amount of related transactions.
However, it only works when there is at least one transaction for each bill. Otherwise, no line for a transaction-less bill is returned.
Probably, that's because I should have done an inner join!
So I try the following:
SELECT
*,
(SELECT SUM(transactions.amount)
FROM transactions
INNER JOIN bills ON transactions.reference = bills.reference) AS paid
FROM bills
GROUP BY id
HAVING paid < amount
However, this returns the same value of paid for all rows! What am I doing wrong ?
Use a left join instead of a subquery:
select b.id, b.amount, b.paid, sum(t.amount) as transactionamount
from bills b
left join transactions t on t.reference = b.reference
group by b.id, b.amount, b.paid
having b.paid < b.amount
Edit:
To compare the sum of transactions to the amount, handle the null value that you get when there are no transactions:
having isnull(sum(t.amount), 0) < b.amount
You need a RIGHT JOIN to include all bill rows.
EDIT
So the final query will be
SELECT
*,
(SELECT SUM(transactions.amount)
FROM transactions
WHERE transactions.reference = bills.reference) AS paid
FROM bills
WHERE paid < amount
I knows this thread is old, but I came here today because I encountering the same problem.
Please see another post with same question:
Sum on a left join SQL
As the answer says, use GROUP BY on the left table. This way you get all the records out from left table, and it sums the corresponding rows from right table.
Try to use this:
SELECT
*,
SUM(transactions.sum)
FROM
bills
RIGHT JOIN
transactions
ON
bills.reference = transactions.reference
WHERE
transactions.sum > 0
GROUP BY
bills.id

Selecting records in SQL that have the minimum value for that record based on another field

I have a set of data, and while the number of fields and tables it joins with is quite complex, I believe I can distill my problem down using the required fields/tables here for illustration regarding this particular problem.
I have three tables: ClientData, Sources, Prices
Here is what my current query looks like before selecting the minimum value:
select c.RecordID, c.Description, s.Source, p.Price, p.Type, p.Weight
from ClientData c
inner join Sources s ON c.RecordID = s.RecordID
inner join Prices p ON s.SourceID = p.SourceID
This produces the following result:
RecordID Description Source Price Type Weight
=============================================================
001002003 ABC Common Stock Vendor 1 104.5 Close 1
001002003 ABC Common Stock Vendor 1 103 Bid 2
001002003 ABC Common Stock Vendor 2 106 Close 1
001002003 ABC Common Stock Vendor 2 100 Unknwn 0
111222333 DEF Preferred Stk Vendor 3 80 Bid 2
111222333 DEF Preferred Stk Vendor 3 82 Mid 3
111222333 DEF Preferred Stk Vendor 2 81 Ask 4
What I am trying to do is display prices that belong to the same record which have the minimum non-zero weight for that record (so the weight must be greater than 0, but it has to be the minimum from amongst the remaining weights). So in the above example, for record 001002003 I would want to show the close prices from Vendor 1 and Vendor 2 because they both have a weight of 1 (the minimum weight for that record). But for 111222333 I would want to show just the bid price from Vendor 3 because its weight of 2 is the minimum, non-zero for that record. The result that I'm after would like like:
RecordID Description Source Price Type Weight
=============================================================
001002003 ABC Common Stock Vendor 1 104.5 Close 1
001002003 ABC Common Stock Vendor 2 106 Close 1
111222333 DEF Preferred Stk Vendor 3 80 Bid 2
Any ideas on how to achieve this?
EDIT: This is for SQL Server Compact Edition.
I was able to come up with the solution so I thought I would share it:
SELECT x.RecordID, VendorSource, VendorPrice
FROM ClientData x
INNER JOIN Sources s ON x.RecordID = s.RecordID
INNER JOIN Prices p ON s.SourceID = p.SourceID
INNER JOIN (SELECT c.RecordID, MIN(Weight) min_weight
FROM ClientData c
INNER JOIN Sources s ON c.RecordID = s.RecordID
INNER JOIN Prices p ON s.SourceID = p.SourceID
WHERE Weight != 0
GROUP BY c.RecordID) w ON x.RecordID = w.RecordID
WHERE p.Weight = w.min_weight
This allows the minimum weight to be populated on a RecordID level in the derived table, so there is 1 weight per RecordID.
For all those who gave answers, thank you; I appreciate the help and any guidance that was offered.
You can use RANK() with a Partition over RecordId with increasing weights to 'rate' each row (after excluding zero weights entirely), and then simply filter out the top ranked rows. The CTE used just to keep the second query simple + clear
;WITH MyRecords AS
(
-- Your source query goes here
select c.RecordID, c.Description, s.Source, p.Price, p.Type, p.Weight
from ClientData c
inner join Sources s ON c.RecordID = s.RecordID
inner join Prices p ON s.SourceID = p.SourceID
)
SELECT RecordID, [Description], [Source], [Price], [Type], [Weight]
FROM
(
SELECT RecordID, [Description], [Source], [Price], [Type], [Weight],
-- With ranking, the lower the weight the better
Rnk = RANK() OVER (PARTITION BY RecordId ORDER BY [Weight] ASC)
FROM MyRecords
-- But exclude Weight 0 entirely
WHERE [Weight] > 0
) RankedRecords
-- We just want the top ranked records, with ties
WHERE Rnk = 1
Edit CE constraint added after the post. See How would I duplicate the Rank function in a Sql Server Compact Edition SELECT statement? on how to simulate RANK() over in CE.
I think you need to change your structure up a little bit to actually make this work as you would like it to. Basically the way you have it a price record is set up against a Source rather than against the Item which seems to be in the ClientData table. By removing the c.Record number column from the Sources table and putting it into the Prices table you should get the correct One(ClientData) to many (Prices), and One(ClientData) to many(Sources) relationships that I think you need.
select c.RecordID, c.Description, s.Source, p.Price, p.Type, p.Weight
from ClientData c
inner join Prices p ON c.RecordID = p.RecordID
inner join Sources s ON s.SourceID = p.SourceID
AND p.Weight> 0
LEFT OUTER JOIN #Prices p2 ON c.RecordID = p2.RecordID
AND p2.PriceID <> p.priceID
AND p2.Weight > 0
AND p2.Weight < p.Weight
WHERE p2.SourceID IS NULL
If you make the change specified above then this query will returns the exact data that you are looking for.