Inserting a record in sybase db table using stored procedure - delphi programming - sql

I am new at programming with delphi. I am currently creating a simple notebook program and i need some help. I have a form called contacts with 5 tEdit fields. I am thinking i could create a stored procedure in my sybase database to insert record into Contacts table, so I can call it with my delphi programm. How do I call this procedure in delphi? the values that will be inserted should be taken from users input into these tEdit fields. Anyone has any suggestions? Or am I thinking the wrong way? thanks in advance

You have several options here, and it will depend on what VCL controls you are using.
(1). You can insert via a tTable component. This let's you have a quick, easy, low level control. You drop the component on the form, set the component properties (tablename, etc), then something like
MyTable.Open;
MyTable.Insert; (or maybe append)
MyTable.FieldByName('MY_FIELD').AsString := 'Bob'; // set the field values
MyTable.post;
(2). Use SQL. Drop a SQL component on the form. Set the SQLText property, using parameters;
for example : "Insert into table (MyField) values :X". My opinion is that this is easier to do in complex situations, correlated subselects, etc.
MySQL.Close;
MySQL.ParamByName('X').AsString := 'BOB';
ExecSQL;
(3). Use stored procedures. - The advantage to this is that they are useable by multiple applications, and can be changed easily. If you want to update the SQL code, you update it once (in the database), versus having to change it in an app, and then distribute the app to multiple users.
The code for this will be nearly identify to (2), although I don't know the specifics of your VCL library. In effect though, you will specify the routine to run, specify the parameter values, and then execute the stored procedure.
Note that all these routines will return an error code or exception code. It is best practice to always check for that...
Here is a little more complex example, using a SQL statement called qLoader. qLoader exists on a datamodule. I am passing a parameter, executing the SQL statement, then iterating through all the results.
try
with dmXLate.qLoader do
begin
Close;
ParamByName('DBTYPE').AsString := DBType;
Open;
while not dmXLate.qLoader.Eof do
begin
// Here is where we process each result
UserName:= dmXLate.qLoader.FieldByName('USERNAME').AsString;
dmXLate.qLoader.Next;
end;
end;
except
on E: Exception do
begin
ShowMEssage(E.Message);
exit;
end;
end;

Related

pl/sql procedure with variable numbers of parameters

I want to know if I can create a PL/SQL procedure that the number of parameters and their types changes.
For example procedure p1.
I can use it like this
p1 (param1, param2,......., param n);
i want to pass table name and data in procedure, but the attributes change for every table,
create or replace PROCEDURE INSERTDATA(NOMT in varchar2) is
num int;
BEGIN
EXECUTE IMMEDIATE 'SELECT count(*) FROM user_tables WHERE table_name = :1'
into num using NOMT ;
IF( num < 1 )
THEN
dbms_output.put_line('table not exist !!! ');
ELSE
dbms_output.put_line('');
-- here i want to insert parameters in the table,
-- but the table attributes are not the same !!
END IF;
NULL;
END INSERTDATA;
As far as I can tell, no, you can not. Number and datatypes of all parameters must be fixed.
You could pass a collection as a parameter (and have different number of values within it), but - that's still a single parameter.
Where would you want to use such a procedure?
If you need to store, update and query a variable amount of information, might I recommend switching to JSON queries and objects in Oracle. Oracle has deep support for both fixed and dynamic querying of json data, both in SQL and PLSQL.
i want to pass table name and data in procedure, but the attributes change for every table,
The problem with such a universal procedure is that something needs to know the structure of the target table. Your approach demands that the caller has to discover the projection of the table and arrange the parameters in a correct fashion.
In no particular order:
This is bad practice because it requires the calling program to do the hard work regarding the data dictionary.
Furthermore it breaks the Law Of Demeter because the calling program needs to understand things like primary keys (sequences, identity columns, etc), foreign key lookups, etc
This approach mandates that all columns must be populated; it makes no allowance for virtual columns, optional columns, etc
To work the procedure would have to use dynamic SQL, which is always hard work because it turns compilation errors into runtime errors, and should be avoided if at all possible.
It is trivially simple to generate a dedicated insert procedure for each table in a schema, using dynamic SQL against the data dictionary. This is the concept of the Table API. It's not without its own issues but it is much safer than what your question proposes.

