Month Difference between rows by group in PostgreSQL - sql

I have data that looks like this using PostgreSQL
customer name order_id order_date
John A001 1-Jan-2017
John A002 1-Feb-2017
John A003 1-Apr-2017
Smith A004 1-Dec-2016
Smith A005 1-Feb-2017
Jane A006 1-Mar-2017
Dave A007 1-Feb-2017
Dave A008 1-Feb-2017
Dave A009 1-Feb-2017
I'm trying to get the difference between month of repurchases in another column. So something like this.
customer name order_id order_date month_diff
John A001 1-Jan-2017 null
John A002 1-Feb-2017 1
John A003 1-Apr-2017 2
Smith A004 1-Dec-2016 null
Smith A005 1-Feb-2017 3
Jane A006 1-Mar-2017 null
Dave A007 1-Feb-2017 null
Dave A008 1-Feb-2017 0
Dave A009 1-Feb-2017 0
Any suggestion would be greatly appreciation. I'm new to postgreSQL. Thank you in advance

This can easily be done using window functions (assuming that order_date is properly defined as DATE)
select customer_name,
order_id,
order_date,
order_date - lag(order_date) over (partition by customer_name order by order_date) as diff
from order_table
order by customer_name, order_date;
Note that the result of the diff is in days if order_date is a date.

try this:
select
t.customer,
t.order_id,
t.order_date,
(select extract(MONTH from t.order_date) - extract(MONTH from tt.order_date)
from your_table tt
where tt.order_id < t.order_id
order by tt.order_id desc limit 1
)
from your_table t
order by t.order_id

try with first_value():
select
customer_name, order_id, order_date
, order_date - first_value(order_date) over (partition by customer_name order by order_id) as month_diff
from tname;

Related

Get max value and max date from sql query

I have a table with duplicate member names but these duplicates also have more than one date and a specific ID. I want the row of the member name with the most recent date (because a member could have been called more than one time a day) and biggest CallID number.
MemberID FirstName LastName CallDate CallID
0123 Carl Jones 2019-03-01 123456
0123 Carl Jones 2020-10-12 215789
0123 Carl Jones 2020-10-12 312546
2045 Sarah Marty 2021-05-09 387945
2045 Sarah Marty 2021-08-11 398712
4025 Jane Smith 2021-10-18 754662
4025 Jane Smith 2021-11-03 761063
8282 Suzy Aaron 2019-12-12 443355
8282 Suzy Aaron 2019-12-12 443386
So the desired output from this table would be
MemberID FirstName LastName CallDate CallID
0123 Carl Jones 2020-10-12 312546
2045 Sarah Marty 2021-08-11 398712
4025 Jane Smith 2021-11-03 761063
8282 Suzy Aaron 2019-12-12 443386
The query I've tried is
SELECT DISTINCT MemberID, FirstName, LastName, MAX(CallDate) as CallDate, MAX(CallID) as CallID
FROM dbo.table
GROUP BY MemberID, FirstName, LastName, CallDate, CallID
ORDER BY LastName asc;
But I'm still getting duplicate names with all their calldates and CallID
try removing CallDate, CallID from the group by clause.
So :
SELECT MemberID, FirstName, LastName, MAX(CallDate) as CallDate, MAX(CallID) as CallID
FROM dbo.table
GROUP BY MemberID, FirstName, LastName
ORDER BY LastName asc;
Hopefully that should do it.
you can use window function:
select * from (
select * , row_number() over (partition by MemberID order by CallID desc) rn
from tablename
) t where rn = 1

How can I get the total of sales for the first month of each salesman

I use Postgresql and I have a table that looks like the one below and I want to know what is the first date of sales for each person and how much the sold that month.
Name
Date_of_Sale
Value
Mike
2019-11-13
$100
Dave
2019-11-17
$300
Charlie
2019-12-04
$150
Charlie
2019-12-19
$100
Dave
2019-11-11
$50
Mike
2019-12-01
$200
So the end result would be:
Name
First sale
Month
Total Value
Mike
2019-11-13
2019-11
$100
Dave
2019-11-11
2019-11
$350
Charlie
2019-12-04
2019-12
$250
I've used the following code but it doesn't bring back a single month.
Thanks in advance
FROM
(
select
name,
to_char(min(date_of_sale), 'YYYY-MM-dd') as first_sale_date,
concat (LPAD(extract('year' FROM date_of_sale)::text, 4, '0'), '-', LPAD(EXTRACT('month' FROM date_of_sale)::text, 2,'0') ,'-', '01') as month,
sum(value) as total_value
from
sales
group by
name,
month
) as a
group by
name, date_first_sale, total_value´´´
You can use distinct on and aggregation:
select distinct on (name) name, min(date_of_sale), sum(value)
from sales s
group by name, date_trunc('month', date_of_sale)
order by name, min(date_of_sale);
You can add date_trunc('month', date_of_sale) if you really want. The query returns the min date, so I don't see why the year/month is needed as well.
Here is a db<>fiddle.

