In databses like SQL Server or Hana it is possible to put statements in block using
BEGIN
DECLARE start TIMESTAMP;
DECLARE end TIMESTAMP;
start = now();
select some_udf(X_ID) from X;
end = now();
select DATEDIFF(start, end);
END;
How is this possible in MEMSQL? If I understood it correctly BEGIN ... END can only be used with procedures or functions?!
Yes, you can write code like that in a stored procedure: http://docs.memsql.com/v6.0-beta/docs/create-procedure.
Related
I'm importing data from Excel to database table using Oracle Forms. Here is the code I'm using:
ligne_fin := 300;
FOR Z in 2..ligne_fin LOOP
ligne:=Z;
v_societe := Excel.get(1,Z,1) ;
v_compte := Excel.get(1,Z,2);
v_Tiers := Excel.get(1,Z,3);
v_section := Excel.get(1,Z,4);
insert into EntrCl (SOCIETE,
COMPTE,
TIERS,
SECTION)
VALUES (v_societe,
v_compte,
v_Tiers,
v_section);
END LOOP
With my get function
function GET(FOLIO in NUMBER, prow in number,pcol in number)
RETURN varchar2
is
deger varchar2(800);
Begin
deger:='';
args := OLE2.create_arglist;
OLE2.add_arg (args, FOLIO);
Worksheet:=OLE2.GET_OBJ_PROPERTY(workbook,'Worksheets',args);
args:=OLE2.CREATE_ARGLIST;
OLE2.ADD_ARG(args, prow);
OLE2.ADD_ARG(args, pcol);
cell:=ole2.get_obj_property(worksheet, 'Cells', args);
deger := OLE2.Get_Char_Property(cell, 'Text');
OLE2.RELEASE_OBJ(cell);
OLE2.destroy_arglist (args);
return(deger);
end;
My issue is that I want to get my ligne_fin automatically using code. I don't want to hardcode it.
Is there any way to get the last record of Excel file using PL/SQL ?
Check if a column returned null value to identify last row
Z:=2;
While(Excel.get(1,Z,1) is not null)
loop
v_societe := Excel.get(1,Z,1) ;
v_compte := Excel.get(1,Z,2);
v_Tiers := Excel.get(1,Z,3);
v_section := Excel.get(1,Z,4);
insert into EntrCl (SOCIETE,
COMPTE,
TIERS,
SECTION)
VALUES (v_societe,
v_compte,
v_Tiers,
v_section);
Z:=Z+1;
end loop;
I am using the following but the value of {sysuserinfoorg} is an empty string:
Data := 'UNINSTALL=' {sysuserinfoorg};
The above line returns 'UNINSTALL'.
I also tried ExpandConstant('{sysuserinfoorg}') with the same result.
I am using this in the DeinitializeUninstall procedure and sending the Data via HTTP post to my server which writes it to a log file. It all works but the {sysuserinfoorg} is empty. What I am after is some information that identifies the user and/or their organization. Inno Setup doc indicates {sysuserinfoorg} includes data from the registry on who the machine is registered to.
The ExpandConstant is the correct way:
Data := 'UNINSTALL=' + ExpandConstant('{sysuserinfoorg}');
The problem can be that there's actually no registered company.
Check the value of RegisteredOrganization value in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion key.
On my machine, it's empty, hence the {sysuserinfoorg} is empty too.
The mere {sysuserinfoorg} is nonsense in Pascal code.
Data := 'UNINSTALL=' {sysuserinfoorg};
The {...} is a comment in Pascal, as you can see with enabled syntax-highlighting.
Hence the code compiles as:
Data := 'UNINSTALL=';
You can also try to retrieve the value explicitly by reading registry:
if RegQueryStringValue(
HKEY_LOCAL_MACHINE_64, 'SOFTWARE\Microsoft\Windows NT\CurrentVersion',
'RegisteredOrganization', S) then
begin
Log('64-bit RegisteredOrganization = ' + S)
end
else
begin
Log('64-bit RegisteredOrganization is not defined')
end;
if RegQueryStringValue(
HKEY_LOCAL_MACHINE_32, 'SOFTWARE\Microsoft\Windows NT\CurrentVersion',
'RegisteredOrganization', S) then
begin
Log('32-bit RegisteredOrganization = ' + S)
end
else
begin
Log('32-bit RegisteredOrganization is not defined')
end;
Log('sysuserinfoname = ' + ExpandConstant('{sysuserinfoname}'));
The Inno Setup log file does not, by default, include the setup exit code. I am looking for a way to include this in the log file. I am assuming this would be done using the Log function and including it in the DeinitializeSetup event. Something like this:
procedure DeinitializeSetup();
begin
Log('Exit code: ' + ExitCode);
end;
What I don't know, and cannot seem to find, is how to return the setup exit code, so that I can use it in the Log function. Is this the best way to do this and how do I return the setup exit code?
There's no way to retrieve the exit code in Pascal Script.
All you can do is to log, if installation was successful or not (what is logged anyway already).
One way to do that is by checking, if the GetCustomSetupExitCode event function was called or not (it's called when exit code would be 0 only).
var
ZeroExitCode: Boolean;
function GetCustomSetupExitCode: Integer;
begin
ZeroExitCode := True;
Result := 0;
end;
procedure DeinitializeSetup();
begin
if ZeroExitCode then
Log('Zero exit code')
else
Log('Non-zero exit code');
end;
Good day people. First off, I'm not an native English speaker I might have some grammar mistakes or such.
I need an advice from people who has done something or an application alike mine, well, the thing is that I'm using a TProgressBar in my delphi form, another component called "TExcelApplication" and a TDBGrid.
When I export the DBGrid's content, the application "freezes", so I basically put that ProgressBar for the user to see how much the process is completed. I've realized that when the TDBGrid is retrieving and exporting each row to the new Excel workbook, you can't move the actual form, so you have to wait until the process is completed to move that form.
So, is it possible to do something (I thought about threads but I'm not sure if they could help) so the user could move the window if he wanted?
Thank you so much for taking your time in reading and giving me an advice. I'm using Delphi XE.
Here's the code I use to export the rows:
with ZQDetalles do
begin
First;
while not EOF do
begin
i := i + 1;
workSheet.Cells.Item[i,2] := DBGridDetalles.Fields[0].AsString;
workSheet.Cells.Item[i,3] := DBGridDetalles.Fields[1].AsString;
workSheet.Cells.Item[i,4] := DBGridDetalles.Fields[2].AsString;
workSheet.Cells.Item[i,5] := DBGridDetalles.Fields[3].AsString;
workSheet.Cells.Item[i,6] := DBGridDetalles.Fields[4].AsString;
workSheet.Cells.Item[i,7] := DBGridDetalles.Fields[5].AsString;
workSheet.Cells.Item[i,8] := DBGridDetalles.Fields[6].AsString;
workSheet.Cells.Item[i,9] := DBGridDetalles.Fields[7].AsString;
Next;
barraProgreso.StepIt;
end;
end;
If you want to see the whole code for the "Export" button, then feel free to see this link: http://pastebin.com/FFWAPdey
Whenever you're doing stuff that takes a significant amount of time in an application with GUI you want to put it in a seperate thread so the user can still operate the form. You can declare a simple thread as such:
TWorkingThread = class(TThread)
protected
procedure Execute; override;
procedure UpdateGui;
procedure TerminateNotify(Sender: TObject);
end;
procedure TWorkingThread.Execute;
begin
// do whatever you want to do
// make sure to use synchronize whenever you want to update gui:
Synchronize(UpdateGui);
end;
procedure TWorkingThread.UpdateGui;
begin
// e.g. updating the progress bar
end;
procedure TWorkingThread.TerminateNotify(Sender: TObject);
begin
// this gets executed when the work is done
// usually you want to give some kind of feedback to the user
end;
// ...
// calling the thread:
procedure TSettingsForm.Button1Click(Sender: TObject);
var WorkingThread: TWorkingThread;
begin
WorkingThread := TWorkingThread.Create(true);
WorkingThread.OnTerminate := TerminateNotify;
WorkingThread.FreeOnTerminate := true;
WorkingThread.Start;
end;
It's pretty straight forward, remember to always use Synchronize when you want to update visual elements from a thread. Usually, you also want to take care that the user can't invoke the thread again while it's still doing work as he's now able to use the GUI.
If the number of rows is small (and you know how many you'll have), you can transfer the data much more quickly (and all at once) using a variant array of variants, something like this:
var
xls, wb, Range: OLEVariant;
arrData: Variant;
RowCount, ColCount, i, j: Integer;
Bookmark: TBookmark;
begin
// Create variant array where we'll copy our data
// Note that getting RowCount can be slow on large datasets; if
// that's the case, it's better to do a separate query first to
// ask for COUNT(*) of rows matching your WHERE clause, and use
// that instead; then run the query that returns the actual rows,
// and use them in the loop itself
RowCount := DataSet1.RecordCount;
ColCount := DataSet1.FieldCount;
arrData := VarArrayCreate([1, RowCount, 1, ColCount], varVariant);
// Disconnect from visual controls
DataSet1.DisableControls;
try
// Save starting row so we can come back to it after
Bookmark := DataSet1.GetBookmark;
try
{fill array}
i := 1;
while not DataSet1.Eof do
begin
for j := 1 to ColCount do
arrData[i, j] := DataSet1.Fields[j-1, i-1].Value;
DataSet1.Next;
Inc(i);
// If we have a lot of rows, we can allow the UI to
// refresh every so often (here every 100 rows)
if (i mod 100) = 0 then
Application.ProcessMessages;
end;
finally
// Reset record pointer to start, and clean up
DataSet1.GotoBookmark;
DataSet1.FreeBookmark;
finally
// Reconnect GUI controls
DataSet1.EnableControls;
end;
// Initialize an instance of Excel - if you have one
// already, of course the next couple of lines aren't
// needed
xls := CreateOLEObject('Excel.Application');
// Create workbook - again, not needed if you have it.
// Just use ActiveWorkbook instead
wb := xls.Workbooks.Add;
// Retrieve the range where data must be placed. Again, your
// own WorkSheet and start of range instead of using 1,1 when
// needed.
Range := wb.WorkSheets[1].Range[wb.WorkSheets[1].Cells[1, 1],
wb.WorkSheets[1].Cells[RowCount, ColCount]];
// Copy data from allocated variant array to Excel in single shot
Range.Value := arrData;
// Show Excel with our data}
xls.Visible := True;
end;
It still takes the same amount of time to loop through the rows and columns of the data, but the time taken to actually transfer that data to Excel is drastically reduced, particularly if there's a good amount of data.
I have another post with more detailed code, but I think that my problem lies in the following logic. Is it possible to have a stored procedure, call another stored procedure, and the called procedure return a string to be used in the first stored procedure?
Example:
ALTER PROCEDURE [dbo].[SP1]
-- Add the parameters for the stored procedure here
#output nvarchar(30)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare #SP2Input nvarchar(30) = 'Input';
Declare #SP2Output nvarchar(30);
Execute #SP2Output = SP2 #SP2Input, #SP2Output;
If #SP2Output = 'Success'
Begin
Set #output = 'This worked';
End
Else
Begin
Set #output = 'This did not work';
End
Select #output;
END
Here is the next stored procedure:
ALTER PROCEDURE [dbo].[SP2]
-- Add the parameters for the stored procedure here
#input nvarchar(30),
#output nvarchar(30) out
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
If #input = 'Input'
Begin
Set #output = 'Success';
End
Else
Begin
Set #output = 'Fail';
End
Select #output;
END
So, what would get returned to whatever calls stored procedure SP1?
Declare #output nvarchar(30);
Execute SP1 #output;
I would assume that 'This worked' would get returned? However, two results are returned:
1) Success
2) This did not work
What am I doing wrong?
There are two ways to get values back from a sub-procedure: OUTPUT parameters and the return value.
OUTPUT parameters are what other languages call reference parameters. If you pass in a #variable its value can be used but also changed within the called procedure. For this to work you need to mark every parameter that you want to be an OUTPUT parameter as such in the definition of the procedure like you did:
ALTER PROCEDURE [dbo].[SP2]
#input nvarchar(30),
#output nvarchar(30) OUT
AS
BEGIN
....
But you also need to mark it as output on every call:
EXECUTE dbo.SP2 #SP2Input, #SP2Output OUT;
Changing the call of dbo.SP2 in you example to this should make it work.
The actual return value of a procedure is always an integer. You specify its value with the return statement in the procedure:
CREATE PROCEDURE dbo.SP3
AS
BEGIN
RETURN 42;
END;
You then can use it this way:
DECLARE #ret INT;
EXEC #ret = dbo.SP3;
PRINT #ret; -- will print 42