<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Create a unique ID for overlapping records with a twist in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879339#M347396</link>
    <description>&lt;P&gt;&lt;BR /&gt;This is a tricky one, that I have been having issues getting the desired result.&amp;nbsp;&lt;/P&gt;&lt;P&gt;Below I have employee data where there are start dates, termination dates, 2 different review record types, and employee ids.&lt;/P&gt;&lt;P&gt;In the data below, I need to create a unique Id to match each B review with only one A review. The matching criteria are the following:&amp;nbsp;&lt;BR /&gt;1) The B review must fall on or between the A review dates (same employee as well).&lt;BR /&gt;2) When the B review matches more than one A review, then the B review must match to the A review with the latest termination date. So if it matches 2 or more A reviews, I need it to match the one with the latest&amp;nbsp;&lt;BR /&gt;termination date (see my example). This is where I'm running into problems.&amp;nbsp;&lt;BR /&gt;3) The A reviews do not always have to match a B review. What is important is that the B reviews are correctly mapped to an A review. In my example, the unmatached A reviews have a null value o the unique Id flag.&amp;nbsp;&lt;BR /&gt;4) A unique id flag to show the correct mapping of the B review back to the A review that fulfills criteria 1 and 2 above.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;data have;&lt;BR /&gt;&amp;nbsp; &amp;nbsp; input employee_id rvw_type $ s_date&amp;nbsp; :yymmdd10. t_Date :yymmdd10.;&lt;BR /&gt;format s_date yymmddd10. t_date yymmdd10.;&lt;BR /&gt;&amp;nbsp; &amp;nbsp; datalines;&lt;BR /&gt;1 A 2019-04-23 2019-04-25&lt;BR /&gt;1 A 2019-04-23 2019-04-27&lt;BR /&gt;1 A 2019-11-20 2019-11-24&lt;BR /&gt;1 A 2019-11-20 2019-11-26&lt;BR /&gt;1 B 2019-04-25 2019-04-25&lt;BR /&gt;1 B 2019-04-23 2019-04-23&lt;BR /&gt;1 B 2019-11-22 2019-11-22&lt;BR /&gt;2 A 2019-01-05 2019-01-06&lt;BR /&gt;2 A 2019-01-05 2019-01-08&lt;BR /&gt;2 B 2019-01-05 2019-01-05&lt;BR /&gt;2 B 2019-01-05 2019-01-06&lt;BR /&gt;;&lt;BR /&gt;run;&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;data want;&lt;BR /&gt;&amp;nbsp; &amp;nbsp; input _employee_id Rvw_type $ s_date&amp;nbsp; :yymmdd10. t_Date :yymmdd10. Unique_match_flag;&lt;BR /&gt;format s_date yymmddd10. t_date yymmdd10.;&lt;BR /&gt;&amp;nbsp; &amp;nbsp; datalines;&lt;BR /&gt;1 A 2019-04-23 2019-04-25 .&lt;BR /&gt;1 A 2019-04-23 2019-04-27 1&lt;BR /&gt;1 A 2019-11-20 2019-11-24 .&lt;BR /&gt;1 A 2019-11-20 2019-11-26 2&lt;BR /&gt;1 B 2019-04-25 2019-04-25 1&lt;BR /&gt;1 B 2019-04-23 2019-04-23 1&lt;BR /&gt;1 B 2019-11-22 2019-11-22 2&lt;BR /&gt;2 A 2019-01-05 2019-01-06 .&lt;BR /&gt;2 A 2019-01-05 2019-01-08 3&lt;BR /&gt;2 B 2019-01-05 2019-01-05 3&lt;BR /&gt;2 B 2019-01-05 2019-01-06 3&lt;BR /&gt;;&lt;BR /&gt;run;&lt;/P&gt;</description>
    <pubDate>Tue, 06 Jun 2023 13:59:00 GMT</pubDate>
    <dc:creator>HR_coder123</dc:creator>
    <dc:date>2023-06-06T13:59:00Z</dc:date>
    <item>
      <title>Create a unique ID for overlapping records with a twist</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879339#M347396</link>
      <description>&lt;P&gt;&lt;BR /&gt;This is a tricky one, that I have been having issues getting the desired result.&amp;nbsp;&lt;/P&gt;&lt;P&gt;Below I have employee data where there are start dates, termination dates, 2 different review record types, and employee ids.&lt;/P&gt;&lt;P&gt;In the data below, I need to create a unique Id to match each B review with only one A review. The matching criteria are the following:&amp;nbsp;&lt;BR /&gt;1) The B review must fall on or between the A review dates (same employee as well).&lt;BR /&gt;2) When the B review matches more than one A review, then the B review must match to the A review with the latest termination date. So if it matches 2 or more A reviews, I need it to match the one with the latest&amp;nbsp;&lt;BR /&gt;termination date (see my example). This is where I'm running into problems.&amp;nbsp;&lt;BR /&gt;3) The A reviews do not always have to match a B review. What is important is that the B reviews are correctly mapped to an A review. In my example, the unmatached A reviews have a null value o the unique Id flag.&amp;nbsp;&lt;BR /&gt;4) A unique id flag to show the correct mapping of the B review back to the A review that fulfills criteria 1 and 2 above.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;data have;&lt;BR /&gt;&amp;nbsp; &amp;nbsp; input employee_id rvw_type $ s_date&amp;nbsp; :yymmdd10. t_Date :yymmdd10.;&lt;BR /&gt;format s_date yymmddd10. t_date yymmdd10.;&lt;BR /&gt;&amp;nbsp; &amp;nbsp; datalines;&lt;BR /&gt;1 A 2019-04-23 2019-04-25&lt;BR /&gt;1 A 2019-04-23 2019-04-27&lt;BR /&gt;1 A 2019-11-20 2019-11-24&lt;BR /&gt;1 A 2019-11-20 2019-11-26&lt;BR /&gt;1 B 2019-04-25 2019-04-25&lt;BR /&gt;1 B 2019-04-23 2019-04-23&lt;BR /&gt;1 B 2019-11-22 2019-11-22&lt;BR /&gt;2 A 2019-01-05 2019-01-06&lt;BR /&gt;2 A 2019-01-05 2019-01-08&lt;BR /&gt;2 B 2019-01-05 2019-01-05&lt;BR /&gt;2 B 2019-01-05 2019-01-06&lt;BR /&gt;;&lt;BR /&gt;run;&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;data want;&lt;BR /&gt;&amp;nbsp; &amp;nbsp; input _employee_id Rvw_type $ s_date&amp;nbsp; :yymmdd10. t_Date :yymmdd10. Unique_match_flag;&lt;BR /&gt;format s_date yymmddd10. t_date yymmdd10.;&lt;BR /&gt;&amp;nbsp; &amp;nbsp; datalines;&lt;BR /&gt;1 A 2019-04-23 2019-04-25 .&lt;BR /&gt;1 A 2019-04-23 2019-04-27 1&lt;BR /&gt;1 A 2019-11-20 2019-11-24 .&lt;BR /&gt;1 A 2019-11-20 2019-11-26 2&lt;BR /&gt;1 B 2019-04-25 2019-04-25 1&lt;BR /&gt;1 B 2019-04-23 2019-04-23 1&lt;BR /&gt;1 B 2019-11-22 2019-11-22 2&lt;BR /&gt;2 A 2019-01-05 2019-01-06 .&lt;BR /&gt;2 A 2019-01-05 2019-01-08 3&lt;BR /&gt;2 B 2019-01-05 2019-01-05 3&lt;BR /&gt;2 B 2019-01-05 2019-01-06 3&lt;BR /&gt;;&lt;BR /&gt;run;&lt;/P&gt;</description>
      <pubDate>Tue, 06 Jun 2023 13:59:00 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879339#M347396</guid>
      <dc:creator>HR_coder123</dc:creator>
      <dc:date>2023-06-06T13:59:00Z</dc:date>
    </item>
    <item>
      <title>Re: Create a unique ID for overlapping records with a twist</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879414#M347418</link>
      <description>&lt;P&gt;I think the tricky part is the multiple rows of RVW_TYPE&lt;/P&gt;&lt;P&gt;in this example for EMPLOYEE_ID=1 there are 4 rows for RVW_TYPE="A" and 3 rows for RVW_TYPE="B".&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Which Review Type B Date are you trying to match? the Start date or Termination Date?&amp;nbsp;&lt;/P&gt;&lt;P&gt;More Importantly which row in review type B would you choose? Earliest and Latest depends on which variable so latest Start date? or latest End date?&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;You can run the below code to look at the 2 datasets you are trying to match up. In merges you usually want primary keys with no repeat rows. So think about what you are trying to match. Since the A data seems to be the master data in your example, think about how to make the B data into single row per subject.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;data ds_a ds_b;&lt;/P&gt;&lt;P&gt;&amp;nbsp;set have;&lt;/P&gt;&lt;P&gt;&amp;nbsp;if rvw_type="A" then output ds_a;&lt;/P&gt;&lt;P&gt;&amp;nbsp;if rvw_type="B" then output ds_b;&lt;/P&gt;&lt;P&gt;run;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 06 Jun 2023 17:43:33 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879414#M347418</guid>
      <dc:creator>Seadrago</dc:creator>
      <dc:date>2023-06-06T17:43:33Z</dc:date>
    </item>
    <item>
      <title>Re: Create a unique ID for overlapping records with a twist</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879433#M347423</link>
      <description>&lt;P&gt;There will be multiple B reviews that can match with a A review. However, sometimes the B reviews map to multiple A reviews. I need them to map in a specific fashion.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;What I need though is for the B reviews to match with a A review where the following occurs:&amp;nbsp;&lt;/P&gt;&lt;P&gt;#1) The B reviews start and termination date are within the start and termination date of the A review.&amp;nbsp;&lt;/P&gt;&lt;P&gt;#2) The B review is paired with the A review that has the latest termination date. There can be multiple B reviews mapping to one A review. I just need to be sure that they map to the A review with the "latest" termination date.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I think I have a roundabout solution to this. I will post if if I get it.&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 06 Jun 2023 19:28:21 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879433#M347423</guid>
      <dc:creator>HR_coder123</dc:creator>
      <dc:date>2023-06-06T19:28:21Z</dc:date>
    </item>
    <item>
      <title>Re: Create a unique ID for overlapping records with a twist</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879585#M347492</link>
      <description>&lt;P&gt;So I think you should try to fulfill the #2 requirement first.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;data ds_a ds_b;&lt;/P&gt;&lt;P&gt;&amp;nbsp;set have;&lt;/P&gt;&lt;P&gt;&amp;nbsp;if rvw_type="A" then output ds_a;&lt;/P&gt;&lt;P&gt;&amp;nbsp;if rvw_type="B" then output ds_b;&lt;/P&gt;&lt;P&gt;run;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;proc sort data=ds_a;&lt;/P&gt;&lt;P&gt;&amp;nbsp; by employee_id t_date;&lt;/P&gt;&lt;P&gt;run;&lt;/P&gt;&lt;P&gt;/*Below dataset will give you one row per ID for the latest or last termination date*/&lt;/P&gt;&lt;P&gt;data ds_a1;&lt;/P&gt;&lt;P&gt;&amp;nbsp; set ds_a;&lt;/P&gt;&lt;P&gt;&amp;nbsp; by employee_id t_date;&lt;/P&gt;&lt;P&gt;&amp;nbsp; if last.empoyee_id;&lt;/P&gt;&lt;P&gt;run;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;/* One you have dataset with single row per subject it becomes easier to merge and match*/&lt;/P&gt;&lt;P&gt;data ds_b1;&lt;/P&gt;&lt;P&gt;&amp;nbsp; set ds_b;&lt;/P&gt;&lt;P&gt;&amp;nbsp;/*rename the date variables in b for clarity*/&lt;/P&gt;&lt;P&gt;&amp;nbsp; s_date_b=s_date;&lt;/P&gt;&lt;P&gt;&amp;nbsp; t_date_b=t_date;&lt;/P&gt;&lt;P&gt;&amp;nbsp; drop s_date t_date;&lt;/P&gt;&lt;P&gt;run;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;proc sort data=ds_b1; by employee_id;&lt;/P&gt;&lt;P&gt;data match;&lt;/P&gt;&lt;P&gt;&amp;nbsp; &amp;nbsp;merge ds_a1 ds_b1;&lt;/P&gt;&lt;P&gt;&amp;nbsp; &amp;nbsp;by employee_id;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp; &amp;nbsp;/*fulfill first condition here b date need to be within time window of a date*/&lt;/P&gt;&lt;P&gt;&amp;nbsp; if s_date_b&amp;gt;=s_date and t_date_b&amp;lt;=t_date then unique_match_flag=1;&lt;/P&gt;&lt;P&gt;run;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 07 Jun 2023 15:09:09 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879585#M347492</guid>
      <dc:creator>Seadrago</dc:creator>
      <dc:date>2023-06-07T15:09:09Z</dc:date>
    </item>
    <item>
      <title>Re: Create a unique ID for overlapping records with a twist</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879610#M347501</link>
      <description>&lt;P&gt;First thing I would do is add a unique identifier to the source data just to make it easier to see if it is working.&lt;/P&gt;
