Ik probeer het hier even omdat op de oracle forums en op metalink niet veel te vinden is.
Hier de vraag:
DE applicatie draait in webforms (6i) op een 8.1.7 database server.
We willen een aantal business rules op de database implementeren. Het afgeslankte voorbeeld is het volgende: Indien een verkoper een type bezoek VISIT bij een verkooppunt heeft en hij boekt dat in als DAY, dan kan hij op die dag niets meer inplannen als AM/PM.
Geen probleem, dit heb ik met een after insert/update trigger op row level opgevangen en een after insert/update op statement level (Om mutating triggers te vermijden).
Nu komt het probleem, omdat het verkopers zijn en dus niets van de eerste maal correct kunnen ingeven
Komt soms de volgende situatie voor:
Ze plaasten een VISIT op AM en ander op PM, dat wordt goed gecommit op de database, de rule is niet geschonden. Maar dan komen ze tot de conclusie dat de de combinatie AM PM eigenlijk DAY is en willen ze deze twee VISITS Naar DAY zetten. Op de database wordt bij validatie via de trigger echter voor het tweede record nog PM gevonden en de combinatie PM/DAY mag niet met als gevolg dat de enige mogelijkheid is dat ze een van de twee records moeten deleten, commiten het ene record wijzigen en dan het tweede record opnieuw toevoegen.
Ik zou graag een oplossing vinden zodat de check pas afgaat als beide records naar de database zijn gestuurt, want dat worden de business rules niet geschonden. Constraints zijn ook geen oplossing want het is niet toegestaan om select staments in constraint te gebruiken.
Ben ik wat duidelijk
Want ik geraak meestal niet uit mijn woorden 
De code van de before insert/update trigger op elk record.
De code van de before insert/update trigger per statement
Hier de vraag:
DE applicatie draait in webforms (6i) op een 8.1.7 database server.
We willen een aantal business rules op de database implementeren. Het afgeslankte voorbeeld is het volgende: Indien een verkoper een type bezoek VISIT bij een verkooppunt heeft en hij boekt dat in als DAY, dan kan hij op die dag niets meer inplannen als AM/PM.
Geen probleem, dit heb ik met een after insert/update trigger op row level opgevangen en een after insert/update op statement level (Om mutating triggers te vermijden).
Nu komt het probleem, omdat het verkopers zijn en dus niets van de eerste maal correct kunnen ingeven
Ze plaasten een VISIT op AM en ander op PM, dat wordt goed gecommit op de database, de rule is niet geschonden. Maar dan komen ze tot de conclusie dat de de combinatie AM PM eigenlijk DAY is en willen ze deze twee VISITS Naar DAY zetten. Op de database wordt bij validatie via de trigger echter voor het tweede record nog PM gevonden en de combinatie PM/DAY mag niet met als gevolg dat de enige mogelijkheid is dat ze een van de twee records moeten deleten, commiten het ene record wijzigen en dan het tweede record opnieuw toevoegen.
Ik zou graag een oplossing vinden zodat de check pas afgaat als beide records naar de database zijn gestuurt, want dat worden de business rules niet geschonden. Constraints zijn ook geen oplossing want het is niet toegestaan om select staments in constraint te gebruiken.
Ben ik wat duidelijk
De code van de before insert/update trigger op elk record.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| CREATE OR REPLACE TRIGGER before_check_int_cal BEFORE INSERT OR UPDATE ON epos_internal_calendar REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW begin pck$epos.v_int_cal_entries := pck$epos.v_int_cal_entries + 1; pck$epos.v_eic_pos_id(pck$epos.v_int_cal_entries) := :NEW.POS_ID; pck$epos.v_eic_am_pm(pck$epos.v_int_cal_entries) := :NEW.AM_PM; pck$epos.v_eic_icty_id(pck$epos.v_int_cal_entries) := :NEW.ICTY_ID; pck$epos.v_eic_icst_id(pck$epos.v_int_cal_entries) := :NEW.ICST_ID; pck$epos.v_eic_from_date(pck$epos.v_int_cal_entries) := :NEW.FROM_DATE; pck$epos.v_eic_till_date(pck$epos.v_int_cal_entries) := :NEW.TILL_DATE; pck$epos.v_eic_iper_id(pck$epos.v_int_cal_entries) := :NEW.IPER_ID; pck$epos.v_eic_id(pck$epos.v_int_cal_entries) := :NEW.ID; end; |
De code van de before insert/update trigger per statement
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
| CREATE OR REPLACE TRIGGER after_check_int_cal
AFTER INSERT OR UPDATE
ON epos_internal_calendar
REFERENCING NEW AS NEW OLD AS OLD
DECLARE
v_pos_id epos_internal_calendar.pos_id%type;
v_am_pm epos_internal_calendar.am_pm%type;
v_icty_id epos_internal_calendar.iper_id%type;
v_test Number;
v_icst_id epos_internal_calendar.icst_id%type;
v_from_date epos_internal_calendar.from_date%type;
v_till_date epos_internal_calendar.till_date%type;
v_iper_id epos_internal_calendar.iper_id%type;
v_id epos_internal_calendar.id%type;
cursor get_ical_type_id (p_type epos_int_cal_types.type%type)
is
select id from epos_int_cal_types
where type = p_type;
r_ical_type_id get_ical_type_id%rowtype;
cursor check_period(p_iper_id epos_internal_calendar.iper_id%type,p_id epos_internal_calendar.id%type) IS
select epos_internal_calendar.icty_id,
epos_internal_calendar.from_date,
epos_internal_calendar.till_date,
epos_internal_calendar.am_pm
FROM epos_internal_calendar
where am_pm = 'P'
AND iper_id = p_iper_id
and id != p_id;
cursor check_all(p_from_date epos_internal_calendar.from_date%type, p_till_date epos_internal_calendar.till_date%type,p_iper_id epos_internal_calendar.iper_id%type,p_id epos_internal_calendar.id%type )IS
select epos_internal_calendar.icty_id,
epos_internal_calendar.from_date,
epos_internal_calendar.till_date,
epos_internal_calendar.am_pm
from epos_internal_calendar
where (From_date >= p_FROM_DATE and from_date <= p_TILL_DATE) or (till_date >= p_FROM_DATE and till_date <= p_TILL_DATE)
AND IPER_ID = p_iper_id
and id != p_id;
cursor check_ampm_type(ampm_type epos_internal_calendar.am_pm%type,p_from_date epos_internal_calendar.from_date%type, p_till_date epos_internal_calendar.till_date%type,p_iper_id epos_internal_calendar.iper_id%type,p_id epos_internal_calendar.id%type) IS
select epos_internal_calendar.icty_id,
epos_internal_calendar.from_date,
epos_internal_calendar.till_date,
epos_internal_calendar.am_pm
from epos_internal_calendar
where From_date between p_FROM_DATE and p_TILL_DATE
and am_pm in (ampm_type)
AND IPER_ID = p_iper_id
and id != p_id;
r_check_all check_all%rowtype;
r_check_period check_period%rowtype;
r_check_ampm_type check_ampm_type%rowtype;
go_on boolean;
message_shown boolean;
BEGIN
go_on := true;
message_shown := false;
-- loop through the memory table defined in pck$epos to check if doubles exist
for i in 1..pck$epos.v_int_cal_entries loop
v_pos_id := pck$epos.v_eic_pos_id(i);
v_am_pm := pck$epos.v_eic_am_pm(i);
v_icty_id := pck$epos.v_eic_icty_id(i);
v_icst_id := pck$epos.v_eic_icst_id(i);
v_from_date := pck$epos.v_eic_from_date(i);
v_till_date := pck$epos.v_eic_till_date(i);
v_iper_id := pck$epos.v_eic_iper_id(i);
v_id := pck$epos.v_eic_id(i);
-- the test to check for doubles
select count(*) into v_test
from epos_internal_calendar ical, epos_pos pos
where pos_id = v_pos_id
and pos.id = ical.pos_id
and pos.salesnbr_amp not like 'NEW%'
--and am_pm = v_am_pm --NO POS CAN BE VISITED TWICE IN A DAY
and icty_id = v_icty_id
--and icst_id = v_icst_id --NO POS CAN BE VISITED TWICE IN A DAY
and (
(iper_id = v_iper_id) OR
(iper_id != v_iper_id and v_icty_id in (select id from epos_int_cal_types where type='VISIT'))
)
and to_char(from_date,'YYYYMMDD') = to_char(v_from_date,'YYYYMMDD');
if v_test >=2 then
pck$messaging6.raise_error('EPOS-0020');
end if;
if v_AM_PM ='D'
then --Check if already something on AM or PM
open check_ampm_type('AM',v_from_date,v_till_date,v_iper_id,v_id);
fetch check_ampm_type into r_check_ampm_type;
if check_ampm_type%found
then close check_ampm_type;
pck$epos.v_int_cal_entries := 0;
pck$messaging6.raise_error('EPOS-0024');
else close check_ampm_type;
end if;
open check_ampm_type('PM',v_from_date,v_till_date,v_iper_id,v_id);
fetch check_ampm_type into r_check_ampm_type;
if check_ampm_type%found
then close check_ampm_type;
pck$epos.v_int_cal_entries := 0;
pck$messaging6.raise_error('EPOS-0024');
else close check_ampm_type;
end if;
open check_ampm_type('D',v_from_date,v_till_date,v_iper_id,v_id);
fetch check_ampm_type into r_check_ampm_type;
if check_ampm_type%notfound
then close check_ampm_type;
else close check_ampm_type;
if ((r_check_ampm_type.icty_id = 2 and v_icty_id != 2)or (r_check_ampm_type.icty_id != 2 and v_icty_id = 2) or (r_check_ampm_type.icty_id != 2 and v_icty_id !=2) )
then pck$epos.v_int_cal_entries := 0;
pck$messaging6.raise_error('EPOS-0024');
message_shown := true;
end if;
end if ;
end if ;
--Check if AMPM = AM
if v_AM_PM ='AM'
then --Check if already something on DAY
open check_ampm_type('D',v_from_date,v_till_date,v_iper_id,v_id);
fetch check_ampm_type into r_check_ampm_type;
if check_ampm_type%found
then close check_ampm_type;
pck$epos.v_int_cal_entries := 0;
pck$messaging6.raise_error('EPOS-0024');
else close check_ampm_type;
end if;
--Check what is planned on type AM
open check_ampm_type('AM',v_from_date,v_till_date,v_iper_id,v_id);
fetch check_ampm_type into r_check_ampm_type;
if check_ampm_type%notfound
then close check_ampm_type;
else close check_ampm_type;
if ((r_check_ampm_type.icty_id = 2 and v_icty_id != 2)or (r_check_ampm_type.icty_id != 2 and v_icty_id = 2) or (r_check_ampm_type.icty_id != 2 and v_icty_id !=2) )
then pck$epos.v_int_cal_entries := 0;
pck$messaging6.raise_error('EPOS-0024');
message_shown := true;
end if;
end if ;
end if;
--Check if AMPM = PM
if v_AM_PM ='PM'
then --Check if already something on DAY
open check_ampm_type('D',v_from_date,v_till_date,v_iper_id,v_id);
fetch check_ampm_type into r_check_ampm_type;
if check_ampm_type%found
then close check_ampm_type;
pck$epos.v_int_cal_entries := 0;
pck$messaging6.raise_error('6');
else close check_ampm_type;
end if;
--Check what is planned on type AM
open check_ampm_type('PM',v_from_date,v_till_date,v_iper_id,v_id);
fetch check_ampm_type into r_check_ampm_type;
if check_ampm_type%notfound
then close check_ampm_type;
else close check_ampm_type;
if ((r_check_ampm_type.icty_id = 2 and v_icty_id != 2)or (r_check_ampm_type.icty_id != 2 and v_icty_id = 2) or (r_check_ampm_type.icty_id != 2 and v_icty_id !=2) )
then pck$epos.v_int_cal_entries := 0;
pck$messaging6.raise_error('EPOS-0024');
message_shown := true;
else
--v_multiple := FALSE;
null;
end if;
end if ;
end if;
if v_AM_PM ='P'
then open check_all(v_from_date,v_till_date,v_iper_id,v_id);
fetch check_all into r_check_all;
if check_all%found
then close check_all;
pck$epos.v_int_cal_entries := 0;
pck$messaging6.raise_error('EPOS-0024');
message_shown := true;
else close check_all;
end if;
end if;
--Check if there is something planned on this day, by use of Period
if message_shown = false
then open check_period(v_iper_id,v_id);
fetch check_period into r_check_period;
if check_period%notfound
then close check_period;
else while go_on LOOP
if v_FROM_DATE >= r_check_period.from_DATE and v_TILL_DATE <= r_check_period.TILL_DATE
then close check_period;
pck$epos.v_int_cal_entries := 0;
pck$messaging6.raise_error('EPOS-0024');
go_on := false;
else fetch check_period into r_check_period;
if check_period%notfound
then close check_period;
go_on:= false;
end if ;
end if;
end loop;
end if;
end if;
end loop;
pck$epos.v_int_cal_entries := 0;
end; |