Loại xử lý tuần tự này có thay đổi và bù trừ là một trong những tình huống mà bước DATA SAS chiếu sáng. Không phải là câu trả lời này là đơn giản, nhưng nó là đơn giản hơn hơn bằng cách sử dụng SQL, có thể được thực hiện, nhưng không được thiết kế với quy trình xử lý tuần tự này.
Hơn nữa, các giải pháp dựa trên bước DATA có xu hướng rất hiệu quả. Điều này chạy theo thời gian O (n log n) trong lý thuyết, nhưng gần với O (n) trong thực tế, và trong không gian liên tục.
Hai bước DATA đầu tiên chỉ tải dữ liệu, được sửa đổi một chút từ câu trả lời của Joe, để có nhiều ID (nếu không cú pháp là MUCH dễ dàng hơn) và thêm một số trường hợp góc, nghĩa là ID không thể xác định trạng thái ban đầu.
data tableA;
informat start end DDMMYY10.;
format start end DATE9.;
input ID Start End A_Flag;
datalines;
1 01/01/2008 23/03/2008 1
2 23/03/2008 15/06/2008 0
2 15/06/2008 18/08/2008 1
;;;;
run;
data tableB;
informat start end DDMMYY10.;
format start end DATE9.;
input ID Start End B_Flag;
datalines;
1 19/01/2008 17/02/2008 1
2 17/02/2008 15/06/2008 0
4 15/06/2008 18/08/2008 1
;;;;
run;
Bước dữ liệu tiếp theo tìm thấy sửa đổi đầu tiên cho mỗi id và cờ và đặt giá trị ban đầu ngược lại với id và cờ.
/* Get initial state by inverting first change */
data firstA;
set tableA;
by id;
if first.id;
A_Flag = ~A_Flag;
run;
data firstB;
set tableB;
by id;
if first.id;
B_Flag = ~B_Flag;
run;
data first;
merge firstA firstB;
by id;
run;
Bước dữ liệu tiếp theo kết hợp bảng "đầu tiên" nhân tạo với hai cột còn lại, giữ trạng thái cuối cùng đã biết và loại bỏ hàng đầu tiên nhân tạo.
data tableAB (drop=lastA lastB);
set first tableA tableB;
by id start;
retain lastA lastB lastStart;
if A_flag = . and ~first.id then A_flag = lastA;
else lastA = A_flag;
if B_flag = . and ~first.id then B_flag = lastB;
else lastB = B_flag;
if ~first.id; /* drop artificial first row per id */
run;
Các bước trên thực hiện hầu hết mọi thứ. Lỗi duy nhất là ngày kết thúc sẽ sai, vì chúng được sao chép từ hàng gốc. Để khắc phục điều đó, hãy sao chép lần bắt đầu tiếp theo vào cuối mỗi hàng, trừ khi đó là hàng cuối cùng. Cách dễ nhất là sắp xếp từng id bằng cách bắt đầu ngược lại, xem lại một bản ghi, sau đó sắp xếp tăng dần ở cuối.
/* sort descending to ... */
proc sort data=tableAB;
by id descending start;
run;
/* ... copy next start to this row's "end" field if not final */
data tableAB(drop=nextStart);
set tableAB;
by id descending start;
nextStart=lag(start);
if ~first.id then end=nextStart;
run;
proc sort data=tableAB;
by id start;
run;
Tôi không thể nghĩ ra cách để thực hiện điều này chỉ với SQL chuẩn và tôi không biết SAS. Nếu tôi biết mùi vị nào, tôi sẽ có thể viết một quy trình có thể hoạt động. – pahoughton
Một số câu trả lời có giải pháp đúng và giống như một câu tôi đã sử dụng trong quá khứ: bạn cần phải xác định tất cả các ngày mà tại đó điều gì đó xảy ra và từ những xác định này trong phạm vi ngày này. Sau đó, tham gia từ tập hợp đầy đủ các phạm vi này trở lại các bảng ban đầu của bạn để xác định các thuộc tính hợp lệ cho phạm vi ngày cụ thể đó. Bạn không cần hàm LAG cho điều này, nhưng một biểu thức bảng chung (với mệnh đề) rất tiện dụng ở đây. –