PLSQL functions help - sql

I have this SELECT below which i have to run it in a LOOP for every activity_id(record) that i get from the join.
Also,this SELECT has to be run in multiple places in a procedure to get details and for that records-->I run the assign_ course or assign_test as below.
Can anyone please help me write a function which would have this select .
inputs are strtplanid,strPersonid, p_ objective_id
FOR activity_id IN
(SELECT objact.activity_id, objact.activity_type,objact.IS_REQUIRED
FROM test_training_plan tp,
test_tp_objective tp_obj,
test_train_obj_activity objact
WHERE tp.tplan_id = tp_obj.tplan_id
AND tp.tplan_id = strtplanid
AND tp_obj.t_objective_id = p_objective_id
AND tp_obj.t_objective_id = objact.t_objective_id
AND objact.activity_id NOT IN (
SELECT tplplr.activity_id
FROM test_learning_record lr,
test_learning_record lr1,
test_tp_learning_activity tplplr
WHERE lr.lr_catalog_history_id = tplplr.activity_id
AND lr.learning_record_id =
tplplr.activity_lp_lr_id
AND tplplr.tp_lp_lr_id = lr1.learning_record_id
AND lr1.lr_catalog_history_id =
strtplanid
AND lr.lr_person_id = strPersonid
AND lr1.lr_person_id = strPersonid
AND lr.status IN
('PASSED', 'WAIVED', 'TESTED_OUT'))
AND objact.activity_id NOT IN (
SELECT event_id
FROM test_train_obj_activity toa,
test_event_sessions sessions,
test_learning_record lr1,
test_tp_learning_activity tplearnact,
test_learning_record tplr
WHERE toa.activity_id = sessions.event_id
AND sessions.event_session_id =
lr1.lr_catalog_history_id
AND lr1.learning_record_id =
tplearnact.activity_lp_lr_id
AND tplearnact.tp_lp_lr_id =
tplr.learning_record_id
AND tplr.lr_catalog_history_id =
strtplanid
--AND toa.is_required = 1
AND toa.t_objective_id = obj.t_objective_id
AND tplr.lr_person_id = strPersonid
AND lr1.lr_person_id = strPersonid
AND lr1.status IN
('PASSED', 'WAIVED', 'TESTED_OUT')))
LOOP
IF (activity.activity_type = 'Course')
THEN
ASSIGN_COURSETP(strPersonid,activity.activity_id,strPersonid,activity.activity_type,
activity.IS_REQUIRED,strtplanid,v_straccreditingorg);
ELSif (activity.activity_type ='Test')
THEN
ASSIGN_TESTTP(strPersonid,activity.activity_id,strPersonid,activity.activity_type,
activity.IS_REQUIRED,strtplanid,v_straccreditingorg);
END IF;

Does this need to return anything?
Why can't you wrap your code in the boilerplate function code?
CREATE OR REPLACE Function ACTIVITY_ASSIGN_TESTTP
(
strtplanid IN number
, strPersonid IN number
, p_objective_id IN number
)
RETURN number
IS
retVal number;
BEGIN
-- YOUR CODE
RETURN retVal
END ACTIVITY_ASSIGN_TESTTP;

Related

My while loop is running forever by calculating and inserting the records into a table

