Oracle SQL: Use outer loop identifiers in inner loop in execute immediate - sql
I have to execute 32 times a very similar operation, that is setting the value of a column in a row for a given record (for a given quarter).
To simplify my code and thrive for beauty, I wanted to use a for loop with an execute immediate, using I_cnt to dynamically set the column name in the statement.
I am using Oracle 10g.
When I call the procedure, Oracle returns
SQL Error: ORA-00904: "REC"."QUARTER_MEL": niepoprawny identyfikator
ORA-06512: przy "LREBIRT.P_PFPL_RISKPROFILE_TEST", linia 55
00904. 00000 - "%s: invalid identifier"
When I call the procedure below, v_risk_volume and v_risk_amount are correctly calculated, it fails to execute immediate my statement.
The code of my procedure:
PROCEDURE CALCULATE_RESULT_TABLE AS
v_risk_volume float;
v_risk_amount float;
v_sql varchar2(1000);
BEGIN
for rec in (select * from PFPL_RISKPROFILE_BASIS_TEST)
LOOP
for i_cnt in 1..32
LOOP
DBMS_OUTPUT.PUT_LINE(rec.quarter_mel);
select Q_VOLUME, Q_AMOUNT into v_risk_volume, v_risk_amount from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = i_cnt;
DBMS_OUTPUT.PUT_LINE(v_risk_volume);
DBMS_OUTPUT.PUT_LINE(v_risk_amount);
v_sql := 'update PFPL_RISKPROFILE_RES_TEST t set Q_'||i_cnt||'_volume = v_risk_volume/rec.Q_VOLUME, Q_'||i_cnt||'_amount = v_risk_amount/rec.Q_AMOUNT where t.QUARTER_MEL = rec.QUARTER_MEL';
DBMS_OUTPUT.PUT_LINE(v_sql);
EXECUTE IMMEDIATE v_sql;
END LOOP;
END LOOP;
END CALCULATE_RESULT_TABLE;
The result of the dbms_output:
1-2012
7
448787,05
update PFPL_RISKPROFILE_RES_TEST t set Q_1_volume = v_risk_volume/rec.Q_VOLUME, Q_1_amount = v_risk_amount/rec.Q_AMOUNT where t.QUARTER_MEL = rec.QUARTER_MEL
Current version of the procedure after previous corrections:
PROCEDURE CALCULATE_RESULT_TABLE AS
v_risk_volume float;
v_risk_amount float;
v_sql varchar2(1000);
BEGIN
for rec in (select * from PFPL_RISKPROFILE_BASIS_TEST)
LOOP
DBMS_OUTPUT.PUT_LINE(rec.quarter_mel);
for i_cnt in 1..32
LOOP
DBMS_OUTPUT.PUT_LINE(i_cnt);
DBMS_OUTPUT.PUT_LINE(rec.quarter_mel);
select Q_VOLUME, Q_AMOUNT into v_risk_volume, v_risk_amount from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = i_cnt;
if rec.Q_volume > 0 then v_risk_volume := round(v_risk_volume/rec.Q_volume,4); else v_risk_volume := 0; end if;
if rec.Q_amount > 0 then v_risk_amount := round(v_risk_amount/rec.Q_amount,4); else v_risk_amount := 0; end if;
v_sql := 'update PFPL_RISKPROFILE_RES_TEST t set Q_'||i_cnt||'_volume = :v, Q_'||i_cnt||'_amount = :a where t.QUARTER_MEL = :q';
DBMS_OUTPUT.PUT_LINE(v_sql);
EXECUTE IMMEDIATE v_sql USING v_risk_volume, v_risk_amount, rec.quarter_mel;
END LOOP;
END LOOP;
END CALCULATE_RESULT_TABLE;
Hello again, I tried what Jeff proposed, but I still have a problem, and it's really ugly, I almost cried writing the code - I did it for 10 quarters, I still need to paste the missing 22 quarters. Now the procedure treated two of the four rows of the loop.
PROCEDURE CALCULATE_RESULT_TABLE AS
v_risk_volume_1 FLOAT;
v_risk_volume_2 FLOAT;
v_risk_volume_3 FLOAT;
v_risk_volume_4 FLOAT;
v_risk_volume_5 FLOAT;
v_risk_volume_6 FLOAT;
v_risk_volume_7 FLOAT;
v_risk_volume_8 FLOAT;
v_risk_volume_9 FLOAT;
v_risk_volume_10 FLOAT;
v_risk_amount_1 FLOAT;
v_risk_amount_2 FLOAT;
v_risk_amount_3 FLOAT;
v_risk_amount_4 FLOAT;
v_risk_amount_5 FLOAT;
v_risk_amount_6 FLOAT;
v_risk_amount_7 FLOAT;
v_risk_amount_8 FLOAT;
v_risk_amount_9 FLOAT;
v_risk_amount_10 FLOAT;
BEGIN
for rec in (select * from PFPL_RISKPROFILE_BASIS_TEST order by quarter_mel)
LOOP
DBMS_OUTPUT.PUT_LINE(rec.quarter_mel);
select Q_VOLUME, Q_AMOUNT into v_risk_volume_1, v_risk_amount_1 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 1;
if rec.Q_volume > 0 then v_risk_volume_1 := round(v_risk_volume_1/rec.Q_volume,4); else v_risk_volume_1 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_1 := round(v_risk_amount_1/rec.Q_amount,4); else v_risk_amount_1 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_2, v_risk_amount_2 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 2;
if rec.Q_volume > 0 then v_risk_volume_2 := round(v_risk_volume_2/rec.Q_volume,4); else v_risk_volume_2 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_2 := round(v_risk_amount_2/rec.Q_amount,4); else v_risk_amount_2 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_3, v_risk_amount_3 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 3;
if rec.Q_volume > 0 then v_risk_volume_3 := round(v_risk_volume_3/rec.Q_volume,4); else v_risk_volume_3 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_3 := round(v_risk_amount_3/rec.Q_amount,4); else v_risk_amount_3 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_4, v_risk_amount_4 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 4;
if rec.Q_volume > 0 then v_risk_volume_4 := round(v_risk_volume_4/rec.Q_volume,4); else v_risk_volume_4 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_4 := round(v_risk_amount_4/rec.Q_amount,4); else v_risk_amount_4 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_5, v_risk_amount_5 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 5;
if rec.Q_volume > 0 then v_risk_volume_5 := round(v_risk_volume_5/rec.Q_volume,4); else v_risk_volume_5 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_5 := round(v_risk_amount_5/rec.Q_amount,4); else v_risk_amount_5 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_6, v_risk_amount_6 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 6;
if rec.Q_volume > 0 then v_risk_volume_6 := round(v_risk_volume_6/rec.Q_volume,4); else v_risk_volume_6 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_6 := round(v_risk_amount_6/rec.Q_amount,4); else v_risk_amount_6 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_7, v_risk_amount_7 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 7;
if rec.Q_volume > 0 then v_risk_volume_7 := round(v_risk_volume_7/rec.Q_volume,4); else v_risk_volume_7 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_7 := round(v_risk_amount_7/rec.Q_amount,4); else v_risk_amount_7 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_8, v_risk_amount_8 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 8;
if rec.Q_volume > 0 then v_risk_volume_8 := round(v_risk_volume_8/rec.Q_volume,4); else v_risk_volume_8 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_8 := round(v_risk_amount_8/rec.Q_amount,4); else v_risk_amount_8 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_9, v_risk_amount_9 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 9;
if rec.Q_volume > 0 then v_risk_volume_9 := round(v_risk_volume_9/rec.Q_volume,4); else v_risk_volume_9 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_9 := round(v_risk_amount_9/rec.Q_amount,4); else v_risk_amount_9 := 0; end if;
select Q_VOLUME, Q_AMOUNT into v_risk_volume_10, v_risk_amount_10 from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter = 10;
if rec.Q_volume > 0 then v_risk_volume_10 := round(v_risk_volume_10/rec.Q_volume,4); else v_risk_volume_10 := 0; end if;
if rec.Q_volume > 0 then v_risk_amount_10 := round(v_risk_amount_10/rec.Q_amount,4); else v_risk_amount_10 := 0; end if;
update PFPL_RISKPROFILE_RES_TEST set
Q_1_volume = v_risk_volume_1,
Q_2_volume = v_risk_volume_2,
Q_3_volume = v_risk_volume_3,
Q_4_volume = v_risk_volume_4,
Q_5_volume = v_risk_volume_5,
Q_6_volume = v_risk_volume_6,
Q_7_volume = v_risk_volume_7,
Q_8_volume = v_risk_volume_8,
Q_9_volume = v_risk_volume_9,
Q_10_volume = v_risk_volume_10 where quarter_mel = rec.quarter_mel;
update PFPL_RISKPROFILE_RES_TEST set
Q_1_amount = v_risk_amount_1,
Q_2_amount = v_risk_amount_2,
Q_3_amount = v_risk_amount_3,
Q_4_amount = v_risk_amount_4,
Q_5_amount = v_risk_amount_5,
Q_6_amount = v_risk_amount_6,
Q_7_amount = v_risk_amount_7,
Q_8_amount = v_risk_amount_8,
Q_9_amount = v_risk_amount_9,
Q_10_amount = v_risk_amount_10 where quarter_mel = rec.quarter_mel;
END LOOP;
END CALCULATE_RESULT_TABLE;
v_sql := 'update PFPL_RISKPROFILE_RES_TEST t set Q_'||i_cnt||'_volume = v_risk_volume/rec.Q_VOLUME, Q_'||i_cnt||'_amount = v_risk_amount/rec.Q_AMOUNT where t.QUARTER_MEL = rec.QUARTER_MEL';
You are not passing the variable value here. You need to use bind variables and USING clause in the EXECUTE IMMEDIATE to refer the bind values..
You need to do it as:
v_sql := 'update PFPL_RISKPROFILE_RES_TEST t set Q_'||i_cnt||'_volume = :v_risk_volume/rec.Q_VOLUME, Q_'||i_cnt||'_amount = :v_risk_amount/:rec.Q_AMOUNT where t.QUARTER_MEL = rec.QUARTER_MEL';
execute immediate v_sql using v_risk_volume, v_risk_amount, rec.Q_AMOUNT
So, I finally found the cause of the last error and I'd like to compile here the different elements of the answer.
The first error was that using EXECUTE IMMEDIATE, the sql executed should not include any references, I replaced by bind variables and it was ok.
The second error was that while the inner cursor goes from 1..32, there were not necessarily values to select into v_risk_volume and v_risk_amount for all the 32 iterations, and the procedure crashed at the first iteration where the select ... into ... returned nothing.
So I changed the logic, putting the inner cursor on the table that was in the select ... into ... statement, and now it runs perfectly. I'm quite happy with this solution, it does the job with minimum code and as the maximum number of records treated is something like 1024 the performances are totally acceptable.
The final code of this procedure:
PROCEDURE CALCULATE_RESULT_TABLE AS
v_risk_volume float;
v_risk_amount float;
v_i_volume varchar2(30);
v_i_amount varchar2(30);
v_sql varchar2(1000);
BEGIN
for rec in (select * from PFPL_RISKPROFILE_RES_TEST)
LOOP
DBMS_OUTPUT.PUT_LINE(rec.quarter_mel);
NULL;
for i in (select * from PFPL_RISKPROFILE_CDR_Q_TEST where quarter_mel = rec.quarter_mel and quarter between 1 and 32 order by quarter)
LOOP
if rec.Q_volume > 0 then v_risk_volume := round(i.Q_VOLUME/rec.Q_volume,4); else v_risk_volume := 0; end if;
if rec.Q_amount > 0 then v_risk_amount := round(i.Q_AMOUNT/rec.Q_amount,4); else v_risk_amount := 0; end if;
v_i_volume := 'Q_'||i.quarter||'_volume';
v_i_amount := 'Q_'||i.quarter||'_amount';
v_sql := 'update PFPL_RISKPROFILE_RES_TEST t set '||v_i_volume||' = :v, '||v_i_amount||' = :a where t.QUARTER_MEL = :q';
EXECUTE IMMEDIATE v_sql USING v_risk_volume, v_risk_amount, rec.quarter_mel;
END LOOP;
END LOOP;
END CALCULATE_RESULT_TABLE;
Related
ORA-06502: PL/SQL: numeric or value error: character string buffer too small only three numbers
create or replace FUNCTION "FNC_CALCULATE_MOD11" (P_VALOR IN NUMBER) return number is Result number; begin DECLARE -- LOCAL VARIABLES HERE V_PROCESSO VARCHAR2(30); V_PESO NUMBER := 2; V_SOMA NUMBER := 0; V_RESTO NUMBER := 0; BEGIN V_PROCESSO := TO_CHAR(P_VALOR); WHILE LENGTH(V_PROCESSO) < 6 --Popular com zeros no inicio até 6 LOOP V_PROCESSO := '0'||V_PROCESSO; END LOOP; --accuses error on this line FOR I IN REVERSE 1 .. LENGTH(V_PROCESSO) LOOP V_SOMA := TO_CHAR (V_SOMA) + TO_NUMBER(SUBSTR(V_PROCESSO,i,1))*V_PESO; IF V_PESO = 9 THEN --repetir peso se for necessario V_PESO := 2; ELSE V_PESO := V_PESO + 1; END IF; END LOOP; V_RESTO := MOD(V_SOMA, 11); Result := 11 - V_RESTO; IF ((Result = 0) OR (Result = 1) OR (Result >= 10)) THEN Result := 1; END IF; END; return(Result); end FNC_CALCULATE_MOD11;
Try to change V_PROCESSO to a bigger size, for example V_PROCESSO VARCHAR2(300);
Getting debug error "; expected" after adding new ifclause to procedure
After adding the ifclause for Art to a MasterReport to multiple the Netto total by -1 for get a -ve result in the credit invoice, I am getting a ; expected with the error indicator jumping to the procedure after it. Image of Error Message It's likely a very stupid error but I can't wrap my head around the problem at the moment. Commenting the new ifclause out will resolve the issue so it's something with that. procedure FooterSR1OnBeforePrint(Sender: TfrxComponent); begin if ( <frxdsqryKopfdaten."MwStNichtAusweisbar"> = 0 ) then mmoBrutto.Memo.Text := FormatFloat('#,##0.00', EndBrutto ) + ' ' + <frxdsqryKopfdaten."CurrencyString"> else mmoBrutto.Memo.Text := FormatFloat('#,##0.00', EndNetto ) + ' ' + <frxdsqryKopfdaten."CurrencyString">; end; procedure Hauptkopf1OnBeforePrint(Sender: TfrxComponent); begin if (<frxdsqryArt."Art"> = 'Gutschrift') then begin EndNetto := EndNetto * (-1) end else begin EndNetto := EndNetto; end; end; begin mmoNetto.Memo.Text := FormatFloat('#,##0.00', EndNetto ) + ' ' + frxdsqryKopfdaten."CurrencyString"> end; procedure BandBankOnBeforePrint(Sender: TfrxComponent); begin if <frxdsqryFirma."Bank1"> <> '' then mmoBank.Visible := False else mmoBank.Visible := FALSE; if <frxdsqryFirma."IBAN1"> <> '' then begin mmoIBAN.Visible := FALSE; mmoBank.Visible := FALSE; mmoBank.Height := 0 end else begin mmoIBAN.Visible := FALSE; mmoBank.Visible := FALSE; end; end;
This is wrong (4× begin, but only 3× end): procedure Hauptkopf1OnBeforePrint(Sender: TfrxComponent); begin if (<frxdsqryArt."Art"> = 'Gutschrift') then begin EndNetto := EndNetto * (-1) end else begin EndNetto := EndNetto; end; end; begin mmoNetto.Memo.Text := FormatFloat('#,##0.00', EndNetto ) + ' ' + frxdsqryKopfdaten."CurrencyString"> end; Your probably wanted this (but hard to say): procedure Hauptkopf1OnBeforePrint(Sender: TfrxComponent); begin if (<frxdsqryArt."Art"> = 'Gutschrift') then begin EndNetto := EndNetto * (-1) end else begin EndNetto := EndNetto; end; end; mmoNetto.Memo.Text := FormatFloat('#,##0.00', EndNetto ) + ' ' + frxdsqryKopfdaten."CurrencyString"> end;
Change color of text in a TStringGrid cell
How can I change the color of text in a TStringGrid cell depending on certain conditions? I am using TStringGrid to display a monthly calendar view on a form and I'm populating the TStringGrid with days of the month in certain rows and columns, with days of the week as column headings. I'm also populating the TStringGrid with job work orders for certain dates that are based on entries in a database. So I'm using the DrawCell event to display the content in the TStringGrid. Certain jobs are recurring jobs and other jobs are one offs. I'd like the recurring jobs to appear in one color and the one offs in another. Is this possible, and/or should I be using a different component to accomplish this task? I assume it's not possible to have two different text colors in the same cell. type TCalendarView2 = class(TForm) CalViewStringGrid: TStringGrid; NextBtn: TButton; PrevBtn: TButton; MonthLabel1: TLabel; CloseBtn: TButton; procedure OnShow(Sender: TObject); procedure CalViewStringGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); procedure NextBtnClick(Sender: TObject); procedure PrevBtnClick(Sender: TObject); procedure CloseBtnClick(Sender: TObject); private { Private declarations } FDateTime: TDateTime; FDay: Word; EndDate, StartDay: TDateTime; // selected date so we know what month the calendar is for iNumDays, iDay: Integer; // Holds the number of days for a given month procedure FillWithWorkOrders; procedure UpdateRowHeights; public { Public declarations } MyDate : TDateTime; end; var CalendarView2: TCalendarView2; implementation {$R *.dfm} uses POEData; procedure TCalendarView2.OnShow(Sender: TObject); var wYear, wMonth: Word; begin FDateTime := Date; // Extract the month, day and year for the current date DecodeDate (FDateTime, wYear, wMonth, FDay); MonthLabel1.Caption := FormatSettings.LongMonthNames[wMonth] + ' ' + IntToStr(wYear); FillWithWorkOrders; end; procedure TCalendarView2.CloseBtnClick(Sender: TObject); begin CalendarView2.Close; end; procedure TCalendarView2.CalViewStringGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); var s, ds, sDay, WorkOrder, WorkOrders: string; dd, idx: integer; dtDate: TDateTime; SerType, WoNum, ETips: string; bIsToday: boolean; begin s := CalViewStringGrid.Cells[ACol, ARow]; Inc(Rect.Left, 2); Inc(Rect.Top, 2); if (gdFixed in State) then begin CalViewStringGrid.Canvas.Brush.Color := CalViewStringGrid.FixedColor; CalViewStringGrid.Canvas.Font.Color := CalViewStringGrid.Font.Color; CalViewStringGrid.Canvas.FillRect(Rect); CalViewStringGrid.Canvas.TextRect(Rect, Rect.Left, Rect.Top, s); Exit; end; idx := Pos(#10, s); if idx <> 0 then begin sDay := Copy(s, 1, idx-1); WorkOrders := Copy(s, idx+1, MaxInt); end else begin ds := s; WorkOrders := ''; end; if sDay <> '' then begin dd := StrToIntDef(sDay, 0); dtDate := Date; bIsToday := (MonthOf(dtDate) = MonthOf(FDateTime)) and (DayOf(dtDate) = dd); end else begin bIsToday := False; end; if bIsToday then begin CalViewStringGrid.Canvas.Brush.Color := clSkyBlue; CalViewStringGrid.Canvas.Font.Color := clBlue; end; begin CalViewStringGrid.Canvas.Brush.Color := CalViewStringGrid.Color; CalViewStringGrid.Canvas.Font.Color := CalViewStringGrid.Font.Color; end; CalViewStringGrid.Canvas.FillRect(Rect); CalViewStringGrid.Canvas.TextRect(Rect, Rect.Left, Rect.Top, sDay); if (WorkOrders = '') then Exit; Inc(Rect.Top, CalViewStringGrid.Canvas.TextHeight(sDay) + 2); repeat idx := Pos(#10, WorkOrders); if idx <> 0 then begin WorkOrder := Copy(WorkOrders, 1, idx-1); WorkOrders := Copy(WorkOrders, idx+1, MaxInt); end else begin WorkOrder := WorkOrders; WorkOrders := ''; end; s := WorkOrder; idx := Pos('-', s); ETips := Copy(s, 1, idx-1); s := Copy(s, idx+1, MaxInt); idx := Pos('-', s); SerType := Copy(s, 1, idx-1); s := Copy(s, idx+1, MaxInt); WoNum := s; if bIsToday then begin CalViewStringGrid.Canvas.Brush.Color := clSkyBlue; //CalViewStringGrid.Font.Color := clBlue; end else if SerType = 'R' then begin CalViewStringGrid.Canvas.Font.Color := clRed; end else if SerType = 'P' then begin CalViewStringGrid.Canvas.Font.Color := clBlue; end else if SerType = 'S' then begin CalViewStringGrid.Canvas.Font.Color := clGreen; end else if SerType = 'N' then begin CalViewStringGrid.Canvas.Font.Color := clBlack; end; begin CalViewStringGrid.Canvas.Font.Color := CalViewStringGrid.Font.Color; end; CalViewStringGrid.Canvas.TextRect(Rect, Rect.Left, Rect.Top, WorkOrder); Inc(Rect.Top, CalViewStringGrid.Canvas.TextHeight(WorkOrder) + 2); until WorkOrders = ''; // CalViewStringGrid.Canvas.Font.Color := clBlack; end; procedure TCalendarView2.FillWithWorkOrders; const days: array[0..6] of String = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'); var X, Y, i, DateSW, RotType, PurType, SheType, SW, iNumDays: Integer; dtTime, StartDay, EndDate: TDateTime; SerType, WoNum, CoName, SCity, ETips, s: string; wDay: Word; WorkOrders: array[1..31] of String; begin RotType := 0; PurType := 0; SheType := 0; SW := 0; // This section displays the abbreviated day of the week in each cell in the first row, // and clears out cell info just in case any data was left over from before for i := 0 to 6 do begin CalViewStringGrid.Cells[i, 0] := days[i]; CalViewStringGrid.Cells[i, 1] := ''; CalViewStringGrid.Cells[i, 2] := ''; CalViewStringGrid.Cells[i, 3] := ''; CalViewStringGrid.Cells[i, 4] := ''; CalViewStringGrid.Cells[i, 5] := ''; CalViewStringGrid.Cells[i, 6] := ''; end; // Gets the number of days for the current month iNumDays := DaysInMonth(FDateTime); // The next two lines initialize the variables the first time through if DateSW = 0 then begin StartDay := FDateTime - FDay; EndDate := EndOfTheMonth(FDateTime); end; DateSW := 1; //Generate and open the ToBeSchedGrid Query POE_Data.ToBeSchedGrid.Close; POE_Data.ToBeSchedGrid.Sql.Clear; POE_Data.ToBeSchedGrid.Sql.Add('SELECT DISTINCT D.WorkOrder, D.CustID, D.OpID, D.EnteredDate, D.EnteredTime, D.EstServiceDate, D.Status, D.EstBoxes, D.Truck, D.EstTips, D.ServiceDesc, D.Zone, D1.CompanyName, D1.Contact, D1.SContact1, D1.SPhone1, D1.SCity'); POE_Data.ToBeSchedGrid.Sql.Add('FROM ":Shred:WorkOrdersIn.DB" D, ":Shred:Customer.DB" D1'); POE_Data.ToBeSchedGrid.Sql.Add('WHERE (D.EstServiceDate > "' + DateToStr(StartDay) + '")'); POE_Data.ToBeSchedGrid.Sql.Add('AND (D.EstServiceDate <= "' + DateToStr(EndDate) + '")'); POE_Data.ToBeSchedGrid.Sql.Add('AND (D1.CustID = D.CustID)'); POE_Data.ToBeSchedGrid.Sql.Add('AND (D.Status <> "Cancelled")'); POE_Data.ToBeSchedGrid.Sql.Add('ORDER BY D.EstServiceDate'); // Save this Query to a text file for debugging purposes POE_Data.ToBeSchedGrid.Sql.SaveToFile('c:\PolarQBE\WorkOrdersIn.txt'); POE_Data.ToBeSchedGrid.Open; // populate each day's Work Orders While NOT POE_Data.ToBeSchedGrid.EOF do begin dtTime := POE_Data.ToBeSchedGridEstServiceDate.AsDateTime; SerType := POE_Data.ToBeSchedGridServiceDesc.AsString; WoNum := POE_Data.ToBeSchedGridWorkOrder.AsString; SCity := POE_Data.ToBeSchedGridSCity.AsString; ETips := POE_Data.ToBeSchedGridEstTips.AsString; if ETips = '' then ETips := '0'; CoName := POE_Data.ToBeSchedGridCompanyName.AsString; if SerType = 'Route' then Inc(RotType); if SerType = 'Purge' then Inc(PurType); if SerType = 'Shred Event' then Inc(SheType); //wDay := DayOfTheMonth(FDateTime); wDay := DayOfTheMonth(dtTime); //WorkOrders[wDay] := WorkOrders[wDay] + ETips + '-' + Copy(CoName,1,11) + '-' + Copy(SCity,1,8) + '-' + Copy(SerType,1,1) + '-' + WoNum + #10; WorkOrders[wDay] := WorkOrders[wDay] + ETips + '-' + Copy(SerType,1,1) + '-' + WoNum + #10; POE_Data.ToBeSchedGrid.Next; end; // Initialize the Row and Column counters Y := 1; X := DayOfWeek(StartOfTheMonth(FDateTime)- 1); if X > 6 then X := (X div 6) - 1; for i := 1 to iNumDays do begin s := IntToStr(i); if WorkOrders[i] <> '' then begin s := s + #10 + WorkOrders[i]; end; CalViewStringGrid.Cells[X, Y] := s; // increment the column counter Inc(X); // if the column counter is greater than 6 reset back to 0. if X > 6 then begin X := 0; Inc(Y); end; end; UpdateRowHeights; end; procedure TCalendarView2.UpdateRowHeights; var X, Y, TxtHeight: Integer; MaxHeight: Integer; R: TRect; begin // This next line seems to really control the height of the rows CalViewStringGrid.Canvas.Font.Size := 8; for Y := CalViewStringGrid.FixedRows to CalViewStringGrid.RowCount - 1 do begin MaxHeight := CalViewStringGrid.DefaultRowHeight - 4; for X := CalViewStringGrid.FixedCols to CalViewStringGrid.ColCount - 1 do begin R := Rect(0, 0, CalViewStringGrid.ColWidths[X] - 4, 0); TxtHeight := DrawText(CalViewStringGrid.Canvas.Handle, PChar(CalViewStringGrid.Cells[X, Y]), -1, R, DT_WORDBREAK or DT_CALCRECT); if TxtHeight > MaxHeight then MaxHeight := TxtHeight; end; // 11/18/2015 - was = AGrid.RowHeights[Y] := MaxHeight + 4; CalViewStringGrid.RowHeights[Y] := MaxHeight + 1; end; end;
Yes, it is possible to use multiple colors in a single cell. Since you are already using the TStringGrid.OnDrawCell event to draw the cells yourself, simply extend your drawing logic to include per-job text colors. All you have to do is assign the TStringGrid.Canvas.Font.Color property before drawing a job's text onto the TStringGrid.Canvas. You just need to expose a way for your OnDrawCell handler to know when a given job is recurring or not, so it can assign the appropriate color before drawing that job's text. Update: Try something more like this instead: type TCalViewForm = class(TForm) CalViewStringGrid: TStringGrid; procedure OnShow(Sender: TObject); procedure CalViewStringGridDrawCell(Sender: TObject; ACol, private FDateTime: TDateTime; FDay: Word; procedure FillWithWorkOrders; procedure UpdateRowHeights; end; ... procedure TCalViewForm.OnShow(Sender: TObject); var wYear, wMonth: Word; begin FDateTime := Date; // Extract the month, day and year for the current date DecodeDate (FDateTime, wYear, wMonth, FDay); MonthLabel.Caption := FormatSettings.LongMonthNames[wMonth] + ' ' + IntToStr(wYear); FillWithWorkOrders; end; procedure TCalViewForm.FillWithWorkOrders; const days: array[0..6] = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'); var X, Y, i, DateSW: Integer; dtTime: TDateTime; SerType, WoNum, CoName, SCity, ETips, s: string; wDay: Word; WorkOrders: array[1..31] of String; begin RotType := 0; PurType := 0; SheType := 0; SW := 0; // This section displays the abbreviated day of the week in each cell in the first row, // and clears out cell info just in case any data was left over from before for i := 0 to 6 do begin CalViewStringGrid.Cells[i, 0] := days[i]; CalViewStringGrid.Cells[i, 1] := ''; CalViewStringGrid.Cells[i, 2] := ''; CalViewStringGrid.Cells[i, 3] := ''; CalViewStringGrid.Cells[i, 4] := ''; CalViewStringGrid.Cells[i, 5] := ''; CalViewStringGrid.Cells[i, 6] := ''; end; // Gets the number of days for the current month iNumDays := DaysInMonth(FDateTime); // The next two lines initialize the variables the first time through if DateSW = 0 then begin StartDay := FDateTime - FDay; EndDate := EndOfTheMonth(FDateTime); end; DateSW := 1; //Generate and open the ToBeSchedGrid Query POE_Data.ToBeSchedGrid.Close; POE_Data.ToBeSchedGrid.Sql.Clear; POE_Data.ToBeSchedGrid.Sql.Add('SELECT DISTINCT D.WorkOrder, D.CustID, D.OpID, D.EnteredDate, D.EnteredTime, D.EstServiceDate, D.Status, D.EstBoxes, D.Truck, D.EstTips, D.ServiceDesc, D.Zone, D1.CompanyName, D1.Contact, D1.SContact1, D1.SPhone1, D1.SCity'); POE_Data.ToBeSchedGrid.Sql.Add('FROM ":Shred:WorkOrdersIn.DB" D, ":Shred:Customer.DB" D1'); POE_Data.ToBeSchedGrid.Sql.Add('WHERE (D.EstServiceDate > "' + DateToStr(StartDay) + '")'); POE_Data.ToBeSchedGrid.Sql.Add('AND (D.EstServiceDate <= "' + DateToStr(EndDate) + '")'); POE_Data.ToBeSchedGrid.Sql.Add('AND (D1.CustID = D.CustID)'); POE_Data.ToBeSchedGrid.Sql.Add('AND (D.Status <> "Cancelled")'); POE_Data.ToBeSchedGrid.Sql.Add('ORDER BY D.EstServiceDate'); // Save this Query to a text file for debugging purposes POE_Data.ToBeSchedGrid.Sql.SaveToFile('c:\PolarQBE\WorkOrdersIn.txt'); POE_Data.ToBeSchedGrid.Open; // populate each day's Work Orders While NOT POE_Data.ToBeSchedGrid.EOF do begin dtTime := POE_Data.ToBeSchedGridEstServiceDate.AsDateTime; SerType := POE_Data.ToBeSchedGridServiceDesc.AsString; WoNum := POE_Data.ToBeSchedGridWorkOrder.AsString; SCity := POE_Data.ToBeSchedGridSCity.AsString; ETips := POE_Data.ToBeSchedGridEstTips.AsString; if ETips = '' then ETips := '0'; CoName := POE_Data.ToBeSchedGridCompanyName.AsString; if SerType = 'Route' then Inc(RotType); if SerType = 'Purge' then Inc(PurType); if SerType = 'Shred Event' then Inc(SheType); wDay := DayOfTheMonth(dtTime); //WorkOrders[wDay] := WorkOrders[wDay] + ETips + '-' + Copy(CoName,1,11) + '-' + Copy(SCity,1,8) + '-' + Copy(SerType,1,1) + '-' + WoNum + #10; WorkOrders[wDay] := WorkOrders[wDay] + ETips + '-' + Copy(SerType,1,1) + '-' + WoNum + #10; POE_Data.ToBeSchedGrid.Next; end; // Initialize the Row and Column counters Y := 1; X := DayOfWeek(StartOfTheMonth(FDateTime)- 1); if X > 6 then X := (X div 6) - 1; for i := 1 to iNumDays do begin s := IntToStr(i); if WorkOrders[i] <> '' then begin s := s + #10 + WorkOrders[i]; end; CalViewStringGrid.Cells[X, Y] := s; // increment the column counter Inc(X); // if the column counter is greater than 6 reset back to 0. if X > 6 then begin X := 0; Inc(Y); end; end; UpdateRowHeights; end; procedure TCalViewForm.CalViewStringGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); var s, sDay, WorkOrder, WorkOrders: string; dd, idx: integer; dtDate: TDateTime; SerType, WoNum, ETips: string; bIsToday: boolean; begin s := CalViewStringGrid.Cells[ACol, ARow]; Inc(Rect.Left, 2); Inc(Rect.Top, 2); if (gdFixed in State) then begin CalViewStringGrid.Canvas.Brush.Color := CalViewStringGrid.FixedColor; CalViewStringGrid.Canvas.Font.Color := CalViewStringGrid.Font.Color; CalViewStringGrid.Canvas.FillRect(Rect); CalViewStringGrid.Canvas.TextRect(Rect, Rect.Left, Rect.Top, s); Exit; end; idx := Pos(#10, s); if idx <> 0 then begin sDay := Copy(s, 1, idx-1); WorkOrders := Copy(s, idx+1, MaxInt); end else begin sDay := s; WorkOrders := ''; end; if sDay <> '' then begin dd := StrToIntDef(sDay, 0); dtDate := Date; bIsToday := (MonthOf(dtDate) = MonthOf(FDateTime)) and (DayOf(dtDate) = dd); end else begin bIsToday := False; end; if bIsToday then begin CalViewStringGrid.Canvas.Brush.Color := clSkyBlue; CalViewStringGrid.Canvas.Font.Color := clBlue; end begin CalViewStringGrid.Canvas.Brush.Color := CalViewStringGrid.Color; CalViewStringGrid.Canvas.Font.Color := CalViewStringGrid.Font.Color; end; CalViewStringGrid.Canvas.FillRect(Rect); CalViewStringGrid.Canvas.TextRect(Rect, Rect.Left, Rect.Top, sDay); if (WorkOrders = '') then Exit; Inc(Rect.Top, CalViewStringGrid.Canvas.TextHeight(sDay) + 2); repeat idx := Pos(#10, WorkOrders); if idx <> 0 then begin WorkOrder := Copy(WorkOrders, 1, idx-1); WorkOrders := Copy(WorkOrders, idx+1, MaxInt); end else begin WorkOrder := WorkOrders; WorkOrders := ''; end; s := WorkOrder; idx := Pos('-', s); ETips := Copy(s, 1, idx-1); s := Copy(s, idx+1, MaxInt); idx := Pos('-', s); SerType := Copy(s, 1, idx-1); s := Copy(s, idx+1, MaxInt); WoNum := s; if SerType = 'R' then begin CalViewStringGrid.Canvas.Font.Color := clRed; end else if SerType = 'P' then begin CalViewStringGrid.Canvas.Font.Color := clBlue; end else if SerType = 'S' then begin CalViewStringGrid.Canvas.Font.Color := clGreen; end else if bIsToday then begin CalViewStringGrid.Canvas.Font.Color := clBlue; end begin CalViewStringGrid.Canvas.Font.Color := CalViewStringGrid.Font.Color; end; CalViewStringGrid.Canvas.TextRect(Rect, Rect.Left, Rect.Top, WorkOrder); Inc(Rect.Top, CalViewStringGrid.Canvas.TextHeight(WorkOrder) + 2); until WorkOrders = ''; end; procedure TCalViewForm.UpdateRowHeights; var X, Y, TxtHeight: Integer; MaxHeight: Integer; R: TRect; begin // This next line seems to really control the height of the rows CalViewStringGrid.Canvas.Font.Size := 9; for Y := CalViewStringGrid.FixedRows to CalViewStringGrid.RowCount - 1 do begin MaxHeight := CalViewStringGrid.DefaultRowHeight - 4; for X := CalViewStringGrid.FixedCols to CalViewStringGrid.ColCount - 1 do begin R := Rect(0, 0, CalViewStringGrid.ColWidths[X] - 4, 0); TxtHeight := DrawText(CalViewStringGrid.Canvas.Handle, PChar(CalViewStringGrid.Cells[X, Y]), -1, R, DT_WORDBREAK or DT_CALCRECT); if TxtHeight > MaxHeight then MaxHeight := TxtHeight; end; // 11/18/2015 - was = AGrid.RowHeights[Y] := MaxHeight + 4; CalViewStringGrid.RowHeights[Y] := MaxHeight + 1; end; end;
I keep getting an error when trying to execute my code
Declare Total integer; i integer; Begini:= 1; total:=1; loop total := total * i; i := i+1; exit when i > 4; End loop; dbms_output.put_line('total is ' || total); End;
For start Begini:= 1; total:=1; Should be Begin i:= 1; total:=1;
PLSQL Printing prime numbers
I want to print prime numbers between 1 to 50. But I don't understand what I am doing wrong in my code. After BEGIN, SQLDeveloper says I had an error because it expected another sign and not = . SET SERVEROUTPUT ON DECLARE i NUMBER; counter NUMBER; n NUMBER; k NUMBER; BEGIN i := 2; counter := 0; n := 50; k := n/2; FOR i IN 1..k LOOP IF (n%i := 0 ) THEN counter := 1; END IF; IF (counter := 0) THEN DBMS_OUTPUT.PUT_LINE(n||' is prime number'); END IF; END LOOP; END;
SET SERVEROUTPUT ON DECLARE i NUMBER; counter NUMBER; n NUMBER; k NUMBER; BEGIN i := 2; counter := 0; n := 50; k := floor(n/2); FOR i IN 1..k LOOP IF (mod(n, i) = 0 ) THEN counter := 1; END IF; IF (counter = 0) THEN DBMS_OUTPUT.PUT_LINE(n||' is prime number'); END IF; END LOOP; END; k := n/2; -- added FLOOR (k is NUMBER, by default it's NUMBER(38, max_scale)) IF (n%i := 0 ) THEN -> IF (mod(n, i) = 0 ) THEN Oracle has MOD function for remainder + to compare you need to use =, := is for assignment. DECLARE counter NUMBER; k NUMBER; BEGIN FOR n IN 1..50 LOOP counter := 0; k := floor(n/2); FOR i IN 2..k LOOP IF (mod(n, i) = 0 ) THEN counter := 1; END IF; END LOOP; IF (counter = 0) THEN DBMS_OUTPUT.PUT_LINE(n||' is prime number'); END IF; END LOOP; END;
In your IF clause you are assigning the value instead of comparison. You are using := operator, where you shd be using = It shud be like (IF counter = 0) then ...... Also I dont think n%i would work, you could do IF (trunc(n) = n) then ... or IF (mod (n,i) =0) then ...
--this function is check prime number. create or replace function prime_a(x number) return varchar2 is n integer; ans varchar2(50); begin n:=(x/2); for i in 2..n loop if mod(x,i)=0 then ans:='not a prime'; exit; else ans:='prime'; end if; end loop; return ans; end; /
step-1: create table tob(prime number); step-2: create or replace procedure ro(m number,n number) is a integer; co Boolean; begin for j in m..n loop co:=false; co:=(j=1 ); a:=(j/2); for i in 2..a loop co:=(mod(j,i)=0); exit when co; end loop; if(not co) then insert into tob values(J); end if; end loop; commit; end; / step-3: exec ro(1,50); step-4: check:- select * from tob;
You should create or replace in your source code: function prime_a(x number) return varchar2 is n integer; ans varchar2(50); begin n:=(x/2); for i in 2..n loop if mod(x,i)=0 then ans:='not a prime'; exit; else ans:='prime'; end if; end loop; return ans; end; /
Why don't you just check for previous prime divisibility? create table prime (primeno bigint) declare #counter bigint set #counter = 2 while #counter < 1000000 begin if not exists(select top 1 primeno from prime where #counter % primeno = 0) insert into prime select #counter set #counter = #counter + 1 end select * from prime order by 1 You could certainly cap the numbers you are checking against in the where condition to reduce your overheads further.
declare i number; j number; k number:=0; begin for i in 1..50 loop for j in 2..i-1 loop if mod(i,j)=0 then k:=1; exit; end if; end loop; if k=0 then dbms_output.put_line(i); end if; k:=0; end loop; end; /
create or replace function prime_a(x number) return varchar2 is n integer; ans varchar2(50); begin n:=(x/2); for i in 2..n loop if mod(x,i)=0 then ans:='not a prime'; exit; else ans:='prime'; end if; end loop; return ans; end; /