Taking Previous Months' Date Automatically in PLSQL - database

Hello I have a procedure and questions about it. This procedure is used for extracting data then inserting them into one table. When I test my code, I have to enter some parameters for executing procedure.
`--this is how I execute the procedure
begin
GPU_DATA_EXTRACTOR(to_date('31/08/2021','DD/MM/YYYY'));
end;`
But what I want to do is that when the billdate parameter is NULL, the procedure should execute last day of the previous month as a parameter automatically. How can I make this change? I am open to any update advices thank you from now.
Updated the script below.
create or replace procedure GPU_DATA_EXTRACTOR_TEST(pid_billdate DATE DEFAULT LAST_DAY(ADD_MONTHS(TRUNC(SYSDATE), -1))) is
c_limit CONSTANT PLS_INTEGER DEFAULT 10000;
CURSOR c1 IS
SELECT DISTINCT intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab
WHERE abr.CHRG_TP = 'INSTALLMENT'
AND abr.TAX_CATG_ID = 'NOTAX'
AND abr.acct_bill_id = ab.acct_bill_id
AND ab.bill_date = pid_billdate;
TYPE prod_ids_t IS TABLE OF apld_bill_rt.intl_prod_id%TYPE INDEX BY PLS_INTEGER;
l_prod_ids prod_ids_t;
begin
execute immediate 'truncate table GPU_INV_TEST';
OPEN c1;
LOOP
FETCH c1 BULK COLLECT INTO l_prod_ids LIMIT c_limit;
EXIT WHEN l_prod_ids.COUNT = 0;
FORALL indx IN 1 .. l_prod_ids.COUNT
INSERT INTO GPU_INV_TEST
SELECT AB.ACCT_BILL_ID,
AB.BILL_NO,
AB.INV_ID,
AB.BILL_DATE,
ba2.bill_acct_id,
ba1.bill_acct_id parent_bill_acct_id,
AB.DUE_DATE,
PG.CMPG_ID,
ABR.NET_AMT,
AB.DUE_AMT,
P.PROD_NUM,
pds.DST_ID,
ABR.DESCR,
p.intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab,
prod p,
FCBSADM.PROD_DST pds,
bill_acct_prod bap,
bill_acct ba1,
bill_acct ba2,
prod_cmpg pg
WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
AND ba2.intl_bill_acct_id = bap.intl_bill_acct_id
AND bap.intl_prod_id = abr.intl_prod_id
AND ABR.CHRG_TP = 'INSTALLMENT'
AND bap.intl_prod_id = pds.intl_prod_id
AND bap.intl_prod_id = p.intl_prod_id
AND p.intl_prod_id = pg.intl_prod_id(+)
AND ABR.intl_prod_id = l_prod_ids(indx)
UNION
SELECT AB.ACCT_BILL_ID,
AB.BILL_NO,
AB.INV_ID,
AB.BILL_DATE,
ba1.bill_acct_id,
ba1.bill_acct_id parent_bill_acct_id,
AB.DUE_DATE,
PG.CMPG_ID,
ABR.NET_AMT,
AB.DUE_AMT,
P.PROD_NUM,
pds.DST_ID,
ABR.DESCR,
p.intl_prod_id
FROM apld_bill_rt abr,
acct_bill ab,
prod p,
FCBSADM.PROD_DST pds,
bill_acct_prod bap,
bill_acct ba1,
prod_cmpg pg
WHERE ab.intl_bill_acct_id = ba1.intl_bill_acct_id
AND AB.ACCT_BILL_ID = ABR.ACCT_BILL_ID
--AND ba1.intl_bill_acct_id = ba2.parent_bill_acct_id
AND ba1.intl_bill_acct_id = bap.intl_bill_acct_id
AND bap.intl_prod_id = abr.intl_prod_id
AND ABR.CHRG_TP = 'INSTALLMENT'
AND bap.intl_prod_id = pds.intl_prod_id
AND bap.intl_prod_id = p.intl_prod_id
AND p.intl_prod_id = pg.intl_prod_id(+)
AND ABR.intl_prod_id = l_prod_ids(indx);
COMMIT;
END LOOP;
CLOSE c1;
end;

You can add a default value for your parameters. Take the following function as an example:
CREATE OR REPLACE FUNCTION sf_showDefault
(
p_in DATE DEFAULT LAST_DAY(ADD_MONTHS(TRUNC(SYSDATE), -1))
)
RETURN DATE
IS
BEGIN
RETURN p_in;
END sf_showDefault;
/
When no parameters are entered it gets a truncated SYSDATE and subtracts one month, then if finds the last day of that month. All the function does is return that data (or the one that you pass in...if you feel like it).
Here is a DBFiddle showing the effect of DEFAULT parameters (LINK)

