Dynamically find unpaid invoices - sql-server

How can I dynamically find un-paid invoices from tables bellow:
Invoices Table
InvoiceID, Date CustomerID, Amount
1 06/01/2022 1 5000.00
2 08/03/2022 1 4000.00
3 08/25/2022 1 3000.00
4 09/05/2022 1 4500.00
5 09/25/2022 1 4500.00
6 010/10/2022 1 2000.00
7 11/20/2022 1 2500.00
Payments Table:-
PaymentID Date CustomerID Amount
1 06/10/2022 1 3000.00
2 06/25/2022 1 4000.00
3 07/15/2022 1 2000.00
4 09/10/2022 1 3000.00
5 10/22/2022 1 4000.00
6 10/24/2022 1 1500.00
7 10/28/2022 1 1000.00
8 11/14/2022 1 500.00

Try to start with this:
SELECT I.CustomerID
, I.AmountTotal-ISNULL(P.AmountTotal,0) as AmountDiff
FROM
( SELECT CustomerID
, SUM(Amount) AmountTotal
FROM <invoices_table>
GROUP
BY CustomerID
) I
LEFT
OUTER
JOIN
( SELECT CustomerID
, SUM(Amount) AmountTotal
FROM <payments_table>
GROUP
BY CustomerID
) P
ON I.CustomerID = P.CustomerID
WHERE I.AmountTotal <= P.AmountTotal

Related

Select several fields based on duplicates and find the max value of a column

I'm using SQL Server 2016 and I'm having an issue grouping by more than one col and finding an average while omitting duplicate rows. I have a transaction table defined as:
CREATE TABLE [dbo].[CUST_TRANSACTION]
(
[EXTRACT_DATE] [date] NULL,
[CUSTOMER_ID] [bigint] NULL,
[TRANS_NUMBER] [bigint] NULL,
[CATEGORY] [smallint] NULL,
[RANKING] [smallint] NULL
)
Some sample data:
EXTRACT_DATE CUSTOMER_ID TRANS_NUMBER CATEGORY RANKING
---------------------------------------------------------------
2017-10-31 10001 1000101 4 100
2017-10-31 10001 1000102 4 100
2017-10-31 10001 1000105 4 0
2017-10-31 10001 1000106 4 0
2017-10-31 10002 1000201 4 200
2017-10-31 10001 1000103 5 100
2017-10-31 10001 1000107 5 0
2017-10-31 10003 1000301 5 300
2017-10-31 10003 1000302 5 300
2017-10-31 10004 1000401 7 500
2017-11-30 10004 1000403 7 300
2017-10-31 10001 1000104 8 100
2017-10-31 10004 1000402 8 0
2017-10-31 10003 1000303 8 300
The request is to find all the customer_id's that are within a given EXTRACT_DATE and with a RANKING > 1 that exist in more than one CATEGORY. Then find the CUSTOMER_ID and the highest CATEGORY that CUSTOMER_ID EXISTS in and finally the number of CATEGORIES the CUSTOMER_ID EXISTS IN
The output should only contain the following two rows:
10001 8 3
10003 8 2
CUSTOMER_ID 10001 is in CATEGORY's (4, 5 & 8)
CUSTOMER_ID 10003 is in CATEGORY's (5 & 8)
Here is the SQL I have so far:
SELECT
MAX(CATEGORY), CUSTOMER_ID,
COUNT(CUSTOMER_ID) "Customer_id count"
FROM
CUST_TRANSACTION
WHERE
EXTRACT_DATE = CONVERT(datetime, '2017-10-31')
AND ranking > 1
GROUP BY
CUSTOMER_ID, CATEGORY
HAVING
COUNT(CUSTOMER_ID) > 1
Output:
CATEGORY CUSTOMER_ID Customer_id count
----------------------------------------
4 10001 2
5 10003 2
I'm getting the correct CUSTOMER_ID's, but not the MAX CATEGORY or correct count of the number CATEGORIES the CUSTOMER_ID EXISTS in. Any suggestions would be great.
Thanks
Try with script
select MAX(CATEGORY), CUSTOMER_ID, count(CUSTOMER_ID) "Customer_id count"
from
(select distinct CUSTOMER_ID, CATEGORY
from CUST_TRANSACTION
where EXTRACT_DATE = Convert(datetime, '2017-10-31' )
and ranking > 1
)
group by CUSTOMER_ID
having count(CUSTOMER_ID) > 1