&lt;P&gt;Let's call it REVIEW.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data have;
  input employee_id rvw_type $ s_date  :yymmdd10. t_Date :yymmdd10.;
  format s_date yymmddd10. t_date yymmdd10.;
  review+1;
datalines;
1 A 2019-04-23 2019-04-25
1 A 2019-04-23 2019-04-27
1 A 2019-11-20 2019-11-24
1 A 2019-11-20 2019-11-26
1 B 2019-04-25 2019-04-25
1 B 2019-04-23 2019-04-23
1 B 2019-11-22 2019-11-22
2 A 2019-01-05 2019-01-06
2 A 2019-01-05 2019-01-08
2 B 2019-01-05 2019-01-05
2 B 2019-01-05 2019-01-06
;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Then match them on whether the dates for B or are between the dates for A.&lt;/P&gt;
&lt;P&gt;Order them by your selection criteria.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc sql;
create table match as
select a.employee_id
     , a.review as a_review
     , a.s_date as a_s_date
     , a.t_Date as a_t_Date
     , b.review as b_review
     , b.s_date as b_s_date
     , b.t_Date as b_t_Date
from (select * from have where Rvw_type='A') a
inner join (select * from have where Rvw_type='B') b
on a.employee_id = b.employee_id
  and b.s_date between a.s_date and a.t_date
  and b.t_date between a.s_date and a.t_date
