I have an Access database table named Receipts with the following field names: receipt number item name, buying price, selling price. I am using an Adoquery and datasource to connect to the access database. The following is the code I am using to print a report.
procedure TReceiptsform.BitBtn1Click(Sender: TObject);
var
qry :string;
begin
with ADOQuery1 do
begin
if ADOQuery1.Locate('receipt number',Edit1.Text,[]) then
open;
SQL.Clear;
qry:= 'SELECT*from Receipts WHERE (((Receipts.[receipt number])='+ edit1.Text+'))order by Receipts.[Item name]';
SQL.Add(qry);
Active:= True;
ReceiptForm.QuickRep1.Preview;
end;
end;
However when I run the program then I click BitBtn1Click at runtime, I get this error.
ProjectSales.exe raised exception class EOleException with message 'Extra ) in query expression "(((Receipt.[item name])=))". Process stopped. Use Step or Run to continue.
Which exception handling code can I use to prevent this error or is there a problem with the Query?
You problem is, that if Edit1 is Null, no value is given to filter on because the use of + eliminates the quotes:
'SELECT * from Receipts WHERE (((Receipts.[receipt number])='+ edit1.Text+'))order by Receipts.[Item name]'
=>
'SELECT * from Receipts WHERE (((Receipts.[receipt number])=)) order by Receipts.[Item name]'
So, use ampersand and some spaces:
'SELECT * from Receipts WHERE (((Receipts.[receipt number])=' & edit1.Text &')) order by Receipts.[Item name]'
Related
How can we get database name in progress openedge like in SQL we can get database name by using show databases; or SELECT schema_name FROM information_schema.schemata; using SQL query to openedge DB.
In ABL you can
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DO i = 1 TO NUM-DBS:
MESSAGE LDBNAME (i) SKIP
PDBNAME (i) SKIP
DBPARAM (i)
VIEW-AS ALERT-BOX INFORMATION BUTTONS OK.
END.
In OpenEdge SQL the SHOW CATALOGS command returns the database/catalog names:
https://docs.progress.com/bundle/openedge-sql-reference/page/SHOW-CATALOGS.html?_ga=2.234385114.558448476.1620632697-128156788.1596090319
SHOW CATALOGS PRO_NAME;
select db_name() from sysprogress.syscalctable;
Just in case the link to "Progress Communities" goes away:
Valeriy Bashkatov (Progress Technologies LLC)
You should run this with a DBA privileged user.
select * from sysprogress.SYSTABLES;
select * from sysprogress.SYSTABLES_FULL;
select * from sysprogress.SYSCOLUMNS where TBL = 'table_name';
select * from sysprogress.SYSCOLUMNS_FULL where TBL = 'table_name';
When using a stored procedure to dynamically generate a table based on configuration and return a result set (SELECT) with the records in that table, the second call to that procedure to generate a different table structure returns no records and it reports a missing column from a previous temporary table of the same name.
I tried this with MariaDB 10.3 and 10.1.21 and received the same result. I have minimized my code here to the minimum to demonstrate the error after trying several variations of single and multiple sub-procedures.
I also tried using some transaction control with COMMITS after executing the process, before trying to start the process with a different parameter, but got the same results.
DROP PROCEDURE IF EXISTS CreateATable;
DELIMITER $$
CREATE PROCEDURE CreateATable( _TableType tinyint )
BEGIN
DROP TEMPORARY TABLE IF EXISTS aTable;
IF _TableType = 1 THEN
SET #SQL_Statement :=
CONCAT(
'CREATE TEMPORARY TABLE aTable (',
'the_id bigint, ',
'the_column varchar(100) ',
') engine=INNODB',
';');
ELSE
SET #SQL_Statement :=
CONCAT(
'CREATE TEMPORARY TABLE aTable (',
'the_id bigint, ',
'the_other_column varchar(100) ',
') engine=INNODB',
';');
END IF;
PREPARE stmtCreateTable FROM #SQL_Statement;
EXECUTE stmtCreateTable;
DEALLOCATE PREPARE stmtCreateTable;
SET #SQL_Statement := NULL;
END$$
DELIMITER ;
DROP PROCEDURE IF EXISTS GetATable;
DELIMITER $$
CREATE PROCEDURE GetATable()
BEGIN
CALL CreateATable( 1 );
SELECT * FROM aTable;
CALL CreateATable( 2 );
SELECT * FROM aTable;
END$$
DELIMITER ;
DROP PROCEDURE IF EXISTS GetATable2;
DELIMITER $$
CREATE PROCEDURE GetATable2(_TableType tinyint)
BEGIN
CALL CreateATable( _TableType );
SELECT * FROM aTable;
END$$
DELIMITER ;
/*
Test execution script starts here
*/
-- Just CALL Create for one and Select
CALL CreateATable( 1 );
DESCRIBE aTable;
SELECT * FROM aTable;
CALL CreateATable( 2 );
DESCRIBE aTable;
SELECT * FROM aTable;
-- -> no errors
-- now CALL procedure to Create and Select from two different temp tables
CALL GetATable();
-- -> no errors
-- now CALL procedure to CREATE AND SELECT from ONE temp table definition using a parameter to select
CALL GetATable2(1);
CALL GetATable2(2);
-- Error Code: 1054. Unknown column 'mySchema.aTable.the_column' in 'field list'
I would expect that I can pass a parameter to a stored procedure to generate a temporary table, and return the records of that temporary table. Even if I call that same procedure multiple times with different parameters on the same session.
The actual results are that when the stored procedure is called to generate the temporary table with a different table structure, it returns this error complaining about the column missing from the temporary table created in the previous invocation of that same stored procedure.
Error Code: 1054. Unknown column 'mySchema.aTable.the_column' in 'field list'
The only way I have found to prevent this error is
a. ending the jdbc connection and ending the server session
b. recompiling one of the stored procedures in the call stack
Recompiling is not viable. And ending the session seems unreasonable.
This seems like a defect. But would be interested to find if there is some way to get this to work.
This seems like a bug and you can report it directly to the MariaDB team at MariaDB bugs database.
A temporary solution is to use a prepared statement in the stored procedure GetATable2 (my test on MariaDB 10.3.16 to use EXECUTE IMMEDIATE):
...
CREATE PROCEDURE `GetATable2`(`_TableType` TINYINT)
BEGIN
CALL CreateATable(`_TableType`);
-- SELECT * FROM `aTable`;
EXECUTE IMMEDIATE 'SELECT * FROM `aTable`';
END$$
...
See dbfiddle.
I have created a query that displays highest returned items from a table. My query it works perfectly with no errors! However, I want an efficient way of converting the query to PL/SQL block. The purpose of conversion is to handle errors.
SELECT ITEM_NO, MAX(QUANTITY) AS MAXIMUM
FROM ITEMS
WHERE CAT_NO >= (
SELECT MAX(ITEM_NUM) FROM ORDER
WHERE STATUS IN('ONE ITEM RETURNED','ALL ITEMS RETURNED')
)
GROUP BY ITEM_NO
ORDER BY ITEM_NO ASC;
Here's a way we do some exception handling in packages. I altered it to use your code as an example. Maybe you can use some ideas from it.
At the top, set a CONSTANT to the name of the procedure, and some variables to catch Oracle SQL error number and message in. Then in the body of the procedure, there is an anonymous block containing the select. First we set a variable to indicate where we are (err_loc) in case there are multiple locations where an error could be caught in one block. Then the select is issued. If an error occurs, it's caught by the EXCEPTION clause. Error info from Oracle is caught in the err* variables, the err_string is built and then emailed via the UTL_MAIL package. RAISE raises the error so the program halts. It's set up like this to be generic as possible, we can drop in the template, change the MBR_NAME, SQL, err_loc and that's it.
PROCEDURE TEST_PROC AS
MBR_NAME CONSTANT VARCHAR2(100) := 'TEST_PROC'; -- For use in error handling. Package member name.
err_nbr NUMBER; -- Holds a SQL error number if an exception occurs.
err_msg VARCHAR2(1000); -- Holds a SQL error message if an exception occurs.
err_string VARCHAR2(2000);
BEGIN
BEGIN
err_loc := 'Selecting max quantity'; -- Email subject
SELECT ITEM_NO, MAX(QUANTITY) AS MAXIMUM
FROM ITEMS
WHERE CAT_NO >= (SELECT MAX(ITEM_NUM)
FROM ORDER
WHERE STATUS IN('ONE ITEM RETURNED','ALL ITEMS RETURNED')
)
GROUP BY ITEM_NO
ORDER BY ITEM_NO ASC;
EXCEPTION
WHEN OTHERS THEN
err_nbr := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 1000);
err_string := 'ERROR: ' || err_nbr || ' occurred: ' || err_msg;
-- PKG_NAME and err_email_recip set in the body.
UTL_MAIL.send(sender => PKG_NAME||'.'||MBR_NAME||'#yourcompany.com',
recipients => err_email_recip,
subject => 'ERROR '|| err_loc,
message => CHR(13))||err_string);
RAISE;
END;
END TEST_PROC;
Have a look at cursors and records.
That way you have fetch data from the query and process the line if needed.
I don't have a database by hand to test my code, but this might give you an idea how a cursor and record work.
In order to capture a EXCEPTION you could add an exception handler and let it log the record you where busy with when the exception occured.
DECLARE
CURSOR CursorName IS
SELECT ColumnOne
FROM TableA
WHERE Name = 'Me';
RecordNumber CursorName%ROWTYPE;
BEGIN
-- Fetch the records from the cursor.
OPEN CursorName;
LOOP
FETCH CursorName INTO RecordNumber;
-- Do something with the record.
EXIT WHEN CursorName %NOTFOUND;
END LOOP;
CLOSE CursorName;
END;
/
Adding a error handeling would be done right above END:
EXCEPTION
WHEN OTHERS THEN
-- Log error message.
END;
/
Link: Error handeling
Does that answer you question a bit?
Let's have a look on my source code:
CREATE OR REPLACE PROCEDURE MAKE_COPY_OF_CLASSROOMS AUTHID CURRENT_USER AS
TYPE classrooms_table_type IS TABLE OF classrooms%ROWTYPE INDEX BY PLS_INTEGER;
classrooms_backup classrooms_table_type;
CURSOR classrooms_cursor IS
SELECT *
FROM classrooms
WHERE year = 1
ORDER BY name;
v_rowcnt PLS_INTEGER := 0;
BEGIN
OPEN classrooms_cursor;
FETCH classrooms_cursor
BULK COLLECT INTO classrooms_backup;
CLOSE classrooms_cursor;
EXECUTE IMMEDIATE 'CREATE TABLE classrooms_copy AS (SELECT * FROM classrooms WHERE 1 = 2)';
--COPY ALL STORED DATA FROM classrooms_backup TO classrooms_copy
END MAKE_COPY_OF_classrooms;
I'm stucked for hours on trying to insert data from "classrooms_backup" into the table "classrooms_copy", which is created by EXECUTE IMMEDIATE command. It's necessary to create table "classrooms_copy" via EXECUTE IMMEDIATE command. I tried to create another EXECUTE command with for loop in it:
EXECUTE IMMEDIATE 'FOR i IN classrooms_backup.FIRST..classrooms_backup.LAST LOOP
INSERT INTO classrooms_copy(id,room_id,year,name)
VALUES(classrooms_backup(i).id,classrooms_backup(i).room_id,classrooms_backup(i).year,classrooms_backup(i).name);
END LOOP;';
But it's road to the hell. I'm retrieving an invalid SQL statement error.
Thanks for your help!
There's no need for much PL/SQL here. Also, try to avoid the keyword CURSOR - there's almost always a better way to do it.
create or replace procedure make_copy_of_classrooms authid current_user as
begin
execute immediate '
create table classrooms_copy as
select *
from classrooms
where year = 1
order by name
';
end make_copy_of_classrooms;
/
When executing the following code, it just says the procedure is completed and doesn't print the infomation i want it to (firstName, lastName) and then the other values from the select query in a table below.
CREATE OR REPLACE PROCEDURE PRINT_ACTOR_QUOTES (id_actor char)
AS
CURSOR quote_recs IS
SELECT a.firstName,a.lastName, m.title, m.year, r.roleName ,q.quotechar from quote q, role r,
rolequote rq, actor a, movie m
where
rq.quoteID = q.quoteID
AND
rq.roleID = r.roleID
AND
r.actorID = a.actorID
AND
r.movieID = m.movieID
AND
a.actorID = id_actor;
BEGIN
FOR row IN quote_recs LOOP
DBMS_OUTPUT.PUT_LINE('a.firstName' || 'a.lastName');
end loop;
END PRINT_ACTOR_QUOTES;
/
When setting server output on, I get
a.firstNamea.lastName
a.firstNamea.lastName
a.firstNamea.lastName
a.firstNamea.lastName
multiple times!
What is "it" in the statement "it just says the procedure is completed"?
By default, most tools do not configure a buffer for dbms_output to write to and do not attempt to read from that buffer after code executes. Most tools, on the other hand, have the ability to do so. In SQL*Plus, you'd need to use the command set serveroutput on [size N|unlimited]. So you'd do something like
SQL> set serveroutput on size 30000;
SQL> exec print_actor_quotes( <<some value>> );
In SQL Developer, you'd go to View | DBMS Output to enable the DBMS Output window, then push the green plus icon to enable DBMS Output for a particular session.
Additionally, assuming that you don't want to print the literal "a.firstNamea.lastName" for every row, you probably want
FOR row IN quote_recs
LOOP
DBMS_OUTPUT.PUT_LINE( row.firstName || ' ' || row.lastName );
END LOOP;
Ensure that you have your Dbms Output window open through the view option in the menubar.
Click on the green '+' sign and add your database name.
Write 'DBMS_OUTPUT.ENABLE;' within your procedure as the first line.
Hope this solves your problem.
Set Query as below at first line
SET SERVEROUTPUT ON
this statement
DBMS_OUTPUT.PUT_LINE('a.firstName' || 'a.lastName');
means to print the string as it is.. remove the quotes to get the values to be printed.So the correct syntax is
DBMS_OUTPUT.PUT_LINE(a.firstName || a.lastName);
For SQL Developer
You have to execute it manually
SET SERVEROUTPUT ON
After that if you execute any procedure with DBMS_OUTPUT.PUT_LINE('info'); or directly .
This will print the line
And please don't try to add this
SET SERVEROUTPUT ON
inside the definition of function and procedure, it will not compile and will not work.
In Oracle SQL Developer, you can follow steps by steps as the below image:
I am using Oracle SQL Developer,
In this tool, I had to enable DBMS output to view the results printed by dbms_output.put_line
You can find this option in the result pane where other query results are displayed.
so, in the result pane, I have 7 tabs. 1st tab named as Results, next one is Script Output and so on. Out of this you can find a tab named as "DBMS Output" select this tab, then the 1st icon (looks like a dialogue icon) is Enable DBMS Output. Click this icon. Then you execute the PL/SQL, then select "DBMS Output tab, you should be able to see the results there.
All of them are concentrating on the for loop but if we use a normal loop then we had to use of the cursor record variable. The following is the modified code
CREATE OR REPLACE PROCEDURE PRINT_ACTOR_QUOTES (id_actor char)
AS
CURSOR quote_recs IS
SELECT a.firstName,a.lastName, m.title, m.year, r.roleName ,q.quotechar from quote q, role r,
rolequote rq, actor a, movie m
where
rq.quoteID = q.quoteID
AND
rq.roleID = r.roleID
AND
r.actorID = a.actorID
AND
r.movieID = m.movieID
AND
a.actorID = id_actor;
recd quote_recs%rowtype;
BEGIN
open quote_recs;
LOOP
fetch quote_recs into recs;
exit when quote_recs%notfound;
DBMS_OUTPUT.PUT_LINE(recd.firstName||recd.lastName);
end loop;
close quote_recs;
END PRINT_ACTOR_QUOTES;
/