Need select 2 rows from Table2, which is joined with Table1. See description

For example i have a Table1:
ID Specified TIN Value DateCreated
----------------------------------
1 0 tin1 45 2014-12-30
2 1 tin2 34 2013-01-05
3 0 tin3 23 2015-02-20
4 3 tin4 47 2013-06-04
5 3 tin5 12 2012-04-02
And a Table2:
ID Table1ID RegistrationDate
----------------------------------
1 1 2015-10-12
2 2 2015-07-21
3 1 2015-11-26
4 1 2015-12-04
5 2 2015-09-18
I need select all columns from Table1 with first and last RegistrationDate column in Table2. The answer should be
ID Specified TIN Value DateCreated FirstRegDate LastRegDate
---------------------------------------------------------------
1 0 tin1 45 2014-12-30 2015-10-12 2015-12-04
2 1 tin2 34 2013-01-05 2015-07-21 2015-09-18
3 0 tin3 23 2015-02-20 NULL NULL
4 3 tin4 47 2013-06-04 NULL NULL
5 3 tin5 12 2012-04-02 NULL NULL
Hi one possible solution can be something similar to pseudo query below(if you can prepare the tables I will modify to reflect actual query)
SELECT table1.*, inlineTable2.firstRegDate, inlineTable2.lastRegDate
FROM Table1
LEFT JOIN
(
SELECT
Table1ID AS id,
MIN(registrationDate) as firstRegDate,
MAX(regsitrationDate) as lastRegDate
FROM table2
GROUP BY table1ID
) AS inlineTable2
ON table1.id = inlineTable2.id
You can group by all columns in table1, and look up the minumum and maximum registration date for the group:
select ID
, Specified
, ... other columns from table1 ...
, min(RegistrationDate)
, max(RegistrationDate)
from Table1 t1
left join
Table2 t2
on t1.ID = t2.Table1ID
group by
ID
, Specified
, ... other columns from table1 ...

unable to make group clause in sql server

I want to display the details of all managers and their respective employees.
I have one table "Employee" column (EmployeeID), and another column (ManagerID) which is foreign key to employeeID
Sample data:
select * from tbl_employee:
EmployeeID Name Salary ManagerID DepartmentID HireDate
1 krishna 21000.00 4 1 2014-12-01 00:00:00.000
2 sanjay 31000.00 2 3 2014-12-02 00:00:00.000
3 Raju 12000.00 4 5 2014-12-03 00:00:00.000
4 kumar 27000.00 4 5 2014-12-04 00:00:00.000
5 renuka 55000.00 4 5 2014-12-05 00:00:00.000
6 prash 22000.00 6 1 2014-12-06 00:00:00.000
7 bhaskar 33000.00 4 3 2014-12-07 00:00:00.000
I need like this
Manager_Name Employee_Name salary ManagerID Department HireDate
kumar krishna 21000.00 4 1 2014-12-01
kumar Raju 12000.00 4 5 2014-12-03
I tried this:
select managerid,name as manager_name from Employee group by ManagerID,name:
managerid manager_name
2 sanjay
4 bhaskar
4 krishna
4 kumar
4 Raju
4 renuka
6 prashant
Maybe like this?
SELECT m.Name as Manager_Name, e.Name as Employee_Name, e.Salary, e.ManagerID, e.Department, e.HireDate
FROM tbl_employee e INNER JOIN tbl_employee m on e.managerId = m.EmployeeID ORDER BY 1

Selecting correct price given purchase date and effective price dates

