To find the last updated record of each month for each policy(another field) - sql

I have a table named a, and other fields as eff_date,policy no.
Now for each policy, consider all the records, and take out the last updated one (eff_date) from each month.
So I need the last updated record for each month for each policy. How would I write a query for this?

I'm not 100 percent on Teradata syntax, but I believe you're after this:
SELECT policy_no,eff_date
FROM (SELECT policy_no,eff_date, ROW_NUMBER() OVER (PARTITION BY policy no, EXTRACT(YEAR FROM eff_date),EXTRACT(MONTH FROM eff_date) ORDER BY eff_date DESC) as RowRank
FROM a) as sub
WHERE RowRank = 1
I'm assuming when you say by month you also want to differentiate by year, but if not, just remove the EXTRACT(YEAR FROM eff_date) from the PARTITION BY section.
Edit: Update for Teradata syntax.

SELECT * from a
qualify ROW_NUMBER() OVER (PARTITION BY policy no, EXTRACT(YEAR FROM eff_date),
EXTRACT(MONTH FROM eff_date) ORDER BY eff_date DESC) = 1

The main difficulty, is that the group by needs to be made both the conbination of policy_no, but also the month (extracted from the date). For example:
In Mysql
SELECT policy_no,
month(eff_date),
year(eff_date),
max(eff_date)
FROM myTable
GROUP BY policy_no,
month(eff_date),
year(eff_date);
Update
I saw derived tables are allowed in teradata. Using a join to a derived table, here is how to access the full rows:
select * from a,
(SELECT policy_no,
month(eff_date),
year(eff_date),
max(eff_date) as MaxMonthDate
FROM a
GROUP BY policy_no,
month(eff_date),
year(eff_date)
) as b
where a.policy_no = b.policy_no and
a.eff_date = b.MaxMonthDate;
http://www.sqlfiddle.com/#!2/1f728/5
Update (Using Extract)
select * from a,
(SELECT a2.policy_no,
EXTRACT(MONTH FROM a2.eff_date),
EXTRACT(YEAR FROM a2.eff_date),
max(a2.eff_date) as MaxMonthDate
FROM a as a2
GROUP BY a2.policy_no,
EXTRACT(MONTH FROM a2.eff_date),
EXTRACT(YEAR FROM a2.eff_date)
) as b
where a.policy_no = b.policy_no and
a.eff_date = b.MaxMonthDate;

I'm going to suggest looking into Windows Aggregate functions and the QUALIFY statement. I believe the following SQL will work.
SELECT Policy_No
, EXTRACT(MONTH FROM Eff_Date) AS Eff_Month_
, Eff_Date
FROM TableA
QUALIFY ROW_NUMBER() OVER (PARTITION BY Policy_No, EXTRACT(MONTH FROM Eff_Date)
ORDER BY Eff_Date DESC) = 1;

Related

MariaDB get first and last record of the month - nested query

I am using MariaDB and I have these kind of data:
I have also data for March and I am using this query to select distinct Months from the database:
select distinct(DATE_FORMAT(DT,'%m-%Y')) AS singleMonth FROM myTable
I want to be able to select FIRST and LAST record of P2 column for every month. How it is possible using the query above for getting all distinct months and also getting first record for the month and last?
Example what the query should return look-like:
You can use window functions and conditional aggregation:
select year(dt), month(dt),
min(case when seqnumn_asc = 1 then p2 end) as first_p2,
min(case when seqnumn_desc = 1 then p2 end) as last_p2
from (select t.*,
row_number() over (partition by year(dt), month(dt) order by dt asc) as seqnum_asc,
row_number() over (partition by year(dt), month(dt) order by dt desc) as seqnum_desc
from t
) t
group by year(dt), month(dt);

Filter SQL Server Records by Latest Date on Every Year

How would I filter this SQL server database so only the green records are left aka the last recorded date every year for each Customer ID field.
If you want to get the rows, not only the date values, using ROW_NUMBER() is an option (you only need to use the appropriate PARTITON BY and ORDER BY clauses):
SELECT *
FROM (
SELECT
CustomerId,
[Date],
ROW_NUMBER() OVER (PARTITION BY CustomerId, YEAR[Date] ORDER BY [Date] DESC) AS Rn
FROM YourTable
) t
WHERE Rn = 1
To check the maximum date in the year, you can write a query to get for each year the date where not exists another (in the same year), as follow:
SELECT *
FROM yourtable t1
WHERE NOT EXISTS
(SELECT 1
FROM yourtable t2
WHERE t1.customerID = t2.customerID
AND t1.date > t2.date
AND DATEPART(YEAR, t1) = DATEPART(YEAR, t2))
If you have only two columns, then you can just use aggregation:
select customer_id, max(date)
from t
group by customer_id, year(date);