How to rank salesman changing in the time on a contract

i'm a beginner on sql, and i hope my post will be clear.
So i have 1 table (see pictures) with my SalesMen linked to a contract.
And i want to be able to rank each SalesMen on a contract.
So if today on a contract 001 i have Martin as the only SalesMan he should have '1' as rank.
But if one day Martin is fired and the new guy is Frank. Then Martin will be rank 2 and Frank '1'.
example:
idContract idSalesMan DateLoad
001 Jean 1900-01-01
001 Jean 1900-02-02
001 Jean 1900-03-03
002 Martin 1900-01-01
002 Martin 1900-02-02
002 Frank 1900-03-03
The result i want :
idContract idSalesMan DateLoad RankedSalesMan
001 Jean 1900-01-01 1
001 Jean 1900-02-02 1
001 Jean 1900-03-03 1
002 Martin 1900-01-01 2
002 Martin 1900-02-02 2
002 Frank 1900-03-03 1
What i did:
1st try :
select idContract,IdSalesMan,
Row_number() over (partition by IDContract , IDsALESmAN order by IDsALESmAN )
But it gave me a regular 1,2,3,4
Then i tried
select
x.*
,case when x.PrecedingSalesMan = x.SalesMan then
Row_number() over (partition by IDContract , IDsALESmAN order by IDsALESmAN )
from(
select idContract,IdSalesMan,
,LAG(CodeAgent,1) over (order by NoContract, idCustomers, kCode_Agent) as PrecedingSalesMan) x
But it doesn't work neither :(
I don,t know what to do
it seems you just need dense_rank()
select *,dense_rank()over(partition by idContract order by idSalesMan) as rn
from table_name
You need DENSE_RANK() :
SELECT t.*,
DENSE_RANK() OVER (PARTITION BY t.idContract ORDER BY t.idSalesMan) AS RankedSalesMan
FROM table t;
You need only idContract in partition clause.

SQL Retrieve distinct data by latest date

I have a table as follows:
Name Customer Date Amount
Joe Aaron 2012-01-03 14:12:00.0 150
Joe Aaron 2012-02-03 14:12:00.0 150
Joe Danny 2012-03-03 14:12:00.0 150
Joe Karen 2012-07-03 14:12:00.0 150
Ronald Blake 2012-05-03 14:12:00.0 1501
I would like to query to retrieve data by specifying the Name and if there are duplicates for Customer column, the records for the latest Date is
For example, if I want to query Joe, I will get the following result:
Name Customer Date Amount
Joe Aaron 2012-02-03 14:12:00.0 150
Joe Danny 2012-03-03 14:12:00.0 150
Joe Karen 2012-07-03 14:12:00.0 150
How should I do this? Tried distinct but it doesnt work that way.
EDIT
I'm using SQL Server. Sorry I re-edit my question and this should be the correct question that I am asking.
Did you Try this?
SELECT Name, Customer, MAX(Date) as CurrentDate, Amount
FROM data
Group By Name, Customer, Amount
HAVING Name = 'Joe'
Another option is using the WITH TIES clause in concert with Row_Number()
Example
Select top 1 with ties *
From YourTable
Where Name='Joe'
Order By Row_Number() over (Partition By Customer Order By Date Desc)
Returns
Name Customer Date Amount
Joe Aaron 2012-02-03 14:12:00.000 150
Joe Danny 2012-03-03 14:12:00.000 150
Joe Karen 2012-07-03 14:12:00.000 150
One option:
SELECT * FROM Table WHERE (NAME, CUSTOMER, DATE) IN (SELECT NAME, CUSTOMER, MAX(DATE) WHERE NAME = 'Joe' GROUP BY NAME, CUSTOMER)