I need a query to find the price of an item at the time of its purchase; the prices change over time.
I have two tables linked by a foreign key:
table Albums:
ID Name PurchaseDate
1 Album1 2014-05-14
2 Album2 2014-05-14
3 Album3 2014-05-14
and
table Prices:
ID AlbumID Price EffDate
1 1 5.00 2014-01-01
2 2 5.00 2014-01-01
3 3 5.00 2014-01-01
4 3 60.00 2014-04-25
5 3 700.00 2014-12-12
When I join the tables with this query:
select a.ID, a.Name, a.PurchaseDate, p.Price, p.EffDate
from Albums a
inner join Prices p
on a.ID=p.AlbumID;
I get the following result:
ID Name PurchaseDate Price EffDate
1 Album1 2014-05-14 5.00 2014-01-01
2 Album2 2014-05-14 5.00 2014-01-01
3 Album3 2014-05-14 5.00 2014-01-01
3 Album3 2014-05-14 60.00 2014-04-25
3 Album3 2014-05-14 700.00 2014-12-12
The problem is the multiple results for Album3. It's easy to get rid of the record with the EffDate in the future:
select a.ID, a.Name, a.PurchaseDate, p.Price, p.EffDate
from Albums a
inner join Prices p
on a.ID=p.AlbumID
where p.EffDate <= a.PurchaseDate;
Which gives the following result:
ID Name PurchaseDate Price EffDate
1 Album1 2014-05-14 5.00 2014-01-01
2 Album2 2014-05-14 5.00 2014-01-01
3 Album3 2014-05-14 5.00 2014-01-01
3 Album3 2014-05-14 60.00 2014-04-25
But I need to select only one record for each Album, i.e. the one with the most current EffDate given the PurchaseDates of 2014-05-14 (namely 60.00 on 2014-04-25 for Album3).
I thought to myself, "that should be easy!" But I just can't figure it out! I've tried DISTINCT, aggregates with MAX(EffDate), common table expressions, ROW_NUMBER () with PARTITION BY and ORDER BY clauses, FIRST_VALUE (Price) OVER ( ... ), and combinations of all these, and I'm still stumped! (And probably also just plain-old-dumb!) Here are two of my many failed attempts:
Attempt A:
WITH cte AS
(
select a.ID, a.Name, a.PurchaseDate, p.Price, p.EffDate
from Albums a
inner join Prices p
on a.ID=p.AlbumID
where p.EffDate <= a.PurchaseDate
)
select ID, Name, PurchaseDate, Price, MaxED = (select max(EffDate) from cte)
from cte;
---This query and other similar variants gives the exact same results as the previous listing!!!! The aggregate function max(EffDate) apparently has no effect on CTE results?!
Attempt B:
select a.ID, a.Name, a.PurchaseDate, p.Price, p.EffDate, pseq
from Albums a
inner join
(select p.*, row_number() over (partition by AlbumID order by EffDate) as pseq
from Prices p) p
on a.ID=p.AlbumID
where p.EffDate <= a.PurchaseDate;
---This query also gives the exact same result as above (except for the extra column 'pseq')!
Solutions in other similar posts such as here have not worked with my situation.
Sorry for the long post, but I thought it important to set the example and my requirements clearly, along with some of my failures. Please Help!
P.S.: I'm using MS SQLEXPRESS 2014 and SSMS. And yes, my actual tables and queries are a lot more complex than this example, but the example presents my underlying problem as succinctly as possible.
Maybe something like this would give you the actual price:
select
a.ID,
a.Name,
a.PurchaseDate,
(select top 1 p.Price from Prices p where p.AlbumId = a.Id and p.EffDate <= a.PurchaseDate order by p.EffDate desc) as 'Price'
from Albums a
Output:
ID Name PurchaseDate Price
----------- -------------------- ----------------------- ---------------------------------------
1 Album1 2014-05-14 00:00:00.000 5.00
2 Album2 2014-05-14 00:00:00.000 5.00
3 Album3 2014-05-14 00:00:00.000 60.00
Or if you need an actual join against Prices to get other columns you can do:
select
*
from Albums a
left join Prices p on
(
a.ID = p.AlbumID and
p.ID = (select top 1 pp.Id from Prices pp where pp.AlbumId = a.Id and pp.EffDate <= a.PurchaseDate order by pp.EffDate desc)
)
And get this output:
ID Name PurchaseDate ID AlbumID Price EffDate
----------- -------------------- ----------------------- ----------- ----------- --------------------------------------- -----------------------
1 Album1 2014-05-14 00:00:00.000 1 1 5.00 2014-01-01 00:00:00.000
2 Album2 2014-05-14 00:00:00.000 2 2 5.00 2014-01-01 00:00:00.000
3 Album3 2014-05-14 00:00:00.000 4 3 60.00 2014-04-25 00:00:00.000