Running count distinct

I am trying to see how the cumulative number of subscribers changed over time based on unique email addresses and date they were created. Below is an example of a table I am working with.
I am trying to turn it into the table below. Email 1#gmail.com was created twice and I would like to count it once. I cannot figure out how to generate the Running count distinct column.
Thanks for the help.
I would usually do this using row_number():
select date, count(*),
sum(count(*)) over (order by date),
sum(sum(case when seqnum = 1 then 1 else 0 end)) over (order by date)
from (select t.*,
row_number() over (partition by email order by date) as seqnum
from t
) t
group by date
order by date;
This is similar to the version using lag(). However, I get nervous using lag if the same email appears multiple times on the same date.
Getting the total count and cumulative count is straight forward. To get the cumulative distinct count, use lag to check if the email had a row with a previous date, and set the flag to 0 so it would be ignored during a running sum.
select distinct dt
,count(*) over(partition by dt) as day_total
,count(*) over(order by dt) as cumsum
,sum(flag) over(order by dt) as cumdist
from (select t.*
,case when lag(dt) over(partition by email order by dt) is not null then 0 else 1 end as flag
from tbl t
) t
DEMO HERE
Here is a solution that does not uses sum over, neither lag... And does produces the correct results.
Hence it could appear as simpler to read and to maintain.
select
t1.date_created,
(select count(*) from my_table where date_created = t1.date_created) emails_created,
(select count(*) from my_table where date_created <= t1.date_created) cumulative_sum,
(select count( distinct email) from my_table where date_created <= t1.date_created) running_count_distinct
from
(select distinct date_created from my_table) t1
order by 1

Select which shows just 2 last created records for each contract

I've got a temporary table where are around 2000 contract codes. Each contract has 1 installment each month, but last month were generated duplicity installment records.
I need to select just last two records for each contract which have generated 2 installments in one month.
For example:
Select * from TABLE_XY
where code = '112233' and rownum <= 2
order by creation_date desc;
This select shows what I need but just for one code.
I have temporary table (name it temporary_table) where I have stored all contracts.
I am not sure if I explained it well :) If you need more ino pls let me know
Thanks
I do not know if I understand what you want to do. If you need to extract the codes related to a contract, stored in the temporary table could make a JOIN or put a select in the IN of the code
Select * from TABLE_XY where code in
(select code from temporary_table where id_contract = ?¿) and rownum <= 2 order by creation_date desc;
This should help
select * from (
select
t.*,
count(code) over (partition by code, to_char(creation_date, 'YYYY-MM')) as cnt,
to_char(creation_date, 'YYYY-MM') as creation_month,
row_number() over (partition by code, to_char(creation_date, 'YYYY-MM') order by creation_date desc) as rnum
from table_xy t
)
where cnt > 1 and rnum < 3
You can try giving row number to code which was repeated for last month with order for that date.
select * from
(Select a.*,row_number() over(partition by code order by creation_date desc) rn from TABLE_XY a)
where rn <= 2;

sql return 1st day of each month in table

I have a sql table like so with two columns...
3/1/17 100
3/2/17 200
3/3/17 300
4/3/17 600
4/4/17 700
4/5/17 800
I am trying to run a query that returns the 1st day of each month in that above table, and grab the corresponding value.
results should be
3/1/17 100
4/3/17 600
then once I have these results... do something with each one.
any ideas how I can get started?
In standard SQL, you would use row_number():
select t.*
from (select t.*,
row_number() over (partition by extract(year from dte), extract(month from dte)
order by dte asc) as seqnum
from t
) t
where seqnum = 1;
Most databases support this functionality, but the exact functions (particularly for dates) may differ depending on the database.
An alternative (SQL Server flavour):
SELECT t.*
FROM YourTable t
JOIN (
select MIN(DateColumn) as MinimumDate
from YourTable
group by FORMAT(DateColumn,'yyyyMM')
) q on (t.DateColumn = q.MinimumDate)
ORDER BY t.DateColumn;
For the GROUP BY this will also be fine:
group by YEAR(DateColumn), MONTH(DateColumn)
or
group by DATEPART(YEAR,DateColumn), DATEPART(MONTH,DateColumn)