Related

Stream and Task Stored procedure example, I am not sure how to troubleshoot the javascript

I have just learned about Streams and Tasks in Snowflake and have tested the example for tracking members and sign ups in the first example here.
I have attempted to create a stored procedure that looks like this:
CREATE OR REPLACE procedure member_update()
returns string not null
language javascript
as
$$
var statement = snowflake.createStatement({sqlText: "BEGIN"} );
statement.execute();
var statement = snowflake.createStatement({sqlText: "UPDATE members SET fee = fee + 15 where fee > 0"} );
statement.execute();
var statement = snowflake.createStatement({sqlText: "SELECT * FROM member_check"} );
statement.execute();
var statement = snowflake.createStatement({sqlText: "COMMIT"} );
statement.execute();
var statement = snowflake.createStatement({sqlText: "SELECT * FROM member_check"} );
statement.execute();
$$
;
INSERT INTO members (id,name,fee)
VALUES
(11,'Bill',0),
(12,'Jason',0),
(13,'Suzan',0),
(14,'Michelle',0),
(15,'AARON',0);
SELECT * FROM MEMBER_CHECK;
INSERT INTO signup
VALUES
(11,'2018-01-01'),
(12,'2018-02-15'),
(13,'2018-05-01'),
(14,'2018-07-16'),
(15,'2018-08-21');
MERGE INTO members m
USING (
SELECT id, dt
FROM signup s
WHERE DATEDIFF(day, '2018-08-15'::date, s.dt::DATE) < -30) s
ON m.id = s.id
WHEN MATCHED THEN UPDATE SET m.fee = 90;
Call member_update();
I have run into an error and was hoping I might get some guidance on by very beginner stored procedure.
Error:
Execution error in store procedure MEMBER_UPDATE: empty argument
passed At Snowflake.createStatement, line 2 position 29

Stored procedure runs correctly but DataReader gets wrong result...sometimes

I have a stored procedure for a travel booking system that takes in a TripID and identifies whether the trip is domestic or not (e.g. whether the origin and destination countries are the same for all trip legs). When I run the procedure from SSMS, it correctly returns 1 for domestic and 0 for international. However, when I try to access the data in my application through DataReader, it inappropriately returns 0 for domestic trips.
That being said, I don't think the problem lies purely with the DataReader because when I alter my stored procedure to return 1 immediately, DataReader will correctly detect this value.
Can anyone suggest changes to my code to fix this behavior?
Here is the stored procedure, pared down:
SET NOCOUNT ON;
-- EXEC CheckIsDomestic 6343
Declare #HomeOffice INT = (SELECT TOP 1 o.DestinationID
FROM TR_Trips t
JOIN TR_Travelers ta ON t.TravelerID = ta.TravelerID
JOIN TR_OfficeLocations o ON ta.OfficeID = o.Office_Loc_Id
WHERE t.TripID = #TripID)
SELECT l.Destination_ID AS DestinationID
INTO #TempDest
FROM TR_Trips t JOIN TR_Legs l ON t.TripID = l.TripID
WHERE t.TripID = #TripID
--Check whether there is a destination in the list that is different than the home country
DECLARE #CountRows int = (SELECT COUNT(*)
FROM #TempDest t
WHERE DestinationID <> #HomeOffice )
IF #CountRows > 0
BEGIN
SELECT 0
RETURN --tried with and without RETURN; no change
END
ELSE
BEGIN SELECT 1
RETURN
END
And here are the applicable parts of my application:
public bool IsDomestic(int TripID)
{
bool ReturnValue = true;
NewStoredProcedureCommand("CheckIsDomestic");
AddParameter("#TripID", TripID, System.Data.SqlDbType.Bit);
ReturnValue = Execute_ReturnValueBool();
return ReturnValue;
}
public Boolean Execute_ReturnValueBool()
{
if (sqlCommand == null)
NewCommand();
if (sqlCommand.Connection.State != ConnectionState.Open)
sqlCommand.Connection.Open();
bool ReturnValue = false;
SqlDataReader DR = sqlCommand.ExecuteReader();
if (DR.HasRows)
{
DR.Read();
System.Diagnostics.Debug.WriteLine(DR[0]);
ReturnValue = Convert.ToBoolean(DR[0]);
}
DR.Close();
sqlCommand.Connection.Close();
return ReturnValue;
}
Why are you using the BIT type for your TripID parameter in the application code? Try setting it to INT.

Manipulating the list of data from stored procedure to be used in another stored procedure

