You may be wondering why I'm writing about SQL code in a Delphi blog and also why I'm writing about Microsoft SQL if this blog series is entitle "ElevateDB: Stored Procedures Part XX".
Well, the answer is simple... I upgraded from Delphi 5 Enterprise to Delphi 2010 Professional. That in itself is a big jump. Furthermore, I want to create a Delphi database applications that uses an embedded database, and in this case I have chosen to use ElevateDB.
So, my goal is to create a very simple Delphi program that prints out an Amortization Schedule using Rave Reports that pulls the data from a database.
Because I'm blogging about how I am going about doing this, sort of creating a Programming Documentary or "Progumentary", wow I just made up a new word. See how this works.
Do I know how to use Rave Reports that comes with Delphi 2010? No, not yet. But I know if the data is in a database table I can more easily create that Rave Report.
Have I created the Delphi 2010 VCL form for gathering the data inputs needed? No, but I know I can do this and that part is coming later.
Do I know how to get the data into an ElevateDB database using a stored procedure? No. But I do know how to get the data into a MS SQL Database using a stored procedure and that is where this Pro-gu-mentary is right now.
ElevateDB comes with an ElevateDB Manager, which is a tool similar to Microsoft SQL Server Management Studio. It allows you to create databases, database objects and gives you a very robust query analyzer for performing all the necessary databse tasks.
I have decided to put all the code logic for creating this amortization schedule inside a stored procedure. This allows me to develop a stand alone module that I can test and measure outside of Delphi. I asked a question on SO about using a proc verus keeping the code in Delphi and received a few interesting responses. (Link to SO Question)
Because I know I can wire up a few simple controls on a Delphi VCL form and make "One" call to an ElevateDB stored procedure this is time well spent and code that will be used when the time comes.
So, after 6 plus hours of trying to get a similar stored procedure working in ElevateDB here is what I came up with:
---------------------------------------------------------------- -- SQL Amortization Schedule -- Copyright 2011 © By Michael J. Riley -- www.zilchworks.com ---------------------------------------------------------------- CREATE PROCEDURE "spAmortizationSchedule" ( IN "StartDate" DATE, IN "Principal" DECIMAL(19,2), IN "APR" DECIMAL(19,4), IN "Months" INTEGER ) BEGIN ---------------------------------------------------------------- -- VARIABLE DECLARATIONS USED FOR PROCESSING ---------------------------------------------------------------- DECLARE Payment decimal(19,2); DECLARE PaymentLast decimal(19,2); DECLARE PmtNumber int ; DECLARE PmtDate date ; DECLARE BalanceStart decimal(19,2); DECLARE PmtInterest decimal(19,2); DECLARE PmtPrincipal decimal(19,2); DECLARE BalanceEnd decimal(19,2); DECLARE SQLStatement Statement; DECLARE Result CURSOR WITH RETURN FOR Stmt; /* ---------------------------------------------------------------- -- TEST FOR NULL INPUTS ADD AT SOME POINT -- PSEUDO-CODE UNTIL I FIGURE OUT HOW TO DO THIS IN ELEVATDB ---------------------------------------------------------------- IF StartDate IS NULL THEN SET STARTDATE = Current_Date; IF Principal IS NULL THEN SET Principal = 190000; IF APR IS NULL THEN SET APR = 3.25; IF Months IS NULL THEN SET Months = 180; */ ---------------------------------------------------------------- -- EMPTY TABLE FOR NEW USE ---------------------------------------------------------------- EXECUTE IMMEDIATE 'EMPTY TABLE "TempAmortization"'; ---------------------------------------------------------------- -- CALCULATE MONTHLY PAYMENT BASED ON INPUT PARAMETERS -- THIS LINE IS LONG AND MAY WRAP MAKING IT HARD TO READ ---------------------------------------------------------------- SET Payment = ROUND(Principal * ((APR/1200)/(1- EXP((Months*-1) * LN(1 + (APR/1200))))) to 2); ---------------------------------------------------------------- -- INITALIZE VARIABLES BEFORE THE LOOP STARTS ---------------------------------------------------------------- SET PmtNumber = 0 ; SET BalanceEnd = Principal ; SET PmtDate = StartDate + INTERVAL '-1' MONTH; ---------------------------------------------------------------- -- PERFORM CALCULATIONS FOR ALL BUT LAST MONTH -- PmtDate column commented out. Need to get the proper syntax. ---------------------------------------------------------------- WHILE PmtNumber < Months -1 DO SET PmtNumber = PmtNumber +1; SET BalanceStart = BalanceEnd; SET PmtDate = PmtDate + INTERVAL '1' MONTH; SET PmtInterest = ROUND(BalanceStart * (APR/1200) to 2); SET PmtPrincipal = Payment - PmtInterest; SET BalanceEnd = BalanceStart - PmtPrincipal; EXECUTE IMMEDIATE ' INSERT INTO TempAmortization ( PmtNumber , -- PmtDate , PmtAmount , BalanceStart , PmtPrincipal , PmtInterest , BalanceEnd ) VALUES ( ' + CAST(PmtNumber as varchar(25)) + ' , -- ''' + CAST(PmtDate as varchar(25)) + ''' , ' + CAST(Payment as varchar(25)) + ' , ' + CAST(BalanceStart as varchar(25)) + ' , ' + CAST(PmtPrincipal as varchar(25)) + ' , ' + CAST(PmtInterest as varchar(25)) + ' , ' + CAST(BalanceEnd as varchar(25)) + ' ) '; END WHILE; ---------------------------------------------------------------- -- PERFORM CALCULATIONS FOR THE LAST MONTH AND -- PmtDate column commented out. Need to get the proper syntax. ---------------------------------------------------------------- SET PmtNumber = PmtNumber +1; SET BalanceStart = BalanceEnd; SET PmtDate = PmtDate + INTERVAL '1' MONTH; SET PmtInterest = ROUND(BalanceStart * (APR/1200) to 2); SET PaymentLast = BalanceStart + PmtInterest; SET PmtPrincipal = BalanceStart; SET BalanceEnd = BalanceStart + PmtInterest - PaymentLast; EXECUTE IMMEDIATE ' INSERT INTO TempAmortization ( PmtNumber , --PmtDate , PmtAmount , BalanceStart , PmtPrincipal , PmtInterest , BalanceEnd ) VALUES ( ' + CAST(PmtNumber as varchar(25)) + ' , --''' + CAST(PmtDate as varchar(25)) + ''' , ' + CAST(PaymentLast as varchar(25)) + ' , ' + CAST(BalanceStart as varchar(25)) + ' , ' + CAST(PmtPrincipal as varchar(25)) + ' , ' + CAST(PmtInterest as varchar(25)) + ' , ' + CAST(BalanceEnd as varchar(25)) + ' ) '; ---------------------------------------------------------------- -- RETURN RESULTS FROM TEMPORARY TABLE ---------------------------------------------------------------- PREPARE Stmt FROM ' SELECT PmtNumber , PmtDate , PmtAmount , BalanceStart , PmtPrincipal , PmtInterest , BalanceEnd FROM TempAmortization '; OPEN Result; END VERSION 1.00! ----------------------------------------------------------------It's crude, it works, except for the PmtDate column but at least I knew enough to comment out just that one portion. There are some things I had to do differently from the original MS SSQL Stored Proc:
- Had to skip error trapping the input parameters becaue I don't know how to set default values
- Had to used to use a real table instead of a temp table because I kept getting errors saying the temp table already exists for this session, bla bla bla
- Had to comment out the Payment Date column because I could not figure out the proper syntax even thought I thought I had worked that out with the ElevateDB Date Math stuff. I'll have to revisit ElevateDB Date Math at a later time
Michael,
<< I'm new to ElevateDB coming from a Microsoft SQL background. Roy suggested I whip up an example of a Microsoft Stored procedure that I'd like to get converted over to ElevateDB and post it to the forum. >>
I know that you've already got this done, but here's an optimal version for EDB:
CODE GOES HERE
(I'll share his code in a future post)
How cool is that. I got the guy who created ElevateDB to whip up an optimized version of the stored proc I needed. The proc I wrote in MS SQL is filled with little nuggets that can be used over and over again in other stored procs. There's alot going on in there. For example:
- Use of defaults for input paramters
- Use of temp table for storing temporary data
- A date math routine that increments a date by one month
- Use of a While loop
- Selection of the final result set
Semper Fi,
Gunny Mike
< Prev | Next > |
No comments:
Post a Comment