I have created a while loop to check if my derived value is less than zero then enter into while loop, increment my Period ID to +1, pull the values from that period and run the logic again.
But my T SQL code is running forever with this logic with the 26000 records which is not a huge data.
Below is my code logic
SELECT #lclcurrentperiod = PERIOD_ID,
#snop_item = FGA_ID,
#lclfullfill_center = fulfillment_center,
#lcldepo_wise_sawtd = DEPOT_WISE_SAWTD,
#lclDemandType = DEMAND_TYPE,
#lclDepo_wise_final = DEPOT_WISE_FINAL,
#lcldepo_wise_forecast = DEPOT_WISE_FORECAST
FROM temp_calc (NOLOCK)
WHERE PERIOd_id IN (SELECT MIN(period_id)FROM temp_calc WHERE depot_wise_forecast > 0)
AND FGA_ID = #fga_id
AND fulfillment_center = #lclFulfillmentCenter
AND DEMAND_TYPE = 'TRANSACTIONAL';
SET #net_offset_forecast = #lclDepo_wise_forecast - #forecast_consumed_by_sales;
INSERT INTO NET_OFFSET_FORECAST (PERIOD_ID,
FGA_ID,
FULFILLMENT_CENTER,
DEMAND_TYPE,
LEGACY_SSC,
DEPOT_WISE_FORECAST,
CUM_FORECAST,
DRAFT_NET_FORECAST,
FORECAST_TO_BE_CONSUMED,
NET_OFFSET_FORECAST)
VALUES (#lclCurrentPeriod, #snop_item, #lclfullfill_center, #lclDemandType, #lclLegacySSC, #lclDepo_wise_forecast, #cum_forecast, #draft_net_forecast, #forecast_consumed_by_sales, #net_offset_forecast);
WHILE (#net_offset_forecast < 0)
BEGIN
SET #lclcurrentperiod = #lclcurrentperiod + 1;
SET #forecast_consumed_by_sales = ABS(#net_offset_forecast);
SELECT #lclcurrentperiod = PERIOD_ID,
#fga_id = FGA_ID,
#lclFulfillmentCenter = FULFILLMENT_CENTER,
#lclDepo_wise_forecast = DEPOT_WISE_FORECAST,
#lclDemandType = DEMAND_TYPE
FROM (SELECT *,
ROW_NUMBER() OVER (ORDER BY PERIOD_ID) AS RN
FROM TEMP_CALC
WHERE DEPOT_WISE_FORECAST > 0
AND FGA_ID = #fga_id
AND fulfillment_center = #lclFulfillmentCenter
AND DEMAND_TYPE = 'TRANSACTIONAL') t
WHERE RN = 1;
SET #net_offset_forecast = #lcldepo_wise_forecast - #forecast_consumed_by_sales;
INSERT INTO NET_OFFSET_FORECAST (PERIOD_ID,
FGA_ID,
FULFILLMENT_CENTER,
DEMAND_TYPE,
LEGACY_SSC,
DEPOT_WISE_FORECAST,
CUM_FORECAST,
DRAFT_NET_FORECAST,
FORECAST_TO_BE_CONSUMED,
NET_OFFSET_FORECAST)
VALUES (#lclCurrentPeriod, #snop_item, #lclfullfill_center, #lclDemandType, #lclLegacySSC, #lclDepo_wise_forecast, #cum_forecast, #draft_net_forecast, #forecast_consumed_by_sales, #net_offset_forecast);
END;
After deriving the net offset forecast it is going into while loop when the net offset forecast is less than zero and performing actions there and not coming up out with the data.
Need to improve the performance of the code to finish the loop and continue processing other data.

Update a table from another table

I have got 2 tables "animal_breeds" and "ztmp.ztmp_509810_anims_out". In "animals breed" every animal has key and breed name and percentage. Few animals might have 2 different breeds with different percentage. Now based on the animals key in "animals_breeds" i want to update "ztmp.ztmp_509810_anims_out"
i am using this code which i know is wrong
update ztmp.ztmp_509810_anims_out
set
alt_id1 = ab.breed
,alt_id2 = pcnt
,alt_id3 = ab.breed
,alt_id4 = pcnt
,alt_id5 = ab.breed
,alt_id6 = pcnt
,alt_id7 = ab.breed
,alt_id8 = pcnt
from animal_breeds ab
where ab.soc_code = ztmp_509810_anims_out.soc_code and ab.animals_key = ztmp_509810_anims_out.animals_key
and ab.soc_code = 'AUNDB';
could i use a for loop inside an update statement?
UPDATE ztmp.ztmp_509810_anims_out AS z
SET soc_code = q.soc_code,
animals_key = q.animals_key,
alt_id1 = breeds[1],
alt_id2 = pcnts[1],
alt_id3 = breeds[2],
alt_id4 = pcnts[2]
FROM (SELECT soc_code, animals_key,
array_agg(breed) breeds, array_agg(pcnt) pcnts
FROM animal_breeds
GROUP BY soc_code, animals_key
) q
WHERE z.soc_code = q.soc_code
AND z.animals_key = q.animals_key;
If there can be more than 2 breeds per animals_key, add breeds[3] and pcnts[3] and so on.

Catching last datetime after update wont result

I have the following code:
UPDATE sm
SET sm_fecha_venc = (SELECT MIN(nd_fecha_venc) FROM [db_facturacion].[dbo].[tb_notas_debito]
WHERE sm_codigo = nd_num_servicio
-- AND nd_referencia = sm_cod_producto
AND nd_num_factura = sm_cod_factura
AND nd_estado = 'G')
,sm_fecha_ult_pago = (SELECT MAX(nd_fecha_pago) FROM [db_facturacion].[dbo].[tb_notas_debito]
WHERE sm_codigo = nd_num_servicio
-- AND nd_referencia = sm_cod_producto
AND nd_num_factura = sm_cod_factura
AND nd_estado = 'C')
,sm_fecha = GETDATE()
,sm_cod_factura_ren = #i_num_factura
OUTPUT DELETED.sm_fecha_venc AS FECHA_VENC_OLD,
DELETED.sm_fecha_ult_pago AS FECHA_ULT_PAGO_OLD,
DELETED.sm_fecha AS FECHA_OLD,
DELETED.sm_cod_factura_ren AS COD_FACTURA_REN_OLD
INTO #TABLATABLA --
FROM [db_facturacion].[dbo].[tb_servicios] sm --WITH(NOLOCK)
INNER JOIN #servicios AS T ON sm_codigo = num_servicio
WHERE sm_tipo_bien_protegido = 1
AND [sm_estado] = 1
--AND sm.sm_cod_forma_contrato = 1
AND sm.sm_tipo_inventario = tipo_inventario
/*===========================
INSERTED DELETED
=============================*/
UPDATE db_facturacion.[dbo].[tb_log_cambio_servicio]
SET cs_fecha_venc_old = FECHA_VENC_OLD
,cs_fecha_ult_pago_old = FECHA_ULT_PAGO_OLD
,cs_fecha_old = FECHA_OLD
,cs_cod_factura_ren_old = COD_FACTURA_REN_OLD
FROM #TABLATABLA
WHERE cs_codigo = #ID_ULTIMO_ING (LAST ##IDENTITY)
Im trying to save the last dates into a log table, just in case I have to return those dates back.
The code works good, just that it's catching the actual date and inserted in the log table.
What am I missing?

How to get results from Oracle Trigger and act accordingly

i have created a after update trigger for a table in my database, that when a value is modified in a specific column, it also updates a same table from another database. My question is, how can i check if the results are 0 (that means such row does not exists in the 2nd database, and 1 that the row exists and its updated) and act accordingly? i want if i get 0 that means such primary key does not exist, to create it in the 2nd database. Here is my ORACLE trigger code:
CREATE OR REPLACE TRIGGER UPDATE_BIOGR
AFTER UPDATE OF ID_PATIENTS,NAME,SNAME,GENDER,DATE_BORN,COUNTRY,CITY,BLOODTYPE,FATHER_ID,MOTHER_ID,FATHER_NAME,FATHER_LASTNAME,MOTHER_FIRSTNAME,MOTHER_LASTNAME,TIL,E_MAIL ON BIOGR
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
v_username varchar2(10);
BEGIN
SELECT user INTO v_username
FROM dual;
UPDATE PERSONAL_RECORD.BIOGR SET
ID = :NEW.ID_PATIENTS, NAME = :NEW.NAME, SNAME = :NEW.SNAME, GENDER = :NEW.GENDER, DATEBORN = :NEW.DATE_BORN, PLACE_BORN = :NEW.COUNTRY,
PLACE_STATE = :NEW.CITY, BLOOD_TYPE = :NEW.BLOODTYPE, ID_FATHER = :NEW.FATHER_ID, ID_MOTHER = :NEW.MOTHER_ID,
FATHER_NAME = :NEW.FATHER_NAME, FATHER_SNAME = :NEW.FATHER_LASTNAME, MOTHER_NAME = :NEW.MOTHER_FIRSTNAME,
MOTHER_SNAME = :NEW.MOTHER_LASTNAME, TIL = :NEW.TIL, EMAIL = :NEW.E_MAIL, UPDATED_FROM = v_username
WHERE PERSONAL_RECORD.BIOGR.ID = :NEW.ID_PATIENTS;
END;
Try the MERGE-Statement with something like the following:
MERGE INTO personal_record.biogr USING dual ON
(PERSONAL_RECORD.BIOGR.ID = :OLD.ID_PATIENTS)
WHEN MATCHED THEN
UPDATE SET
ID = :NEW.ID_PATIENTS, NAME = :NEW.NAME, SNAME = :NEW.SNAME, GENDER = :NEW.GENDER, DATEBORN = :NEW.DATE_BORN, PLACE_BORN = :NEW.COUNTRY,
PLACE_STATE = :NEW.CITY, BLOOD_TYPE = :NEW.BLOODTYPE, ID_FATHER = :NEW.FATHER_ID, ID_MOTHER = :NEW.MOTHER_ID,
FATHER_NAME = :NEW.FATHER_NAME, FATHER_SNAME = :NEW.FATHER_LASTNAME, MOTHER_NAME = :NEW.MOTHER_FIRSTNAME,
MOTHER_SNAME = :NEW.MOTHER_LASTNAME, TIL = :NEW.TIL, EMAIL = :NEW.E_MAIL, UPDATED_FROM = v_username
WHEN NOT MATCHED THEN
INSERT (id, name, sname, ....)
VALUES (:NEW.ID_PATIENTS, :NEW.NAME, :NEW.SNAME, ...);

Oracle: an elegant way to extract record which share a column value

I've found two way to take every record, which shares one column value, among some distinct record set identified each one by a set of WHERE conditions.
(The example query are very more clear...)
Do you know a third way more sinthetic? maybe using analytical function?
select a.grup_gruppo_id
FROM conf_gruppi_delim a, conf_gruppi_delim b, conf_gruppi_delim c
WHERE a.ASTG_ASSE_TIPO_GRUPPO_ID = 'BASE_TSC'
AND a.TGAS_TIPGRUPDETT_ASSI_ID = 'C5JqJeruozekiQtN'
AND a.DELI_VALORE1 = '1RWOoegWqEdL9Vch'
AND a.DELI_FLAG_ANN = 'N'
--
AND b.ASTG_ASSE_TIPO_GRUPPO_ID = 'TIPI_MERCATO'
AND b.TGAS_TIPGRUPDETT_ASSI_ID = '_tgas_time_f'
AND b.DELI_VALORE1 = 'ZFLIB'
AND b.DELI_FLAG_ANN = 'N'
--
AND c.ASTG_ASSE_TIPO_GRUPPO_ID = 'SEQUENZA'
AND c.TGAS_TIPGRUPDETT_ASSI_ID = '_tgas_sefm_f'
AND c.DELI_VALORE1 = 'LE8IZjuiOHVtxAwi'
AND c.DELI_FLAG_ANN = 'N'
--
AND A.GRUP_GRUPPO_ID = b.GRUP_GRUPPO_ID
AND b.GRUP_GRUPPO_ID = c.GRUP_GRUPPO_ID
SELECT GRUP_GRUPPO_ID
FROM conf_gruppi_delim a
WHERE ASTG_ASSE_TIPO_GRUPPO_ID = 'BASE_TSC'
AND TGAS_TIPGRUPDETT_ASSI_ID = 'C5JqJeruozekiQtN'
AND DELI_VALORE1 = '1RWOoegWqEdL9Vch'
AND DELI_FLAG_ANN = 'N'
INTERSECT
SELECT GRUP_GRUPPO_ID
FROM conf_gruppi_delim a
WHERE ASTG_ASSE_TIPO_GRUPPO_ID = 'TIPI_MERCATO'
AND TGAS_TIPGRUPDETT_ASSI_ID = '_tgas_time_f'
AND DELI_VALORE1 = 'ZFLIB'
AND DELI_FLAG_ANN = 'N'
INTERSECT
SELECT GRUP_GRUPPO_ID
FROM conf_gruppi_delim a
WHERE ASTG_ASSE_TIPO_GRUPPO_ID = 'SEQUENZA'
AND TGAS_TIPGRUPDETT_ASSI_ID = '_tgas_sefm_f'
AND DELI_VALORE1 = 'LE8IZjuiOHVtxAwi'
AND DELI_FLAG_ANN = 'N'
In this case where you're just filtering on 3 different sets of values
SELECT GRUP_GRUPPO_ID
FROM conf_gruppi_delim a
WHERE (ASTG_ASSE_TIPO_GRUPPO_ID,
TGAS_TIPGRUPDETT_ASSI_ID,
DELI_VALORE1,
DELI_FLAG_ANN ) IN
( ('SEQUENZA','_tgas_sefm_f','LE8IZjuiOHVtxAwi','N'),
('TIPI_MERCATO','_tgas_time_f','ZFLIB','N'),
('BASE_TSC','C5JqJeruozekiQtN','1RWOoegWqEdL9Vch','N') )
GROUP BY GRUP_GRUPPO_ID
HAVING COUNT( distinct ASTG_ASSE_TIPO_GRUPPO_ID ) = 3