How would I add an artificial termination date to the termination date column based on two different dates for the same patient id - oracle

I need to figure out a query that will compare two EFFECTIVE dates for a given patient number with different HMOs and determine which is the later date of the two and then populate a TERMINATION date field for only the older of the two effective dates with the last day of the previous month of the newer effective date of the two. This needs to be done across multiple patient, HMO, effective date combinations in a table.
SELECT * FROM tablename
The output is this:
HMO PATIENT EFFECTIVE TERMINATION
16 221135 01-APR-18
18 221135 01-OCT-17
12 251181 01-SEP-16
16 251181 01-MAR-15
12 271126 01-MAR-15
16 271126 01-DEC-16
12 291141 01-DEC-16
16 291141 01-FEB-19
12 391134 09-MAY-13
16 391134 01-APR-18
What I am trying to do via a query or queries is this:
HMO PATIENT EFFECTIVE TERMINATION
16 221235 01-APR-18
18 221235 01-OCT-17 3/31/2018
12 251381 01-SEP-16
16 251381 01-MAR-15 8/31/2016
12 2711126 01-MAR-15 11/30/2016
16 2711126 01-DEC-16
12 292241 01-DEC-16 1/31/2019
16 292241 01-FEB-19
12 391534 09-MAY-13 31-MAR-19
16 391534 01-APR-18
I've tried using a case statement but it is unsurprisingly creating four rows per patient, hmo combo and populating two of the rows with dates and leaving two blank:
SELECT DISTINCT
S.HMO
,S.PATIENT
,S.EFFECTIVE
,CASE WHEN S.EFFECTIVE > E.EFFECTIVE THEN LAST_DAY(ADD_MONTHS(S.EFFECTIVE, -1))
WHEN S.EFFECTIVE < E.EFFECTIVE THEN LAST_DAY(ADD_MONTHS(E.EFFECTIVE, -1))
ELSE NULL END AS TERMINATION
FROM tablename S INNER JOIN tablename E ON S.PATIENT=E.PATIENT
WHERE S.PATIENT =221135
Any ideas or advice would be welcome.

With sample data you posted:
SQL> select * from tablename order by patient, effective;
HMO PATIENT EFFECTIVE TERMINATIO
---------- ---------- ---------- ----------
18 221135 10/01/2017
16 221135 04/01/2018
16 251181 03/01/2015
12 251181 09/01/2016
12 271126 03/01/2015
16 271126 12/01/2016
6 rows selected.
such a MERGE might do:
SQL> merge into tablename a
2 using (select patient, max(effective) max_effective,
3 min(effective) min_effective
4 from tablename
5 group by patient
6 ) x
7 on (a.patient = x.patient)
8 when matched then update set
9 a.termination = x.max_effective - 1
10 where a.effective = x.min_effective;
3 rows merged.
Result is then
SQL> select * from tablename order by patient, effective;
HMO PATIENT EFFECTIVE TERMINATIO
---------- ---------- ---------- ----------
18 221135 10/01/2017 03/31/2018
16 221135 04/01/2018
16 251181 03/01/2015 08/31/2016
12 251181 09/01/2016
12 271126 03/01/2015 11/30/2016
16 271126 12/01/2016
6 rows selected.
SQL>

Related

Finding Max Weekly Average on a month