oracle forms 6i missing package body

In a software we've acquired, we found that there are some package bodies that have procedures that are just defined as null. For example:
procedure execute_report(parameters) is
begin
null;
end;
Despite this, these procedures are being used through the forms, and they seem to work properly. As in the example, calling the procedure "execute_report" actually runs a report.
The procedure is not defined in any library, or even using the query:
SELECT * FROM ALL_OBJECTS WHERE OBJECT_NAME LIKE '%EXEC%'
does not return anything from the database that might be called...
Is there a way to hide the code in the forms, libraries or DB that I'm missing?
You probably have a pll (forms library) that contains the procedure execute_report
Then this will be called instead of the database version.

Getting results from Oracle stored procedure insertion through pyodbc

I am using pyodbc (version 3.0.7) to access an Oracle (version 11g) database. We are writing stored procedures to handle the insertions. The primary keys for inserted objects are assigned with triggers, so we want to get the newly-inserted object's primary key into python after the stored procedure is called by the python script. (Due to client requirements, we don't have the flexibility of changing database, libraries, etc.)
According to the pyodbc documentation, return (OUT) parameters in stored procedures are not supported. Neither are stored functions. The documentation suggests to add a SELECT statement to the end of a stored procedure to get results out. However, we are new to SQL scripting, and Google searching for the last two days has turned up a lot of information for SQLServer and other databases, but next to nothing for Oracle. Trying the SQLServer examples on the Oracle db has not been tremendously helpful, as the Oracle SQL Developer shows various errors with the syntax (DECLARE where one shouldn't be, INTO required for SELECT statements, etc.).
Ultimately, we want the stored procedure to insert a new object, and then we want to somehow get the newly-created primary key for that object.
Here is an example of a stored procedure that correctly inserts an object (note that if obj_id is given as "None" in python, then the object is assigned a new primary key by a trigger):
CREATE OR REPLACE PROCEDURE insert_an_obj (an_obj_id NUMBER) AS
new_primary_key NUMBER;
BEGIN
INSERT INTO OBJS (OBJ_ID) VALUES (an_obj_id) RETURNING OBJ_ID INTO new_primary_key;
-- A SELECT statement should go here in order to get the new value for new_primary_key.
END insert_an_obj;
Supposedly, a SELECT statement at the end of the stored procedure will make it so the next time my script calls cursor.fetchall(), the script would get a list of whatever was selected. However, I have been unable to get this to work. Some failed SELECT examples (one of which might go in the stored procedure above in place of the SELECT comment) include the following:
-- These fail to compile because SQL Developer doesn't like them (though various sources online said that they work on SQLServer):
SELECT * FROM OBJS WHERE OBJ_ID=new_primary_key;
SELECT OBJ_ID FROM OBJS WHERE OBJ_ID=new_primary_key;
Like I said, I'm new to SQL, and likely I just need to know the proper syntax to get the SELECT statement working nicely in Oracle. Any suggestions? Or is there something that I'm misunderstanding?
As mentioned by Justin Cave in the comment above, "you can't just put a SELECT in a stored procedure to return data to the client." At least not with Oracle 11g. He continues: "In 11g, the only way to regurn data from a stored procedure is to have an OUT parameter", which AFIK, not possible using version 3.0.7 of pyodbc.

Oracle triggers and stored procedures

I need to make for my webApp a trigger to execute a stored procedure on Oracle. But i'm very new to Oracle and I'm still getting the hang of it. I can make a simple Trigger with a sequence to auto-increment a value from a table, but that's it.
Is there any good tutorials and examples available on this specific subject? I tried searching here, but i have only found a very generic question: How can i learn Stored Procedure and Trigger?. But i can be more specific: I need this trigger to run a stored procedure that generates a new code for my user, adding data to this code. The procedure is done, i just don't know how to use it in a trigger, pass the parameters, and how to insert/update values from the oracle trigger itself.
Help will be much appreciated.
Assuming your function to generate the code is named f_generate_code() and your table is named foobar and the column that should be populated is name code you'd do it like this:
create or replace trigger trg_update_code
before insert or update on foobar
for each row
begin
:new.code := f_generate_code();
end;
/

best way to insert data using dephi in sql server 2008

I've always used such script to insert data into a table in delphi 7
sql := 'INSERT INTO table_foo (field1,field2,field3) VALUES ('
+quotedstr('value1')
+','+quotedstr('value2')
+','+quotedstr('value3')
+')';
adoquery1.close;
adoquery1.sql.text := sql;
adoquery1.execsql;
but one of my friend just showed me another way that looks cleaner, like so:
sql := 'SELECT * FROM table_foo';
adoquery1.close;
adoquery1.sql.text := sql;
adoquery1.open;
adoquery1.insert;
adoquery1.fieldbyname('field1').asstring := quotedstr('value1');
adoquery1.fieldbyname('field2').asstring := quotedstr('value2');
adoquery1.fieldbyname('field3').asstring := quotedstr('value3');
adoquery1.post;
which of the two methods are better (faster, easier to read/debug)? especially when the data in table_foo is large or there are a lot more fields to fill.
If you do use INSERT INTO statements use parameters (for reasons of readability, avoid SQL injection, SQL caching) e.g.:
adoquery1.sql.text := 'INSERT INTO table_foo (field1, field2) values (:field1, :field2)';
adoquery1.Parameters.ParamByName('field1').Value := value1;
adoquery1.Parameters.ParamByName('field2').Value := value2;
I prefer the second way (with a small tweak which I'll explain).
Since you are inserting one record, the tweak is to select an empty recordset i.e.:
SELECT * FROM table_foo where 1=0
This way you don't select all records form the table.
Also no need to use QuotedStr when assigning the values i.e.:
adoquery1.FieldByName('field1').AsString := 'value1';
The main reason I use this method is because it's easy to read and to maintain.
I don't need to bother myself with pure SQL queries. I don't need to deal with Parameters which sometime required to specify the data type for the parameters (e.g. Parameters.ParamByName('field1').DataType := ftInteger). No need to ParseSQL.
I simply use the DataSet As(Type) e.g.
FieldByName('field1').AsBoolean := True;
I would also prefer to use this method if I need to insert multiple records in a single transaction.
The downside for the second method is the short trip to the SQL server via SELECT FROM.
Another option would be to create a SQL stored procedure, pass your values to the SP, and write all the SQL logic inside the SP.
The second approach demands more local resources from the dataset, since it will keep a memory of the original result set and then use that memory to decide which records should be sent to the server by using which SQL statement. That approach also requires a live connection with the server and a bidirectional local cursor set in the dataset. TADODataset does all that for you. It works more to you work less, but it will consume more from the system. The decison, under my view, depends on which resource is more important, your time or computer resources.
Personaly, I prefer using TClientDataset (CDS). It will allow you to have an in-memory dataset and by using TDatasetProvider.BeforeUpdateRecord event in the corresponding TDatasetProvider you will get the best of both worlds: absolute control over which sentence will be submited to the server and a flexible and bidirectinal dataset that works very well on GUIs.
Besides (this is the most important to me), with CDS you will be able to isolate the specifics of your DBMS away from the main logic of your application, because that logic will be operating on a DB-independent dataset. If you have to shift from ADO to, let´s say, DBX, your main code will not be hurt because it´s written on CDS.