order by b.review,a.t_date 
;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Now you can limit it to the latest one.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data want;
 set match;
 by b_review ;
 if last.b_review ;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Result&lt;/P&gt;
&lt;PRE&gt;       employee_
Obs        id       a_review      a_s_date      a_t_Date    b_review      b_s_date      b_t_Date

 1         1            2       2019-04-23    2019-04-27        5       2019-04-25    2019-04-25
 2         1            2       2019-04-23    2019-04-27        6       2019-04-23    2019-04-23
 3         1            4       2019-11-20    2019-11-26        7       2019-11-22    2019-11-22
 4         2            9       2019-01-05    2019-01-08       10       2019-01-05    2019-01-05
 5         2            9       2019-01-05    2019-01-08       11       2019-01-05    2019-01-06
&lt;/PRE&gt;</description>
      <pubDate>Wed, 07 Jun 2023 16:28:40 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879610#M347501</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2023-06-07T16:28:40Z</dc:date>
    </item>
    <item>
      <title>Re: Create a unique ID for overlapping records with a twist</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879653#M347518</link>
      <description>&lt;P&gt;Hello&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/442299"&gt;@HR_coder123&lt;/a&gt;,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Another option is to create a sorted version of dataset HAVE (call it HAVE_S) so that the A-review observation with the&amp;nbsp;&lt;SPAN&gt;latest termination date (among the matching observations) is the first that will be found if the other criteria regarding the dates are checked in a DATA step (reading HAVE_S with a SET statement). Of course, the actual values of the unique IDs (see variable UID below) depend on the sort order.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc sort data=have out=have_s;
