I want to insert the result of a stored procedure into a table
Something like :
CREATE PROCEDURE MyStoredProc2()
DYNAMIC RESULT SETS 1
BEGIN
INSERT INTO MyTable
SELECT * FROM (CALL MyStoredProc1())
END;
Definition of MyStoredProc1 :
CREATE PROCEDURE MyStoredProc1 ()
DYNAMIC RESULT SETS 1
BEGIN
DECLARE CURSOR_1 CURSOR WITH RETURN ONLY FOR
SELECT * FROM Table;
OPEN CURSOR_1;
END;
Thanks for your help
Related
I Tried to get result from ADOQuery in Delphi. I wrote this function for Get a Name from table according custom ID.
function GetNameByID(Id : Integer) : string;
var query : string;
Begin
ShowMessage(GetDBGridViewIndex().ToString);
query := 'SELECT Name FROM Table1 WHERE ID=' + IntToStr(Id);
With ADOQuery do
Begin
try
SQL.Clear;
SQL.Add(query);
Open;
First;
Result:= // Need Get Result;
finally
Close;
end;
End;
ShowMessage(result);
End;
But I don't know how can return Result from ADOQuery.
TADOQuery is a descendant of TDataset.
You can iterate through the result records with the First, Next, Prior, and Last methods and find out if you've reached the end with Eof.
Within each result record you can access the fields with:
Fields[Index].AsString
Fields[Index].AsInteger
...
or
FieldByName(FieldName).AsString
FieldByName(FieldName).AsInteger
...
In this case you can access to the result using:
Result := Fields[0].AsString;
Result := FieldByName('Name').AsString;
After you Open the query, the cursor is pointing the First record. You don't need to call the First method after Open.
I am using ADOQuery in Delphi 7 and Oracle. I am getting error while passing parameters to ADOQuery. I have used following line. Please help me to identify error.
ADOQuery.Sql.text:= 'select * from temp_table '+
'where column1 in (select column from table2 where id=:id) and id=:id';
ADOQuery.Parameters.ParamByValue('id').value= 'abc';
ADOQuery.open;
when I open the query i will get following error:
Parameter object is improperly defined. Inconsistent or incomplete information is provided.
We have the same problem, we ended "masking" the class TParameters like this:
Declaration:
TMyParameter = class(TParameter)
private
function GetAsValue: variant;
Procedure SetAsValue(const Value: variant);
public
property Value: variant read GetAsValue write SetAsValue;
end;
Implementation:
procedure TMyParameter.SetAsValue(const Value: variant);
var
iPar: Integer;
begin
for iPar:= 0 to Collection.Count - 1 do
if (Name = TParameter(Collection.Items[iPar]).Name) then
TParameter(Collection.Items[iPar]).Value:= Value;
end;
function TMyParameter.GetAsValue: variant;
begin
Result:= inherited Value;
end;
And how to use:
TMyParameter(ADOQuery.Parameters.ParamByName('id')).AsValue:= 'abc';
I hope it helps.
for i:=0 to ADOQuery.Parameters.Count-1 do
begin
if ADOQuery.Parameters.Items[i].Name = 'id' then
ADOQuery.Parameters.Items[i].Value := 'abc';
end;
You need to distinguish between the two id;s:
ADOQuery.Sql.text:= 'select * from temp_table a where column1 in (select column from table2 b where b.id=:id) and a.id=:id';
ADOQuery.Parameters.ParamByValue('id').value= 'abc';
ADOQuery.open;
In the SQL code declare a variable of the necessary type, assign to that variable the parameter; you will be able to use that variable as many times as necessary:
ADOQuery.Sql.text:= 'declare #param varchar(50); set #param = :id; '+
'select * from temp_table '+
'where column1 in (select column from table2 where id=#param) and id=#param';
ADOQuery.Parameters.ParamByValue('id').value= 'abc';
ADOQuery.open;
Regards
In order to show my data in some order, I have ORDER column. So I can move up and down rows. That is already working, I just swap ORDER number for the affected rows. My problem is, when I delete a row, I need to reorder all other rows. To show the rows in the proper order I use the .IndexFieldNames := 'ORDER', but when I iterate through all rows and assign the new ORDER number, with active index its pretty slow. When I remove the .IndexFieldNames := '', then the rows are not in the correct order anymore, and the new order is wrong.
Here is my code:
class procedure TDataModuleEx.ReOrderColumn(const aDataSet: TClientDataSet;
const aFieldName: string; aResetClone: Boolean);
var
clone: TClientDataSet;
newOrderNo: Integer;
begin
newOrderNo := 0;
clone := TClientDataSet.Create(nil);
try
clone.CloneCursor(aDataSet, aResetClone);
clone.IndexFieldNames := aFieldName;
clone.IndexFieldNames := ''; //Indexed Edit is too slow
clone.First;
while not clone.eof do
begin
Inc(newOrderNo);
clone.Edit;
clone.FieldByName(aFieldName).AsInteger := newOrderNo;
clone.Post;
clone.Next;
end;
finally
clone.Free;
end;
end;
How can I reorder my rows after one is deleted efficiently?
I made some testing on a table with 10 000 records. Procedure ReOrderColumn made renumbering for about 3 seconds. ClientDataSet. ApplyUpdate took about 30 seconds.
Total about 33 seconds.
I wrote stored procedure in Firebird database which made renumbering for about 3 seconds.
SET TERM ^ ;
create or alter procedure REORDER
as
declare variable ID integer;
declare variable I integer;
BEGIN
i = 0;
FOR
select new_table.id
from new_table
order by FORDER
INTO :ID
as cursor tcur
DO
BEGIN
i = :i + 1;
update new_table t set t.forder = :i
where current of tcur;
END
END^
SET TERM ; ^
From Delphi
procedure Reorder;
begin
//Apply changes to server
dm1.ClientDataSet1.ApplyUpdates(0);
//execute stored procedure
dm1.spReorder.ExecProc; <--- ABOUT 3 SEC FOR 10 000 records
//Refresh dataset
dm1.ClientDataSet1.Close;
dm1.ClientDataSet1.Open;
end;
I have a string grid, from which i can delete columns. I defined a CustomStringGrid type that allows me to use DeleteColumn method.
This is how it looks:
TCustomStringGrid = class(TStringGrid)
[...]
With tCustomStringGrid(mygrid) do
DeleteColumn(col)
end;
IS there something similar to add a column? I've tried InsertColumn but it doesn't seem to exist. I want to add a column at a particular position. In fact, if a user deletes a column i have an undo button which i want to reinsert the deleted column (i'm keeping the data in an array so i can recreate the column but i don't know how to insert one in a particular position).
Thank you!
It's not built in but easy to emulate, with ColCount = ColCount + 1 and MoveColumn from a HackClass.
type
THackGrid=Class(Grids.TCustomGrid)
End;
Procedure InsertColumn(G:TStringGrid;Position:Integer);
begin
if Position<G.ColCount then
begin
G.ColCount := G.ColCount + 1;
THackGrid(g).MoveColumn(G.ColCount - 1,Position);
end;
end;
procedure TMyForm.Button1Click(Sender: TObject);
begin
InsertColumn(StringGrid1,1);
end;
THack grid is not working, maybe it is ok when both cols are visible, but that works always :
Procedure MoveColumn(G:TStringGrid;OldPosition : integer;NewPosition:Integer);
var
i : integer;
temp : string;
begin
for i := 0 to g.rowcount - 1 do
begin
temp := g.cells[OldPosition,i];
g.cells[OldPosition,i] := g.cells[NewPosition,i];
g.cells[NewPosition,i] := temp;
end;
end;
I have DBGrid where I load names from DataSetPeople associated to table_people. I create a Drag and Drop procedure, where the user can drag a name and drop into a ListBox. The user can drop into a listbox_employees or listbox_manager.
MY PROBLEM
I want to create a relationship between people from table_people using the names that user drop in both listbox. I create table_relationship where employeeID match with managerID.
So, how can I get the name from each listbox, associate this name to an ID, and put this ID into a employeeID or managerID from DataSetRelationship associated to table_relationship ?
If your IDs are numeric (integer) values, you can use the TListBox.Items.Objects to store it when you fill it (in your drop event handler on the form):
var
PersonName: string;
PersonID: Integer;
begin
with YourDataModule do // Gives access to the tables in the data module
begin
PersonName := table_people.FieldByName('employeeName').AsString;
PersonID := table_people.FieldByName('employeeID').AsInteger);
end;
listbox_employees.Items.AddObject(PersonName, TObject(PersonID);
end;
For the manager, just change to the listbox for the manager and the field values for the manager.
To get the ID back out to use for an INSERT statement:
// Make sure both listboxes have the same number of items, of course.
var
EmployeeID: Integer;
ManagerID: Integer;
i: Integer;
begin
for i := 0 to ListBox_Employees.Items.Count - 1 do
begin
EmployeeID := Integer(ListBox_Employees.Items.Objects[i]);
ManagerID := Integer(ListBox_Manager.Items.Objects[i]);
if not YourDataModule.MakeRelationship(EmployeeID, ManagerID) then
ShowMessage('Unable to relate this employee and manager!');
end;
end;
// If you're using a SQL query, the `INSERT` should be created like this
// somewhere, like in your datamodule's OnCreate event
// qryRelationShips.SQL.Clear;
// qryRelationShips.SQL.Add('INSERT INTO table_relationship (employeeID, managerID)');
// qryRelationShips.SQL.Add('VALUES (:employeeID, :managerID)';
//
// Or you can type it into the SQL property in the Object Inspector at designtime
// INSERT INTO table_relationship (employeeID, managerID) VALUES (:employeeID, :managerID)
function TYourDataModule.MakeRelationship(const EmpID, MgrID: Integer): Boolean;
begin
Result := False;
// INSERT into your dataset:
qryRelationShips.ParamByName('employeeID').AsInteger := EmpID;
qryRelationShips.ParamByName('managerID').AsInteger := MgrID;
try
qryRelationShips.ExecSQL;
Result := qryRelationShips.RowsAffected;
finally
qryRelationShips.Close;
end;
end;
// If you're using a table instead of a query, getting a result is harder
function TYourDataModule.MakeRelationship(const EmpID, MgrID: Integer): Boolean;
begin
Result := True;
try
tblRelationShips.Insert;
tblRelationShips.FieldByName('employeeID').AsInteger := EmpID;
tblRelationShips.FieldByName('managerID').AsInteger := MgrID;
tblRelationShips.Post;
except
Result := False;
end;
end;
I hope you have made tables using SQLite database. So what you want to do is possible by using a query to insert the rows. Use db.execSQL();
You can keep a counter for incrementong the id values.