I am stuck on my query attempt. I have a table that lists test results with their dates. I need to run a query to return the highest weekly average for a particular month.
I have the first part figured out:
SELECT Effluent BOD5, WEEK(Date)
FROM bod
WHERE YEAR(Date) = 2020 AND MONTH (Date) = 4
ORDER BY WEEK(Date)
Returns:
Effluent BOD5 / WEEK(Date)
10 14
14 14
9 15
6 16
7 16
11 17
8 17
I need to get the result of 12 (which is the highest weekly average (week 14).
Any help would be great![enter image description here][1]
I messed around with this and figured it out! Here is what I used:
SELECT max(Total)
FROM
(SELECT week, avg(test) AS Total
From
(SELECT Effluent BOD5 test, WEEK(Date) week
FROM bod
WHERE YEAR(Date) = 2020 AND MONTH(Date) = 4
ORDER BY WEEK(Date),Effluent BOD5 desc)ab
GROUP BY week)ac

Validating decimals in a column - oracle sqldeveloper

Im trying to come up with a test that validates decimals in a particular column (with 220000 records). For example for column A there shouldn't be any values with more decimals than 2, 1 is also ok.
for example :
Column A (datatype varchar)
48528.64
135082.54
5249.1
I tried with round function but than I get an error saying invalid number.
Also I would like to be able to change the number of decimals I put in the test to use with different columns
For example
Its 1 big table with all columns having datatype VARCHAR2(2000 char)
examples for columns:
total amount (value should have no more than 2 decimals)
48528.64
135082.54
349.1123 (not OK)
Balance (value should have no more than 2 decimals)
45428.64
1895082.11
5249.1483 (not OK)
Loan (value should have no more than 6 decimals)
100.64
88999.11654
1000.178875554 (not OK)
For each column I want to set up a seperate test that checks if the value is within the number of decimals allowed. So preferable a select statement with a where clause where I can adjust the numbers of decimals so I end up with all records having 1 or 2 decimals, or all the records that have more than 2 decimals
Invalid number error is due to the fact that you have something that isn't a number in that column, so when you apply numeric function to it, Oracle complains. That's what you get when you store numbers as strings. Don't do that.
Anyway, here's one option which shows what you might try to do: as these are strings, calculate number of digits right of the decimal point.
SQL> select * From test;
A
--------------------
48528.64 -- OK
135082.54 -- OK
5249.1 -- OK
1.2345 -- not OK
-25.553 -- not OK
SQL> select *
2 from test
3 where length(regexp_substr(a, '\d+$')) > 2;
A
--------------------
1.2345
-25.553
SQL>
If there are several columns and you'd like to check each of them using a separate table which holds allowed number of decimals, then you could do something like this:
SQL> with
2 big (total, balance, loan) as
3 (select 48528.64 , 45428.64 , 100.64 from dual union all
4 select 135082.54 , 1895082.11 , 88999.11654 from dual union all
5 select 349.1123 , 5249.1483, 1000.178875554 from dual
6 ),
7 septest (tdec, bdec, ldec) as
8 (select 2, 2, 6 from dual)
9 select
10 b.total,
11 case when length(regexp_substr(b.total,'\d+$')) > s.tdec then 'Not OK'
12 else 'OK'
13 end total_ok,
14 --
15 b.balance,
16 case when length(regexp_substr(b.balance,'\d+$')) > s.bdec then 'Not OK'
17 else 'OK'
18 end balance_ok,
19 --
20 b.loan,
21 case when length(regexp_substr(b.loan,'\d+$')) > s.ldec then 'Not OK'
22 else 'OK'
23 end loan_ok
24 from big b cross join septest s;
TOTAL TOTAL_OK BALANCE BALANCE_OK LOAN LOAN_OK
---------- ---------- ---------- ---------- ---------- ----------
48528,64 OK 45428,64 OK 100,64 OK
135082,54 OK 1895082,11 OK 88999,1165 OK
349,1123 Not OK 5249,1483 Not OK 1000,17888 Not OK
SQL>
Lines #1 - 8 represent sample data; you already have that. Query you actually need begins at line #9.

Oracle Archive and Purge Options

I am trying to figure out what are the best options to perform archive and purge given our situation.
We have roughly 50 million records in say Table A. We want to archive data into a target table and then purge those data in the source table. We would like to retain the data base on several criteria that overlap with each other. For example, we want to retain the data from the past 5 months in addition to keeping all the records with say Indicator='True'. Indicator='True' will likely return records beyond 5 months. This means I have to use OR condition in order to capture the data. Base on the conditions, we would need to retain 10 million records and archive/purge 40 million records. I would need to create a process that will run every 6 months to do this.
My question is, what are the most efficient options for me to get this done for both archiving and purging? Would a PROC/bulk delete/insert be my best option?
Partition seems to be out of the question since there are several conditions that overlap with each other.
Use composite partitioning, e.g. range (for your time dimension) and list (to distinct between the rows that should be kept long and limited time.
Example
The rows with KEEP_ID='N' should be eliminated after 5 months.
CREATE TABLE tab
( id NUMBER(38,0),
trans_dt DATE,
keep_id VARCHAR2(1)
)
PARTITION BY RANGE (trans_dt) INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))
SUBPARTITION BY LIST (keep_id)
SUBPARTITION TEMPLATE
( SUBPARTITION p_catalog VALUES ('Y'),
SUBPARTITION p_internet VALUES ('N')
)
(PARTITION p_init VALUES LESS THAN (TO_DATE('01-JAN-2019','dd-MON-yyyy'))
);
Populate with sample data for 6 months
insert into tab (id, trans_dt, keep_id)
select rownum, add_months(date'2019-08-01', trunc((rownum-1) / 2)), decode(mod(rownum,2),0,'Y','N')
from dual connect by level <= 12;
select * from tab
order by trans_dt, keep_id;
ID TRANS_DT KEEP_ID
---------- ------------------- -------
1 01.08.2019 00:00:00 N --- this subpartition should be deleted
2 01.08.2019 00:00:00 Y
3 01.09.2019 00:00:00 N
4 01.09.2019 00:00:00 Y
5 01.10.2019 00:00:00 N
6 01.10.2019 00:00:00 Y
7 01.11.2019 00:00:00 N
8 01.11.2019 00:00:00 Y
9 01.12.2019 00:00:00 N
10 01.12.2019 00:00:00 Y
11 01.01.2020 00:00:00 N
12 01.01.2020 00:00:00 Y
Now use partition extended names to reference the subpartition that should be dropped.
Drop subpartition older than 5 months, but only for KEEP_ID = 'N'
alter table tab drop subpartition for (DATE'2019-08-01','N');
New data
ID TRANS_DT KEEP_ID
---------- ------------------- -------
2 01.08.2019 00:00:00 Y
3 01.09.2019 00:00:00 N
4 01.09.2019 00:00:00 Y
.....

