2016-07-28 13 views
0

Ich möchte die Datensätze für eine bestimmte Spalte einfügen, die um 1 erhöht wird, wenn die neue Zeile in Tabelle eingefügt wird basierend auf der folgenden Bedingung Für das aktuelle Jahr die erste Zeile mit Wert : 1 für laufende Jahr soll der Spaltenwert von 1 Bedeutung 1 für erste Aufzeichnung dieses laufenden Jahres und nächste verfügbare Nummer für die passende JahrAutomatisches Inkrement für nicht primäre Schlüsselspalte in Oracle

Year Value 
2016 1 
2016 2 
2016 3 
2017 1 
2017 2 
... 

Mein Ansatz wie dies etwas erhöht werden:

INSERT INTO ABC(ANALYSIS_YEAR,ANALYSIS_NUMBER) 
values (EXTRACT(YEAR FROM sysdate), 
     case when ANALYSIS_YEAR=EXTRACT(YEAR FROM sysdate) then AutoIcreamt with starting value 1 else 1; 
    ) 
+0

Möchten Sie die gleiche Zeile der Tabelle aktualisieren, die mit einem Spaltenwert eingefügt wird 1 – XING

+1

Nein, dass die Spalte nicht aktualisiert wird – SantyEssac

Antwort

0

Sie werden wahrscheinlich einen Trigger auf der Einfügung benötigen, der so aussieht (ich denke, Sie können den Wert von Jahr nicht ändern, in diesem Fall wird es komplizierter). Wie @ ibre5041 Dies wird nicht auf einem Multi-User-Umgebung arbeiten, da Sie Duplikate haben könnte, wenn ein paar Transaktionen zur gleichen Zeit auf dem gleichen Jahr ausgeführt werden:

CREATE OR REPLACE TRIGGER trg_bi_table1 
before insert 
ON table_1 
Begin 
    select nvl(max(value),0)+1 as value 
    into :new.value 
    from table_1 
    where Year = :new.Year; 
end; 
/

In einer Multi-User-Umgebung Sie sollte verwenden select for update

+0

Die Anforderung besteht darin, eine Zeile einzufügen. Wie kommt es, dass Ihr Auslöser eine Zeile in die Tabelle einfügt? Ich denke, Sie müssen die komplette Lösung zur Verfügung stellen – XING

+0

@Raj_Te Ich denke, er sucht nach der Autoincrement der Spalte namens "Value". – vercelli

+0

Auch in diesem Fall, wenn sich das Jahr ändert, wird der obige Trigger nicht auf 1 zurückgesetzt. – XING

2

Jede Lösung, die aktuelle Tabellenwerte überprüft, funktioniert nicht in einer "echten" Umgebung mit mehreren Benutzern und mehreren Sitzungen und parallelen Transaktionen.

Ich glaube, Sie brauchen, um die zwei Anforderungen zu trennen:

  1. die Fähigkeit haben, Aufzeichnungen auf sequenzieren basiert, wenn sie erstellt wurden
  2. die Fähigkeit haben, auf Rekord-Sequenzierung innerhalb eines Jahres zu berichten.

Die erste wird mit einer Sequenz behandelt, da diese hierfür genau gestaltet und Concurrency (mehrere Benutzer, mehrere Transaktionen, ...) behandeln.

Die zweite ist eine Berichtspflicht und bietet abhängig von den Leistungsanforderungen eine Reihe von Optionen.

Zu allererst eine Sequenz erzeugen:

create sequence seq_analysis_id start with 1 increment by 1 nocache nocycle; 

Nicht mal eine Basistabelle erstellen und einen Trigger, um das Auto-Inkrement zu handhaben:

create table analysis_data (
    analysis_id integer not null, 
    analysis_date date not null 
    ); 

alter table analysis_data add constraint pk_analysis_data primary key (analysis_id); 

create or replace trigger trg_analysis_data 
before insert on analysis_data 
for each row 
begin 
    :new.analysis_id := seq_analysis_id.nextval(); 
end trg_analysis_data; 
/

insert into analysis_data (analysis_date) values (to_date('2015-12-28', 'YYYY-MM-DD')); 