Currently I'm writing a stored procedureusing T-SQL in SQL Server. My script contains code to run another stored procedure to get list of data from a table. I want to manipulate the data, using the list of data to modify them for another purpose (e.g. summing up a column and adding more lists of data) from the stored procedure. A way that I know is to create a temporary table. But after that, I'm not so sure. Please help. thanks.
This is my code:
ALTER PROCEDURE [dbo].[AJU_Rpt_ARAgingSp]
(#Slsman_Starting slsmantype = NULL,
#Slsman_Ending slsmantype = NULL,
#Custnum_Starting custnumtype = NULL,
#Custnum_Ending custnumtype = NULL,
#CustType endusertypetype = NULL,
#CutOff_Date datetype = NULL,
#SumToCorp ListYesNoType = NULL, -- >> 0 = individual, 1 = corp customer
#ShowActive ListYesNoType = NULL, -- >> 0 = all trx, 1 = active only
#TransDomCurr ListYesNoType = NULL, -- >> 0 = dont convert, 1 = convert to local currency
#AgingBasis ArAgeByType = NULL, -->> i = invoice date, d = due date
#LeftToRight ListYesNoType = NULL, -- >> 0 = right to left, 1 = left to right
#CurrSite NVARCHAR(8),
#ShowDetailInfo NVARCHAR(1) = NULL)
AS
BEGIN
SET NOCOUNT ON
IF ISNULL(#CurrSite ,'') = ''
SET #CurrSite = (SELECT TOP 1 site_ref FROM parms_mst)
DECLARE #v_StartDate DateType
SET #Slsman_Starting = ISNULL(#Slsman_Starting, dbo.LowCharacter())
SET #Slsman_Ending = ISNULL(#Slsman_Ending, dbo.HighCharacter())
SET #Custnum_Starting = ISNULL(#Custnum_Starting, dbo.LowCharacter())
SET #Custnum_Ending = ISNULL(#Custnum_Ending, dbo.HighCharacter())
SET #v_StartDate = dbo.LowDate()
SET #CutOff_Date = GETDATE()
EXEC dbo.ApplyDateOffsetSp #v_StartDate OUT, NULL, 0
EXEC AJU_Rpt_DebtorSp
#CustNumStart = #Custnum_Starting
,#CustNumEnd = #Custnum_Ending
,#DistDateStart = #v_StartDate
,#DistDateEnd = #CutOff_Date
,#CurrCodeStart = NULL
,#CurrCodeEnd = NULL
,#SlsmanStart = #Slsman_Starting
,#SlsmanEnd = #Slsman_Ending
,#TerritoryStart = NULL
,#TerritoryEnd = NULL
,#CustTypeStart = NULL
,#CustTypeEnd = NULL
,#SiteGroup = #CurrSite
,#ConsolidatePayment = NULL
,#DisplayResult = 1
END
Since the initial result table is temporarily needed, you could do as follows:
In the invoking procedure, create a table variable with identical structure as returned by the invoked procedure,
Write within the invoking procedure a statement like the following:
INSERT INTO #_Tempo_Table
EXEC Invoked_Procedure (<params>) ;
Within the invoked procedure issue a SELECT that will return the records set.
If, in the other hand, you need to pass the initial table to the invoked procedure:
Create a type with a structure identical to the table that needs to be shared,
Add to the invoked procedure an argument of the type you just created (must be declared as READONLY),
Once you have the table with data within the invoking procedure, make the call to the invoked procedure passing the table variable as argument.
This methods will render the best performance (here I'm assuming that you are not passing a table with millions of records; if you do, it will still be the fastest way though you might need a lot of memory).

Parameter coming with null value does not change when I change it in stored procedure

I have a stored procedure as shown below; when I pass NULL for Gkol I want it to be changed to the minimum possible amount (that exists in the table), but it does not happen - why is that?
ALTER PROCEDURE sp_vUnitsUnitTejariGetFilteredUnitDetail
(#UnitFB BIT,
#UnitWithCooking BIT,
#MMofidFrom FLOAT = NULL,
#MMofidTo FLOAT = NULL,
#GKolFrom FLOAT = NULL,
#GKolTo FLOAT = NULL)
AS
BEGIN
DECLARE #MMofidCalculative BIT
DECLARE #GKolCalculative BIT
IF (#MMofidFrom IS NULL)
SELECT #MMofidFrom = MIN(MMofid)
FROM vw_PSA_UnitsUnitTejari
IF (#MMofidTo IS NULL)
SELECT #MMofidTo = MAX(MMofid)
FROM vw_PSA_UnitsUnitTejari
IF (#GKolFrom IS NULL)
SELECT #GKolFrom = MIN(GKol)
FROM vw_PSA_UnitsUnitTejari
IF (#GKolTo IS NOT NULL)
SELECT #GKolTo = MAX(GKol)
FROM vw_PSA_UnitsUnitTejari
SELECT *
FROM vw_PSA_UnitsUnitTejari
WHERE UnitTypeID = 1
AND UnitStateID = 1
AND UnitFB = ISNULL(#UnitFB, UnitFB)
AND UnitWithCooking = ISNULL(#UnitWithCooking, UnitWithCooking)
AND MMofid BETWEEN #MMofidFrom AND #MMofidTo
AND GKol BETWEEN #GKolFrom AND #GKolTo
END
I figured out why it was not working, the problem was in the last if block
if(#GKolTo is not null)
I removed NOT and everything went well, thanks everyone

Oracle Triggers Update at Another Table

I am trying to create a trigger in Oracle. I know sql but i have never created trigger before. I have this code:
create or replace trigger "PASSENGER_BOOKING_T1"
AFTER
insert on "PASSENGER_BOOKING"
for each row
begin
IF (:NEW.CLASS_TYPE == 'ECO')
SELECT F.AVL_SEATS_ECOCLASS,F.FLIGHT_ID INTO SEAT, FLIGHT_INFO
FROM BOOKING B, JOURNEY_FLIGHT J, FLIGHT F
WHERE B.JOURNEY_ID = J.JOURNEY_ID and F.FLIGHT_ID = J.FLIGHT_ID;
UPDATE FLIGHT
SET AVL_SEATS_ECOCLASS = (SEAT-1)
WHERE FLIGHT_ID = FLIGHT_INFO;
END IF;
end;​
This trigger fires when there is an insert in Passenger_Booking table. And seating capacity is reduced by one (which is at different table).
Select query should be alright but there is something wrong in somewhere.
Could anyone suggest anything?
I changed the body part to this but still having issues:
UPDATE FLIGHT
SET AVL_SEATS_ECOCLASS =
(SELECT F.AVL_SEATS_ECOCLASS FROM BOOKING B, JOURNEY_FLIGHT J, FLIGHT F WHERE B.JOURNEY_ID = J.JOURNEY_ID and F.FLIGHT_ID = J.FLIGHT_ID;
);
An IF statement needs a THEN
In PL/SQL, you use an = to test for equality, not ==
You need to declare the variables that you are selecting into
When I do those three things, I get something like this
create or replace trigger PASSENGER_BOOKING_T1
AFTER insert on PASSENGER_BOOKING
for each row
declare
l_seat flight.seat%type;
l_flight_id flight.flight_id%type;
begin
IF (:NEW.CLASS_TYPE = 'ECO')
THEN
SELECT F.AVL_SEATS_ECOCLASS,F.FLIGHT_ID
INTO l_seat, l_flight_id
FROM BOOKING B,
JOURNEY_FLIGHT J,
FLIGHT F
WHERE B.JOURNEY_ID = J.JOURNEY_ID
and F.FLIGHT_ID = J.FLIGHT_ID;
UPDATE FLIGHT
SET AVL_SEATS_ECOCLASS = (l_seat-1)
WHERE FLIGHT_ID = l_flight_id;
END IF;
end;​
Beyond those syntax errors, I would be shocked if the SELECT INTO statement was correct. A SELECT INTO must return exactly 1 row. Your query should almost certainly return multiple rows since there are no predicates that would restrict the query to a particular flight or a particular booking. Presumably, you want to join to one or more columns in the PASSENGER_BOOKING table.
Additionally, if this is something other than a homework assignment, make sure you understand that this sort of trigger does not work correctly in a multi-user environment.
just a wild guess
edit as Justin pointed out (thanks Justin) equality check
create or replace trigger "PASSENGER_BOOKING_T1"
AFTER
insert on "PASSENGER_BOOKING"
for each row
declare
v_flight_id FLIGHT.FLIGHT_ID%TYPE;
begin
IF (:NEW.CLASS_TYPE = 'ECO') THEN
SELECT F.ID into v_flight_id
FROM BOOKING B, JOURNEY_FLIGHT J, FLIGHT F
WHERE B.ID = :NEW.BOOKING_ID -- note that I've made this up
AND B.JOURNEY_ID = J.JOURNEY_ID AND F.FLIGHT_ID = J.FLIGHT_ID;
UPDATE FLIGHT
SET AVL_SEATS_ECOCLASS = (SEAT-1)
WHERE ID = v_flight_id;
END IF;
end;​

Resources