How to count repeat values in multiples columns with a select

i have the position_table table:
CODE_POSITION NAME GRADE VALIDITY DATE ELIMINATION LEVEL
1 AAAA01 MANAGER 10 01/03/2016 31/12/2999 HIGH
2 BBBB01 ANALYST 09 01/03/2016 31/12/2999 LOW
3 CCCC01 STAFF 05 01/03/2016 31/12/2999 HIGH
4 BBBB01 ANALYST 09 01/03/2016 31/12/2999 HIGH
5 AAAA01 MANAGER 10 01/03/2016 31/12/2999 LOW
6 DDDD01 INTERN 01 01/03/2016 31/12/2999 HIGH
7 DDDD01 INTERN 01 01/07/2016 31/12/2999 LOW
I use this query to find and count the same code_position:
select code_position, count(code_position)
from position_table
group by code_position
having count(code_position) > 1;
And this is the result:
CODE_POSITION COUNT(CODE_POSITION)
1 AAAA01 2
2 BBBB01 2
3 DDDD01 2
Note:
The AAAA01 code is repeated twice and has the same date of validity and grade.
The BBBB01 code is repeated twice and has the same date of validity and grade.
The DDDD01 code is repeated twice and have different date of validity.
Now i need to check which code_position is repeated and if they have the same validity date and grade to. Like: AAAA01 and BBBB01.
You can use more then one condition in GROUP BY. If you use more conditions, all will be compared and just grouped if identically.
SELECT
code_position,
COUNT(code_position),
validity,
grade
FROM position_table
GROUP BY
code_position,
validity,
grade
HAVING COUNT(code_position) > 1

Event Study (Extracting Dates in SAS)

I need to analyse abnormal returns for an event study on mergers and acquisitions.
** I would like to analyse abnormal returns to acquirers by using event windows. Basically I would like to extract the prices for the acquirers using -1 (the day before the announcement date), announcement date, and +1 (the day after the announcement date).**
I have two different datasets to extract information from.
The first is a dataset with all the merger and acquisition information that has the information in the following format:
DealNO AcquirerNO TargetNO AnnouncementDate
123 abcd Cfgg 22/12/2010
222 qwert cddfgf 26/12/1998
In addition, I have a 2nd dataset which has all the prices.
ISINnumber Date Price
abcd 21/12/2010 10
abcd 22/12/2010 11
abcd 23/12/2010 11
abcd 24/12/2010 12
qwert 20/12/1998 20
qwert 21/12/1998 20
qwert 22/12/1998 21
qwert 23/12/1998 21
qwert 24/12/1998 21
qwert 25/12/1998 22
qwert 26/12/1998 21
qwert 27/12/1998 23
ISIN number is the same as acquirer no, and that is the matching code.
In the end I would like to have a database something like this:
DealNO AcquirerNO TargetNO AnnouncementDate Acquirerprice(-1day) Acquireeprice(0day) Acquirerprice(+1day)
123 abcd Cfgg 22/12/2010 10 11 12
222 qwert cddfgf 26/12/1998 22 21 23
Do you know how I can get this?
I'd prefer to use sas to run the code, but if you are familiar with any other programs that can get the data like this, please let me know.
Thank you in advance ^_^.
This can be done quite easily with PROC SQL and joining the PRICE dataset three times. Try this (assuming data set names of ANNOUCE and PRICE):
Warning: untested code
%let day='21DEC2010'd;
proc sql;
create table RESULT as
select a.dealno,
a.acquirerno,
a.targetno,
a.annoucementdate,
p.price as acquirerprice_prev,
c.price as acquirerprice_cur,
n.price as acquirerprice_next
from ANNOUCE a
left join (select * from PRICE where date = &day-1) p on a.acquirerno = p.isinumber
left join (select * from PRICE where date = &day) c on a.acquirerno = c.isinumber
left join (select * from PRICE where date = &day+1) n on a.acquirerno = n.isinumber
;
quit;

Resources