insert into analysis_data (analysis_date) values (to_date('2015-12-29', 'YYYY-MM-DD')); 

insert into analysis_data (analysis_date) values (to_date('2015-12-30', 'YYYY-MM-DD')); 

insert into analysis_data (analysis_date) values (to_date('2015-12-31', 'YYYY-MM-DD')); 

insert into analysis_data (analysis_date) values (to_date('2016-01-01', 'YYYY-MM-DD')); 

insert into analysis_data (analysis_date) values (to_date('2016-01-02', 'YYYY-MM-DD')); 

insert into analysis_data (analysis_date) values (to_date('2016-01-03', 'YYYY-MM-DD')); 

commit; 

select * from analysis_data; 

ANALYSIS_ID ANALYSIS_DATE 
    1   28/12/2015 
    2   29/12/2015 
    3   30/12/2015 
    4   31/12/2015 
    5   01/01/2016 
    6   02/01/2016 
    7   03/01/2016 

Ok - so dass alles gut funktioniert, aber doesn ‚t Ihnen, was Sie für :)

gefragt Dies ist der zweite Teil - die Meldepflicht:

Die erste Option ist nur die Zahlen erhalten müssen Sie dynamisch:

select 
    analysis_id, 
    analysis_date, 
    extract(year from analysis_date) analysis_year, 
    row_number() 
     over (partition by trunc(analysis_date, 'YYYY') 
     order by analysis_date, analysis_id) analysis_number 
from 
    analysis_data; 

Verwendung von analytischen Funktionen (row_number in diesem Fall) sind eine gute Möglichkeit, diese Art der Sache zu behandeln.

ANALYSIS_ID ANALYSIS_DATE ANALYSIS_YEAR ANALYSIS_NUMBER 
    1   28/12/2015  2015    1 
    2   29/12/2015  2015    2 
    3   30/12/2015  2015    3 
    4   31/12/2015  2015    4 
    5   01/01/2016  2016    1 
    6   02/01/2016  2016    2 
    7   03/01/2016  2016    3 

Ich habe von analysis_date, analysis_id in der row_number Funktion bestellt.Dies ist wahrscheinlich nicht notwendig, aber würde benötigt werden, wenn Sie mit Updates für die analysis_date umgehen müssten (in diesem Fall funktioniert die Sequenz nicht mehr für die Bestellung innerhalb eines Jahres allein).

Man könnte dies ein wenig einfacher für die Berichterstattung machen, indem es in einer Ansicht Verpackung:

create or replace view analysis_data_v as 
select 
    analysis_id, 
    analysis_date, 
    extract(year from analysis_date) analysis_year, 
    row_number() 
     over (partition by trunc(analysis_date, 'YYYY') 
     order by analysis_date, analysis_id) analysis_number 
from 
    analysis_data; 

Dies alles was Sie brauchen können, aber wenn Sie große Datenmengen haben, dann können Sie im Voraus berechnen müssen einige dieser Werte. Sie haben virtuelle Spalten in 11g, aber diese funktionieren nicht für analytische Funktionen. Meine Wahl wäre hier eine materialisierte Ansicht verwenden - viele Möglichkeiten, materialisierte Ansicht Auffrischungen zu handhaben und die einfachste wäre:

create materialized view analysis_data_mv 
    build immediate 
    refresh complete on demand 
as 
    select 
     analysis_id, 
     analysis_date, 
     analysis_year, 
     analysis_number 
    from 
     analysis_data_v; 

select * from analysis_data_mv order by analysis_year, analysis_number; 

ANALYSIS_ID ANALYSIS_DATE ANALYSIS_YEAR ANALYSIS_NUMBER 
    1   28/12/2015  2015    1 
    2   29/12/2015  2015    2 
    3   30/12/2015  2015    3 
    4   31/12/2015  2015    4 
    5   01/01/2016  2016    1 
    6   02/01/2016  2016    2 
    7   03/01/2016  2016    3 

In diesem Fall wird die materialisierte Ansicht würde manuell aktualisiert:

exec dbms_mview.refresh('analysis_data_mv'); 

Hoffe das hilft.

+0

Sehr schön erklärt. Upvoted für Ihre Antwort. – XING