previous record end date update in informatica using next record start date - logic

I have a problem regarding update of end date of previous record using the next records start date. The problem is both the records coming in, in the same table load. Also there is no unique row identifier except the combination of all columns.
Example: Source Table
HICN FIRST_NAME LAST_NAME M_NAME DOB(string) START_DATE
X123 ABC DEF M ' 19600101 1/1/2013
Y456 ABC DEF M 19600101 2/2/2014
Now, (this is my business requirement, nothing I can do about it) In the target I have an extra column END DATE. This is the first load and I have to identify on the fly using a concatenated combination of First name, last name, etc etc
that the 1st and the second record are the same and if(and only if) the HICN number changes for the member I have to update the end_date of the 1st record( i.e. record with HICN X123) with the Start_Date of the 2nd record( i.e. record with HICN Y456) so my target should look like:
HICN FIRST_NAME LAST_NAME M_NAME DOB(string) START_DATE END DATE
X123 ABC DEF M ' 19600101 1/1/2013 2/2/2014
Y456 ABC DEF M 19600101 2/2/2014 12/31/1990
I have figured out how to update date cols and flag(which i did not mention above for active and inactive hicn for a member) for a second run but not sure how to do this if both the records come in the same batch. Any help would be greatly appreciated. Thanks

Try these options:
Create a column in target table like ROW_ID with VARCHAR2(100)
Create an Expression in Expression transformation with following -
MD5(Col1||''||col2||''||...etc)
'*' - is an separator to get precised output
This MD5 function will generate an 32 bit mask which we will use it in next steps
Have a Dynamic lookup on the target table
Now, every time when you receive a new row it will get added to target as well as Dynamic lookup. Hence, if you try to Match the ROW_ID field with 2nd rows calculated ROW_ID, you can easily find out the duplicate record.
MD5 is one of the best and fastest way to find dups using whole column list. DO NOT foget to create Dynamic Lookup otherwise you wont be able to find dups.
Let me know if you need further info.

Related

Inserting Row Number based on existing value in the table

I have a requirement that I need to insert row number in a table based on value already present in the table. For example, the max row_nbr record in the current table is something like this:
+----------+----------+------------+---------+
| FST_NAME | LST_NAME | STATE_CODE | ROW_NBR |
+----------+----------+------------+---------+
| John | Doe | 13 | 123 |
+----------+----------+------------+---------+
Now, I need to insert more records, with given FST_NAME and LST_NAME values. ROW_NBR needs to be generated while inserting the data into table with values auto-incrementing from 123.
I can't use a sequence, as my loading process is not the only process that inserts data into this table. And I can't use a cursor as well, as due to high volume of data the TEMP space gets filled up quickly. And I'm inserting data as given below:
insert into final_table
( fst_name,lst_name,state_code)
(select * from staging_table
where state_code=13);
Any ideas how to implement this?
It sounds like other processes are finding the current maximum row_nbr value and incrementing it as they do single-row inserts in a cursor loop.
You could do something functionally similar, either finding the maximum in advance and incrementing it (if you're already running this in a PL/SQL block):
insert into final_table (fst_name, lst_name, state_code, row_nbr)
select st.*, variable_holding_maximum + rownum
from staging_table st
where st.state_code=13;
or by querying the table as part of the query, which doesn't need PL/SQL:
insert into final_table (fst_name, lst_name, state_code, row_nbr)
select st.*, (select max(row_nbr) from final_table) + rownum
from staging_table st
where st.state_code=13;
db<>fiddle
But this isn't a good solution because it doesn't prevent clashes from different processes and sessions trying to insert at the same time; but neither would the cursor loop approach, unless it is catching unique constraint errors and re-attempting with a new value, perhaps.
It would be better to use a sequence, which would be an auto-increment column but you said you can't change the table structure; and you need to let the other processes continue to work without modification. You can still do that with a sequence and trigger approach, having the trigger always set the row_nbr value form the sequence, regardless of whether the insert statement supplied a value.
If you create a sequence that starts from the current maximum, with something like:
create sequence final_seq start with <current max + 1>
or without manually finding it:
declare
start_with pls_integer;
begin
select nvl(max(row_nbr), 0) + 1 into start_with from final_table;
execute immediate 'create sequence final_seq start with ' || start_with;
end;
/
then your trigger could just be:
create trigger final_trig
before insert on final_table
for each row
begin
:new.row_nbr := final_seq.nextval;
end;
/
Then your insert ... select statement doesn't need to supply or even think about the row_nbr value, so you can leave it as you have it now (except I'd avoid select * even in that construct, and list the staging table columns explicitly); and any existing inserts that do supply the row_nbr don't need to be modified and the value they supply will just be overwritten from the sequence.
db<>fiddle showing inserts with and withouth row_nbr specified.

Inserting Record Type

