Database Modeling:Find how the data looks like in the give date and time - oracle

if i have table1, table2, table3..table50 that stores different information about a product
what would be the efficient way to keeping track of incremental changes in a way that if i want to go back and pull how that particular product looked in a give date, it would be very fast and accurate.
i would want to track changes in a way that it can be retrieved very fast and also reduce too many redundancy.

1.If you are on Oracle 11g, Oracle Flashback technology is the feature that lets you do this.
http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28424/adfns_flashback.htm#BJFGJHCJ.
2.In older versions, you can use the DBMS_WM package and enable versioning for the tables that you need. However, there are certain restrictions on the kinds of tables you can enable versioning for.
http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96628/long_ref.htm#80312
3.The other implementations I have seen so far have their own version of some procedures of DBMS_WM. Basically, have a structure like..
SQL> desc scott_emp;
Name Null? Type
----------------------------------------- -------- -------------
EMPNO NOT NULL NUMBER(4)
ENAME NOT NULL VARCHAR2(10)
JOB NOT NULL VARCHAR2(9)
MGR NUMBER(4)
HIREDATE NOT NULL DATE
SAL NOT NULL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NOT NULL NUMBER(2)
EFF_DATE DATE
END_DATE DATE
Where the final two columns are used to see for what time period a record was "logically active" in the Database. The implementation is done using triggers where
Each Insert/Update is Converted to
"Expire the Current Row(update)+
Insert a New Row"
Each Delete is
Converted to "Expire the Current
row"
The last approach might solve your purpose if you only want to track changes to some columns (eg. Let's say only dept and salary changes are all you care about).
Please do not choose a model like this. (Do not Store each column change as a separate row)
http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:1769392200346820632

Related

Maintain dependency between two tables while executing triggers in oracle

How we can maintain dependency between two tables while executing triggers in oracle??
As we know we can use follows clause if we have single table and multiple triggers based on that table but my concern is that is there any way if we have 2 different tables and there are different triggers based on these table so how can we maintain some proper sequence in this case.
For example:
--Table1:
CREATE TABLE emp(
empId number PRIMARY KEY,
FirstName varchar2(20),
LastName varchar2(20),
Email varchar2(25),
PhoneNo varchar2(25),
Salary number(8)
);
--Table 2:
CREATE TABLE emp_1(
empId number PRIMARY KEY,
FirstName varchar2(20),
LastName varchar2(20),
Email varchar2(25),
PhoneNo varchar2(25),
Salary number(8)
);
Trigger on EMP:
CREATE OR replace TRIGGER TRIGGER_emp
BEFORE INSERT OR AFTER UPDATE ON emp
FOR EACH ROW
BEGIN
dbms_output.put_line ('MY EXECUTE ORDER FOR EMP IS SECOND -EXECUTED');
END;
/
Trigger on EMP1:
CREATE OR replace TRIGGER TRIGGER_emp1
BEFOR INSERT OR AFTER UPDATE ON emp_1
FOR EACH ROW
BEGIN
dbms_output.put_line ('MY EXECUTE ORDER FOR EMP IS FIRST -EXECUTED');
END;
/
Now i want this trigger TRIGGER_emp1 will execute first and then this trigger will execute TRIGGER_emp last. Is it possible to do so in oracle
Please guide me in this.
You seem to be a clone of user who recently posted two questions regarding the same subject. It was said that you can't do that. Triggers "belong" to a single table, which means that
you insert (or update) values in emp table, which then
fires trigger trigger_emp which does something
in your case, it just displays a message (you might, or might not see; that depends on a tool you use)
as nothing happened to table emp1, trigger trigger_emp1 won't fire - why would it?
if you want it to fire, then let the first trigger (trigger_emp) affect rows in emp1 table (insert a row or update existing values)
once you do that, trigger_emp1 will do whatever it does
Maybe, just maybe you should consider creating a stored procedure which contains code that works with rows in both emp and emp1 table. Then, instead of relying on triggers and worry whether they will fire, when will they fire and in which sequence, your main transaction would actually call the procedure which would then do the job (and affect rows in emp and emp1, in any order you want - that's easy to do as you'd just rearrange statements within the procedure).

Pseudorecord best practice when trigger fires but value should never change

Consider the following tables and trigger, is there a need to specify :new.employee_id in the insert statement or is this generally considered best practice. The trigger will only fire on the salary column of the table and the employee_id should not be affected. Is the :new.employee_id syntax just good practice when creating triggers or unnecessary? Could there be a potential issue if this is not added?
Link to Oracle HR SCHEMA employees table
Employees Table HR Schema
CREATE TABLE salary_log (
whodidit VARCHAR2(25), whendidit timestamp,
oldsalary NUMBER,
newsalary NUMBER,
emp_affected NUMBER);
CREATE OR REPLACE TRIGGER saltrig
AFTER INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
INSERT INTO salary_log
VALUES(user,sysdate, :old.salary, :new.salary, :new.employee_id);
END;
If you were to NOT include it:
You would have to alter your trigger code to explicitly name the columns you are supplying values for, and
Your log table would show that someone's salary changed, who did it and what the old and new values are, but you would not know whose salary was changed. The data in that column would be null.
Is the :new.employee_id syntax just good practice when creating triggers or unnecessary?
If you want this value in your log table, then it is required.

Is it possible to use SYSDATE as a column alias?

If I want to run a report daily and store the report's date as one of the column headers. Is this possible?
Example output (Counting the activities of employees for that day):
SELECT EMPLOYEE_NAME AS EMPLOYEE, COUNT(ACTIVITY) AS "Activity_On_SYSDATE" FROM EMPLOYEE_ACCESS GROUP BY EMPLOYEE_NAME;
Employee Activity_On_17042016
Jane 5
Martha 8
Sam 11
You are looking to do a reporting job with a data storing tool. The database (and SQL) is for storing and retrieving data, not for creating reports. There are special tools for creating reports.
In database design, it is very unhealthy to encode actual data in table or column name. Neither a table name nor a column name should have, as part of the name (and of the way they are used), an employee id, a date, or any other bit of actual data. Actual data should only be in fields, which in turn are in columns in different tables.
From what you describe, your base table should have columns for employee, activity and date. Then on any given day, if you want the count for the "current" day, you can query with
select employee, count(activity) ct
from table_name
where activity_date = SYSDATE
group by employee
If you want, you can also include the "activity_date" column in the output, that will show for which date the report was run.
Note that I assumed the column name for "date" is "activity_date." And in the output I used "ct" for a column alias, not "count." DATE and COUNT are reserved words, like SYSDATE, and you should NOT use them as table or column name. You could use them as aliases, as long as you don't need to refer to these aliases anywhere else in SQL, but it is still a very bad idea. Imagine you ever need to refer to a column (by name or by alias) and the name or alias is SYSDATE. What would a where clause like this mean?
where sysdate = sysdate
Do you see the problem?
Also, I can't tell from your question - were you thinking of storing these reports back in the database? To what end? It is better to store just one query and run it whenever needed (and make the "activity_date" for which you want the counts) an input parameter, so you can run the query for any date, at any time in the future. There is no need to store the actual daily reports in the database, as long as the base table is properly maintained.
Good luck!

Oracle Partition by 2 columns Interval

Im trying to find on google my situation but no one talk about this situation.
i have a table thats is gonna be partitionized with 2 columns.
for 2 columns partitions can anyone show an example for the interval?
In this case i have only one.
For this example how do i use an interval with 2 columns
INTERVAL( NUMTODSINTERVAL(1,'DAY'))
My table:
create table TABLE_TEST
(
PROCESS_DATE DATE GENERATED ALWAYS AS (TO_DATE(SUBSTR("CHARGE_DATE_TIME",1,10),'yyyymmdd')),
PROCESS_HOUR VARCHAR(10) GENERATED ALWAYS AS (SUBSTR("CHARGE_DATE_TIME",12,2)),
ANUM varchar(100),
SWTICH_DATE_TIME varchar(100),
CHARGE_DATE_TIME varchar(100),
CHARGE varchar(100),
)
TABLESPACE TB_LARGE_TAB
PARTITION BY RANGE (PROCESS_DATE, PROCESS_HOUR)
INTERVAL( NUMTODSINTERVAL(1,'DAY'))
Many Thanks,
Macieira
You can't use an interval if your range has more than one column; you'd get: ORA-14750: Range partitioned table with INTERVAL clause has more than one column. From the documentaion:
You can specify only one partitioning key column, and it must be of NUMBER, DATE, FLOAT, or TIMESTAMP data type.
I'm not sure why you're splitting the date and hour out into separate columns (since a date has a time component anyway), or why you're storing the 'real' date and number values as strings; it would be much simpler to just have columns with the correct data types in the first place. But assuming you are set on storing the data that way and need the separate process_date and process_hour columns as you have them, you can add a third virtual column that combines them:
create table TABLE_TEST
(
PROCESS_DATE DATE GENERATED ALWAYS AS (TO_DATE(SUBSTR(CHARGE_DATE_TIME,1,10),'YYYYMMDD')),
PROCESS_HOUR VARCHAR2(8) GENERATED ALWAYS AS (SUBSTR(CHARGE_DATE_TIME,12,2)),
PROCESS_DATE_HOUR DATE GENERATED ALWAYS AS (TO_DATE(CHARGE_DATE_TIME, 'YYYYMMDDHH24')),
ANUM VARCHAR2(100),
SWTICH_DATE_TIME VARCHAR2(100),
CHARGE_DATE_TIME VARCHAR2(100),
CHARGE VARCHAR2(100)
)
PARTITION BY RANGE (PROCESS_DATE_HOUR)
INTERVAL (NUMTODSINTERVAL(1,'DAY'))
(
PARTITION TEST_PART_0 VALUES LESS THAN (DATE '1970-01-01')
);
Table table_test created.
I've also changed your string data types to varchar2 and added a made-up initial partition. process_hour probably wants to be a number type, depending on how you'll use it. As I don't know why you're choosing your current data types it's hard to tell what would really be more appropriate.
I don't really understand why you'd want the partition range to be hourly and the interval to be one day though, unless you want the partitions to be from, say, midday to midday; in which case the initial partition (test_part_0) would have to specify that time, and your range specification is still wrong for that.
Interval partitioning could be built only on one column.
In your case you have proper partition key column - CHARGE_DATE_TIME. Why do you create virtual columns as VARCHAR2? And why do you need to create partition key on them? Interval partitioning could be built only on NUMBER or DATE columns.

Oracle create table to handle valid_from and valid_to data

I am in the middle of designing a table which include two columns valid_from and valid_to to track historical changes. For example, my table structure is like below:
create table currency_data
(
currency_code varchar(16) not null,
currency_desc varchar(16) not null,
valid_from date not null,
valid_to date,
d_insert_date date,
d_last_update date,
constraint pk_currency_data primary key (currency_code, valid_from)
)
The idea is to leave the valid_to as blank to start with, and if the currency_desc changes in the future, I will need to set a valid_to to the date that the old description is not valid any more, and create a new rows with a new valid_from. But how can I ensure that there will be never a overlap between these 2 rows. For example the query below should only yield one row.
select currency_desc
from currency_data
where currency_code = 'USD'
and trunc(sysdate) between valid_from and nvl(valid_to, sysdate)
Is there a better way to achieve this please other than make sure all developers/end users aware of this rule. Many thanks.
There is a set of implementation approaches known as slowly changing dimensions (SCD) for handling this kind of storage.
What you are currently implementing is SCD II, however, there are more.
Regarding your possible interval overlap issue - there is no simple way to enforce table-level (instead of row-level) consistency with standard constraints, so I guess a robust approach would be to restrict direct DML to this table and wrap it into some standartized pl/sql API which will enforce your riles prior to insert/update and which every developer will use.

Resources