I am very new to SQL and PL/SQL. I am writing a procedure to take a museum, average the price of art, then increase the average by a percent. The user enters the museum ID (musmID) and percent increase. If the percent is too high there is an exception raised. If the musmID entered does not match one on the table, an exception is raised. Output is museum name, old avg price, and new avg price. So far it will only work when the exception for invalid musmID is not written. I keep getting the same error of PLS-00201:identifier 'MUMSID' must be declared.
Table 1 is arts and column names are musmID(FK) and price.
Table 2 is museums and column names are museum and musmID(PK).
My code:
CREATE OR REPLACE PROCEDURE proc_second (p_musmID IN arts.musmID%TYPE,
p_percent IN NUMBER) IS
v_musmID arts.musmID%TYPE;
v_oldavg arts.price%TYPE;
v_newavg arts.price%TYPE;
v_musmName museums.museum%TYPE;
too_high EXCEPTION;
musmID_invalid EXCEPTION;
BEGIN
IF p_percent > 40 THEN
raise too_high;
END IF;
IF musmID != p_musmID THEN
raise musmID_invalid;
END IF;
SELECT musmID, AVG(price) INTO v_musmID, v_oldavg from arts
WHERE musmID = p_musmID
GROUP BY musmID;
SELECT museum INTO v_musmName from museums
WHERE musmId = p_musmID;
v_newavg := v_oldavg * (1 + (p_percent/100));
dbms_output.put_line (v_musmname || ' ' || v_oldavg || ' ' || v_newavg);
EXCEPTION
WHEN too_high THEN
dbms_output.put_line ('Specify less than 40 percent increase');
WHEN musmID_invalid THEN
dbms_output.put_line ('You entered an invalid museum ID');
END;
/
Warning: Procedure created with compilation errors.
These are the errors i am getting.
LINE/COL ERROR
-------- -----------------------------------------------------------------
15/3 PL/SQL: Statement ignored
15/6 PLS-00201: identifier 'MUSMID' must be declared
I know it is probably something basic i am not seeing but so far if i get rid of the errors, the procedure raises the musmID_invalid exception no matter what is entered.
Huh. This code is wrongly arranged, as far as I can tell. You're first checking a variable, and then fetch its value.
I've created two dummy tables, just to make the procedure compile.
SQL> create table arts
2 (musmid number,
3 price number);
Table created.
SQL> create table museums
2 (musmid number,
3 museum number);
Table created.
Now, the procedure: it seems that you don't need V_MUSMID variable at all, because it is equal to P_MUSMID parameter (see the SELECT which selects the AVG(PRICE) and its WHERE clause). It means that you can use P_MUSMID throughout the code, instead of V_MUSMID.
It also means that MUSMID_INVALID will never be raised; you should, though, handle the NO_DATA_FOUND which will be raised if you pass a non-existent P_MUSMID.
So, I removed what I thought you don't need and - this is the remaining code; see if it does any good.
SQL> create or replace procedure proc_second (p_musmid in arts.musmid%type,
2 p_percent in number)
3 is
4 v_oldavg arts.price%type;
5 v_newavg arts.price%type;
6 v_musmname museums.museum%type;
7 too_high exception;
8 begin
9 if p_percent > 40 then
10 raise too_high;
11 end if;
12
13 select m.museum, avg(a.price)
14 into v_musmname, v_oldavg
15 from arts a join museums m on m.musmid = a.musmid
16 where a.musmid = p_musmid
17 group by m.museum;
18
19 v_newavg := v_oldavg * (1 + (p_percent/100));
20
21 dbms_output.put_line (v_musmname || ' ' || v_oldavg || ' ' || v_newavg);
22
23 exception
24 when too_high then
25 dbms_output.put_line ('Specify less than 40 percent increase');
26 when no_data_found then
27 dbms_output.put_line ('You entered an invalid museum ID');
28 end;
29 /
Procedure created.
SQL> exec proc_second(1, 20);
You entered an invalid museum ID
PL/SQL procedure successfully completed.
SQL>
Related
I was wondering if someone could help me with the error message I am getting from Snowflake. I am trying to create a stored procedure that will loop through 125 files in S3 and copy into the corresponding tables in Snowflake. The names of the tables are the same names as the csv files. In the example I only have 2 file names set up (if someone knows a better way than having to liste all 125, that will be extremely. helpful) .
The error message I am getting is the following:
syntax error line 5 at position 11 unexpected '1'.
syntax error line 6 at position 22 unexpected '='. (line 4)
CREATE OR REPLACE PROCEDURE load_data_S3(file_name VARCHAR,table_name VARCHAR)
RETURNS VARCHAR
LANGUAGE SQL
AS
$$
BEGIN
FOR i IN 1 to 2 LOOP
CASE i
WHEN 1 THEN
SET file_name = 'file1.csv';
SET table_name = 'FILE1';
WHEN 2 THEN
SET file_name = 'file2.csv';
SET table_name = 'FILE2';
--WILL LIST THE REMAINING 123 WHEN STATEMENTS
ELSE
-- Do nothing
END CASE;
COPY INTO table_name
FROM #externalstg/file_name
FILE_FORMAT = (type='csv');
END LOOP;
RETURN 'Data loaded successfully';
END;
$$;
There are various ways to list the files in a stage (see the post here). You can loop through the resultset and run COPY INTO on each record
CREATE PROCEDURE EPS.PROCEDURE_OTE_LTE_BIDDER_REPORT
(
IN P_USERID INTEGER,
IN P_AUCTIONID INTEGER,
IN P_REPORT_FLAG VARCHAR(3),
OUT O_ERROR_CODE INTEGER,
OUT OUTPUT_MESSAGE VARCHAR(100),
IN P_LOG_USERID INTEGER
)
LANGUAGE SQL
P1:BEGIN ATOMIC DECLARE SQLCODE INTEGER DEFAULT 0;
DECLARE V_USERID INTEGER;
DECLARE V_AUCTIONID INTEGER;
DECLARE V_REPORT_FLAG_TECHNOCOMMERCIALQUALIFIEDCUSTOMER VARCHAR(3);
DECLARE V_COUNT_TECHNOCOMMERCIALQUALIFIEDCUSTOMER INTEGER;
DECLARE V_REPORT_FLAG_SELECTIVEUSERWISETENDERREPORT VARCHAR(3);
DECLARE V_COUNT_SELECTIVEUSERWISETENDERREPORT INTEGER;
SELECT COUNT(*) INTO V_COUNT_TECHNOCOMMERCIALQUALIFIEDCUSTOMER FROM EPS.TECHNOCOMMERCIALQUALIFIEDCUSTOMER A
WHERE A.AUCTIONID=P_AUCTIONID AND A.USERID=P_USERID;
SELECT COUNT(*) INTO V_COUNT_SELECTIVEUSERWISETENDERREPORT FROM EPS.SELECTIVEUSERWISETENDERREPORT B
WHERE B.AUCTIONID=P_AUCTIONID AND B.USERID=P_USERID;
IF P_REPORT_FLAG = 'Y' THEN
IF V_COUNT_TECHNOCOMMERCIALQUALIFIEDCUSTOMER < 1 THEN
INSERT INTO EPS.TECHNOCOMMERCIALQUALIFIEDCUSTOMER (A.AUCTIONID,A.USERID,A.QUALIFIED) VALUES (P_AUCTIONID,P_USERID,'Y');
ELSE
SET OUTPUT_MESSEGE = 'DATA ALREADY PRESENT';
END IF;
ELSE
IF V_COUNT_TECHNOCOMMERCIALQUALIFIEDCUSTOMER > 0 THEN
DELETE FROM EPS.TECHNOCOMMERCIALQUALIFIEDCUSTOMER C WHERE C.AUCTIONID=P_AUCTIONID AND C.USERID=P_USERID;
ELSE
SET OUTPUT_MESSAGE = 'NO DATA FOUND';
END IF;
END IF;
IF P_REPORT_FLAG = 'Y' THEN
IF V_COUNT_SELECTIVEUSERWISETENDERREPORT < 1 THEN
INSERT INTO EPS.SELECTIVEUSERWISETENDERREPORT AA
( AA.AUCTIONID,
AA.USERID,
AA.TENDERREPORTTYPEID,
AA.STATUS,
AA.CREATEID,
AA.CREATEDATE,
AA.UPDATEID,
AA.UPDATEDATE
)
VALUES
(
P_AUCTIONID,
P_USERID,
103.
'A',
P_LOG_USERID,
CURRENT TIMESTAMP,
NULL,
NULL
);
ELSE
SET OUTPUT_MESSEGE = 'DATA ALREADY PRESENT';
END IF;
ELSE
IF V_COUNT_SELECTIVEUSERWISETENDERREPORT > 0 THEN
DELETE FROM EPS.SELECTIVEUSERWISETENDERREPORT CC WHERE CC.AUCTIONID=P_AUCTIONID AND CC.USERID=P_USERID;
ELSE
SET OUTPUT_MESSAGE = 'NO DATA FOUND';
END IF;
END IF;
END P1
I am getting this error
SQL Error [42601]: An unexpected token "END-OF-STATEMENT" was found following "Y PRESENT'". Expected tokens may include: "
END IF".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.7.85
SQL Error [42601]: An unexpected token "END-OF-STATEMENT" was found following "Y PRESENT'". Expected tokens may include: "
END IF".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.7.85
An unexpected token "END-OF-STATEMENT" was found following "Y PRESENT'". Expected tokens may include: "
END IF".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.7.85
An unexpected token "END-OF-STATEMENT" was found following "Y PRESENT'". Expected tokens may include: "
END IF".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.7.85
It helps to properly use a syntax editor that understands SQL, and take more care with checking your code. A good SQL editor may highlight your mistakes before you try to compile, as would any code review.
On a separate note, you should understand the difference between ANSI SQL PL and Oracle PL/SQL. Your code seems to use ANSI SQL PL syntax, although your mistakes may be mistakes for any flavour of SQL.
Here are some of the obvious syntax mistakes in your code (there may be others):
On the line INSERT INTO EPS.SELECTIVEUSERWISETENDERREPORT AA , the AA should be omitted.
For the same insert statement you have 103., when you might mean 103,.
For the line INSERT INTO EPS.TECHNOCOMMERCIALQUALIFIEDCUSTOMER (A.AUCTIONID,A.USERID,A.QUALIFIED) you probably mean instead
INSERT INTO EPS.TECHNOCOMMERCIALQUALIFIEDCUSTOMER (AUCTIONID,USERID,QUALIFIED)
The same mistake is present for the line with INSERT INTO EPS.SELECTIVEUSERWISETENDERREPORT (do not qualify the column names).
For the line beginning SET OUTPUT_MESSEGE = you probably mean SET OUTPUT_MESSAGE =, and this typo is present on other lines.
I have a table 'EMAIL' with unique field 'addr'. When I make a query from mysql console (via Putty) it returns '0 rows affected' (since the 'id' didnt actually change), but FIREDAC always returns rowsAffected=1 (or 2 or 3 if there are more fields). Why is it so, how do I fix that?
+----+-------+------+------+
| id | owner | addr | pass |
+----+-------+------+------+
| 1 | NULL | test | NULL |
+----+-------+------+------+
mysql> update EMAIL set id=last_insert_id(id);
Query OK, 0 rows affected (0.00 sec) // 0 affected!
Rows matched: 1 Changed: 0 Warnings: 0
FIREDAC (FDconnection + FDquery)
procedure test;
var conn:TFDCONNECTION;
query:TFDQUERY;
begin;
conn:=TFDCONNECTION.Create(nil);
query:=TFDQUERY.Create(nil);
query.Connection:=conn;
conn.Params.Add('DriverID=MySQL');
conn.Params.Add('CharacterSet=utf8');
conn.Params.Add('Server=192.168.56.11'); //ubuntu server, v 14.14 5.7.30
conn.Params.Add('User_Name=root');
conn.Params.Add('Password=mypass');
conn.Params.Add('Database=MYDB');
conn.Params.Add('Port=3306');
query.SQL.Text:='update EMAIL set id=last_insert_id(id)';
query.ExecSQL;
//never shows '0', always thinks all the rows have been updated!
showmessage(inttostr( query.RowsAffected ));
query.Close;
conn.Free;
query.Free;
end;
[SOLVED!] I edited the source code of 'FireDAC.Phys.MySQL', line 471, commented out the 'CLIENT_FOUND_ROWS' flag (thanks to #Olivier)
For a MySQL database, in the case of UPDATE queries, the number of affected rows (returned by mysql_affected_rows()) depends on the CLIENT_FOUND_ROWS flag.
If the flag is disabled, then only records that are actually modified are taken into account.
If the flag is enabled, then all processed records (whether they are modified or not) are taken into account.
By default, CLIENT_FOUND_ROWS is disabled, but FireDAC enables it when it calls mysql_real_connect().
I am trying to write a PL/SQL function name hoursWorked that takes workerId and prjId and returns total amount of hours worker has worked on a project.
Table named PROJECTHOURS
WORKERPRJID | WORKERID | PRJID | TOTHOURS | CDATE
---------- ---------- ---------- ---------- ---------
1 1 1 10 1-JAN-14
2 1 1 7 2-JAN-14
3 1 1 6 4-JAN-14
4 2 1 5 11-JAN-14
5 2 1 9 15-JAN-14
6 2 1 7 13-JAN-14
7 1 2 5 11-JAN-14
8 2 2 9 15-JAN-14
9 2 2 7 13-JAN-14
I have tried the following:
CREATE OR replace PROCEDURE Hoursworked (j IN NUMBER,
n IN NUMBER)
IS
hours_worked projecthours.tothours%TYPE := 0;
BEGIN
SELECT workerid,
prjid,
SUM(tothours)
INTO hours_worked
FROM projecthours
WHERE workerid = j
AND prjid = n
GROUP BY j,
n;
RETURN hours_worked;
END;
SQL> show errors;
Errors for PROCEDURE HOURSWORKED:
LINE/COL ERROR
-------- -----------------------------------------------------------------
6/1 PL/SQL: SQL Statement ignored
6/52 PL/SQL: ORA-00947: not enough values
12/1 PL/SQL: Statement ignored
12/1 PLS-00372: In a procedure, RETURN statement cannot contain an
expression
Admittedly I am very inexperienced with SQL in general, so any insights are very welcome, as to what I am doing wrong.
The select is wrong, you select 3 values, but fetch into only one. The group by references are incorrect.
You don't need to select the workerid or the project id, neither do you need the group by.
Should be like below
CREATE OR replace PROCEDURE Hoursworked (j IN NUMBER,
n IN NUMBER,
hours_worked OUT NUMBER)
IS
BEGIN
SELECT SUM(tothours)
INTO hours_worked
FROM projecthours
WHERE workerid = j
AND prjid = n;
END;
In a procedure Return immediately ends program execution, and doesn't expect any parameters. Either change the program unit type to a function, or use OUT variables as above.
And please give better parameter names than "j" & "n"
This question already has an answer here:
Error -104 creating Firebird stored procedure
(1 answer)
Closed 1 year ago.
I want to create a stored procedure in Firebird:
CREATE PROCEDURE CalcPvIncome
( BeginDate date,
EndDate date,
KwPrice decimal (2,2) )
RETURNS ( Total_PV_Production decimal (9,2),
Total_Income decimal (9,2) )
AS
BEGIN
FOR SELECT SUM(ENERGY/1000), SUM((ENERGY/1000) * :KwPrice)
FROM PVPROD
WHERE proddate >= :BeginDate AND proddate <= :Enddate
INTO :Total_PV_Production , :Total_Income
DO
BEGIN
SUSPEND ;
END
END
I get this error:
Engine Code : 335544569
Engine Message : Dynamic SQL Error SQL error code = -104 Unexpected end of command - line 18, column 9
The SQL statement:
SELECT
SUM(ENERGY/1000) AS Total_PV_Production,
sum((ENERGY/1000)*0.55) as Total_Income
FROM
PVPROD
where
proddate >= '12.06.2012' and proddate <= '12.07.2012'
You have to add SET TERM statement before and after the stored procedure. It is used to change the "terminator character". Here's an example:
SET TERM ^ ;
CREATE PROCEDURE CalcPvIncome
( BeginDate date,
EndDate date,
KwPrice decimal (2,2) )
RETURNS ( Total_PV_Production decimal (9,2),
Total_Income decimal (9,2) )
AS
BEGIN
...
END
SET TERM ; ^
Note that default terminator is ^ and also note that you are setting ; as new terminator before and resetting it back to ^ after stored procedure declaration.