I have a source table, and a history table. They are identical, except the history table has a notes column as the last column.
The table is large, 55 columns, which I do not want to list all the columns. We do not want to use a trigger on this, but just create the history entry in the code itself.
If I simply do an INSERT INTO <history> SELECT * FROM <source> WHERE...... I will get "not enough values".
I'm hoping to do something of this nature: (Note this is just an anonymous block)
DECLARE
v_old_rec company_table%ROWTYPE;
BEGIN
SELECT * INTO v_old_rec
FROM company_table
WHERE company_id = 32789;
INSERT INTO company_table_hist
VALUES v_old_rec || ',MONTHLY UPDATE';
END;
Anything like this possible, so I do not have to list 55 columns?
Thank you.
It's quite simple actually:
INSERT INTO company_table_hist
(SELECT t.*, MONTHLY_UPD
FROM company_table t
WHERE company_id = 32789);
Of course monthly_upd must be bound somehow

convert oracle table column name to MM/DD/YYYY

I would like convert the column name to date.
for example the column name is today, i want to convert it dynamically to today's date like MM/DD/YYYY .
as of now the column name is "Today" i want it to be current date
You can't configure a column to change its name automagically. To reflect the current day or whatever else.
But, you can change the column name by using an alias when doing a query. In order to make the things the more transparent as possible, you might want to create a view. Here is an example:
-- Some table with a column named "TODAY"
CREATE TABLE T AS (SELECT LEVEL today FROM DUAL CONNECT BY LEVEL < 5);
-- Use PL/SQL to create a view on the given table
-- with a dynamic column name
DECLARE
today varchar(10) := TO_CHAR(SYSDATE,'DD/MM/YYYY');
query varchar(200) := 'CREATE OR REPLACE VIEW V'
|| ' AS SELECT today "' || today || '"'
|| ' FROM T';
BEGIN
execute immediate query;
END;
Then, to query the "table" with the right column name, you will simply need to query V instead of T:
SELECT * FROM V;
12/12/2014
1
2
3
4
If you recreate your view daily, say by calling the above PL/SQL code from a job, you will see each day a view with the current date as the column name. But, as the underlying table is left unchanged, you will still be able to query it using the canonical name today. Which is important for example if you need to perform join on that table.
That being said, I'm not sure I will push toward such a solution. Use at your own risks!
If you want the column name heading to appear as something different than what the column name is defined in the table, you simply use the as "DisplayColumnName" clause for that column:
select user_name, today as "12/12/2014" from some_table;
But you would need to programatically generate the SQL statement for that to work. What coding environment you are using would dictate how to dynamically create a select statement.

SQL Table Column that uses input from Another Column in Same Table

I want to have a column in table which calculates the value depending on the other column in the same table.
For example,
I have "Validity" Table with Columns "DateManufactured", "DateExpires"
The Date Expires column must calculate value suppose adding 30 days for Datemanufactured.
How Can we do this in Visual Studio2010->DataSet Design-> DataTable Column-> Properties->Expression
See relevant Image here
What could be the possible expression for this in terms of SQL Server Expressions?
Please Suggest optimal Solution.
Thanks in advance.
I believe you are looking for DateAdd
SELECT DATEADD(day, 30, '15 Dec 1988')
select dateadd(day,30,getdate())
this will take the current date(getdate())
add 30 days to it.
I would suggest creating a stored procedure to insert your data into your table with parameters of the values that needs to be inserted. you can then do your calculation based on your date parameter. Example:
Create Procedure InsertValidity
(
#City varchar(20),
#Area varchar(20),
...
#DatePosted datetime,
...
#UserID
)
as
declare #DurationFrom datetime
set #DurationFrom = (select DATEADD(dd,30,#DatePosted)
insert into Validity (City, Area, ..., DatePosted, ... UserID)
values(#City, #Area, ..., #DatePosted,...#DurationFrom,...#UserID)
This should solve your problem. Just complete the script by replacing the ... with your other data then execute the stored procedure in your application.

Validate person without value in date column

I have a table with several employees. They have the following columns empid,datecolumn1,is_valid.
Very few employees have a more than one record in the table. If an employee has more than one record in the table I would like to 'invalidate' one of the records on the following condition:
1. If a employee has more than one record in the table then the record with no value in the datecolumn1 is valid (update is_valid to 1) and the record with value in datecolumn1 is not valid (update is_valid to 0).
How do I accomplish this?
As Ben points out, you've stated that if datecolumn1 is NULL you want the is_valid column to be set to both 0 and 1. Assuming you fix that, you may need to adjust this CASE statement depending on which way you decide is correct.
UPDATE employees
SET is_valid = (CASE WHEN datecolumn1 IS NULL
THEN 1
ELSE 0
END)
WHERE empid IN (SELECT e.empid
FROM employees e
GROUP BY emempid
HAVING COUNT(*) > 1)
create a staging table, and fill it by a SELECT on the original table with a GROUP BY employee Id (or whatever your unique identifier is). Create a second staging table and fill it by SELECTING on the original table and excluding all rows that match rows in your grouped table. Now you have a table that contains only those people with multiple rows. From your original table, set is_valid to 0 on all rows that match employee id with the second staging table and also have no datecolumn1 (or perhaps that also have a datecolumn1 - your question as of this writing is a bit unclear.) and is_valid to 1 on the others. Once done with that, delete the staging tables, and you should have what you need.
You could also do this with a single more complicated multiselect call, but I find it helpful to use staging tables when things get complicated.

Resources