by employee_id rvw_type descending t_date s_date;
run;

data want(drop=_:);
if _n_=1 then do;
  dcl hash h(multidata:'y');
  h.definekey('rvw_type');
  h.definedata('rvw_type','s_date','t_date','uid');
  h.definedone();
  dcl hiter hi('h');
end;
do until(last.employee_id);
  set have_s;
  by employee_id;
  if rvw_type='A' then h.add();
  else if rvw_type='B' then do;
    _r=rvw_type;
    _s=s_date;
    _t=t_date;
    _u=.;
    h.reset_dup();
    do while(h.do_over(key:'A')=0);
      if s_date&amp;lt;=_s &amp;amp; _t&amp;lt;=t_date then do;
        if uid=. then do;
          _c+1;
          uid=_c;
          h.replacedup();
        end;
        _u=uid;
        leave;
      end;
    end;
    h.add(key:_r,data:_r,data:_s,data:_t,data:_u);
  end;
end;
do while(hi.next()=0);
  output;
end;
h.clear();
run;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Wed, 07 Jun 2023 19:35:43 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879653#M347518</guid>
      <dc:creator>FreelanceReinh</dc:creator>
      <dc:date>2023-06-07T19:35:43Z</dc:date>
    </item>
    <item>
      <title>Re: Create a unique ID for overlapping records with a twist</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879663#M347520</link>
      <description>&lt;P&gt;I ended up taking a very similar route except using 2 unique IDs for both A and B, but essentially ended up at the same place with the data step at the end as you have proposed (using the LAST statement to get rid of the duplicates from the cartesian product).&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;The other way I did this (very similar as well), was to just merge the A_termination dates directly onto the B records, and then use the LAST statement to get rid of the cartesian product, and finally create a variable that concatenated the employee Id and last termination date into one.&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Thanks again for your help everyone!&lt;/P&gt;</description>
      <pubDate>Wed, 07 Jun 2023 21:11:49 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Create-a-unique-ID-for-overlapping-records-with-a-twist/m-p/879663#M347520</guid>
      <dc:creator>HR_coder123</dc:creator>
      <dc:date>2023-06-07T21:11:49Z</dc:date>
    </item>
  </channel>
</rss>