SQL Server: aggregate to single result

I have this query
SELECT Client.ClientNo,
Client.ContactName,
Deal.Currency,
MAX(Deal.DealDate)
FROM Deal
JOIN Client ON Deal.ClientNo = Client.ClientNo
GROUP BY Client.ClientNo, Client.ContactName, Deal.Currency;
which gives me a result
1 John Smith EUR 2014-10-07
1 John Smith GBP 2014-11-12
2 Jane Doe GBP 2014-09-17
2 Jane Doe USD 2014-12-23
1 John Smith USD 2013-11-13
2 Jane Doe EUR 2012-09-06
Problem is, I need an aggregated result with the latest date per client, like this:
1 John Smith GBP 2014-11-12
2 Jane Doe USD 2014-12-23
How can I change my query to achieve this?
UPDATE Thanks to jarlh for the answer, however I have missed something - if there is a duplicate row - it will remain in the result, looking like this:
1 John Smith GBP 2014-11-12
1 John Smith GBP 2014-11-12
2 Jane Doe USD 2014-12-23
Any way to make that work?
You could do something like this:
Test data:
DECLARE #Deal TABLE(ClientNo INT,Currency VARCHAR(10),DealDate DATETIME)
DECLARE #Client TABLE(ClientNo INT,ContactName VARCHAR(100))
INSERT INTO #Deal
VALUES (1,'EUR','2014-10-07'),(1,'GBP','2014-11-12'),(2,'GBP','2014-09-17'),
(2,'USD','2014-12-23'),(1,'USD','2013-11-13'),(2,'EUR','2012-09-06')
INSERT INTO #Client
VALUES (1,'John Smith'),(2,'Jane Doe')
Query:
;WITH latestDeals
AS
(
SELECT
ROW_NUMBER() OVER(PARTITION BY ClientNo ORDER BY DealDate DESC) AS RowNbr,
Deal.*
FROM
#Deal AS Deal
)
SELECT
client.ClientNo,
client.ContactName,
latestDeals.Currency,
latestDeals.DealDate
FROM
#Client AS client
JOIN latestDeals
ON client.ClientNo=latestDeals.ClientNo
AND latestDeals.RowNbr=1
Update:
If you want to use conventional query. You could do something like this:
SELECT
client.ClientNo,
client.ContactName,
Latestdeal.maxDealDate as DealDate,
deal.Currency
FROM
#Client AS client
JOIN
(
SELECT
MAX(Deal.DealDate) AS maxDealDate,
Deal.ClientNo
FROM
#Deal AS Deal
GROUP BY
Deal.ClientNo
) AS Latestdeal
ON client.ClientNo=Latestdeal.ClientNo
JOIN #Deal as deal
ON client.ClientNo=deal.ClientNo
AND deal.DealDate=Latestdeal.maxDealDate
This will result in the same output
Result:
1 John Smith GBP 2014-11-12 00:00:00.000
2 Jane Doe USD 2014-12-23 00:00:00.000
Untested, but should work. Will return several rows for a clieant if the client has two (or more) deals the same, latest day.
SELECT Client.ClientNo,
Client.ContactName,
Deal.Currency,
Deal.DealDate
FROM Deal
JOIN Client ON Deal.ClientNo = Client.ClientNo
WHERE Deal.DealDate = (select max(DealDate) from Deal
where ClientNo = Client.ClientNo)
Try this,
Test Data:
CREATE TABLE #YourTable
(
CLIENT_NO INT,
CONTACT_NAME VARCHAR(20),
CURRENCY VARCHAR(10),
[DEAL_DATE] DATE
)
INSERT INTO #YourTable VALUES
(1,'John Smith','EUR','2014-10-07'),
(1,'John Smith','GBP','2014-11-12'),
(2,'Jane Doe','GBP','2014-09-17'),
(2,'Jane Doe','USD','2014-12-23'),
(1,'John Smith','USD','2013-11-13'),
(2,'Jane Doe','EUR','2012-09-06')
Query:
SELECT CLIENT_NO,CONTACT_NAME,CURRENCY,[DEAL_DATE]
FROM (SELECT *,
Row_Number()
OVER (
PARTITION BY CLIENT_NO
ORDER BY [DEAL_DATE] DESC) AS RN
FROM #YourTable)A
WHERE RN = 1