How to get TOP (1) row within each Group in sql server 2000

I have some following set of data from where I want to select Top 1 row for each PK_PatientId based on the current order
PK_PatientId PK_PatientVisitId PK_VisitProcedureId DateSort
------------ ----------------- ------------------- -----------------------
1 4 4 2009-06-22 00:00:00.000
1 3 3 2009-06-22 00:00:00.000
1 2 2 2010-03-11 00:00:00.000
1 1 1 2010-03-11 00:00:00.000
5 6 6 2009-05-24 00:00:00.000
5 5 5 2009-11-07 00:00:00.000
7 7 7 2009-05-24 00:00:00.000
8 8 8 2009-05-24 00:00:00.000
9 9 9 2009-05-24 00:00:00.000
10 10 10 2009-05-24 00:00:00.000
Query that lead me to this result is
SELECT
P.PK_PatientId
, PV.PK_PatientVisitId
, MAX(TVP.PK_VisitProcedureId) AS PK_VisitProcedureId
, MAX(PV.LastUpdated) AS DateSort
--, Row_Number() OVER (Partition BY PK_PatientId ORDER BY PV.PK_PatientVisitId DESC) AS RowNo
FROM
dbo.M_Patient AS P
INNER JOIN
dbo.M_PatientVisit AS PV
ON
P.PK_PatientId = PV.FK_PatientId
INNER JOIN
dbo.TX_VisitProcedure AS TVP
ON
PV.PK_PatientVisitId = TVP.FK_PatientVisitId
WHERE
(P.IsActive = 1)
AND
(PV.IsActive = 1)
AND
(TVP.IsActive = 1)
GROUP BY
PK_PatientId
, PK_PatientVisitId
ORDER BY
PK_PatientId
, PK_PatientVisitId DESC
and I have to get the remaining functionality that I was doing with Row Number function by taking RowNo=1. But Now I have to take this procedure to SQL 2000 due to which this function can't be used.
Desired Result is
PK_PatientId PK_PatientVisitId PK_VisitProcedureId DateSort RowNo
------------ ----------------- ------------------- ----------------------- --------------------
1 4 4 2009-06-22 00:00:00.000 1
5 6 6 2009-05-24 00:00:00.000 1
7 7 7 2009-05-24 00:00:00.000 1
8 8 8 2009-05-24 00:00:00.000 1
9 9 9 2009-05-24 00:00:00.000 1
which I am getting when using Row_Number in sql 2005. I want same result using sql 2000 only.
I have to use SQL 2000
You just need to strap this to the end of your WHERE clause:
AND NOT EXISTS (
SELECT *
FROM dbo.M_PatientVisit PV2
WHERE P.PK_PatientId = PV2.FK_PatientId
AND PV2.PK_PatientVisitId > PV.PK_PatientVisitId
)
...which will result in the query returning "the patient visits for patients where there does not exist another visit for that patient with a higher ID" - that is, you'll get the visits with the highest IDs.
Note that you'll need to include the other logic in the WHERE clause in this subquery in order to ensure that the bits are active etc.
Would you mind use temporary table in your procedure? I mean that you can insert max(PatientVisitId) rows into a temporary table.

Resources