I have the following SQL statement:
DECLARE
OLD_CUSTOMER_ID VARCHAR(8);
NEW_CUSTOMER_ID VARCHAR(8);
T_ENTITY T_CUSTOMER_GRNT_TEMPLATE_BASE.ENTITY%TYPE;
C_CUSTOMER_ID T_CUSTOMER_PROFILE_BASE.CUSTOMER_ID%TYPE;
T_TEMPLATE_ID T_CUSTOMER_GRNT_TEMPLATE_BASE.TEMPLATE_ID%TYPE;
T_AUTHORIZATIONS T_CUSTOMER_GRNT_TEMPLATE_BASE.AUTHORIZATIONS%TYPE;
BEGIN
OLD_CUSTOMER_ID := '00000081';
NEW_CUSTOMER_ID := '00000587';
MERGE INTO T_CUSTOMER_GRNT_TEMPLATE_BASE TGT
USING (
SELECT T.ENTITY, C.CUSTOMER_ID, T.TEMPLATE_ID, T.AUTHORIZATIONS
INTO T_ENTITY, C_CUSTOMER_ID, T_TEMPLATE_ID, T_AUTHORIZATIONS
FROM T_CUSTOMER_PROFILE_BASE C
JOIN T_CUSTOMER_GRNT_TEMPLATE_BASE T ON C.CUSTOMER_ID = T.CUSTOMER_ID
WHERE C.CUSTOMER_ID = OLD_CUSTOMER_ID
) SRC
ON ( TGT.ENTITY = SRC.ENTITY
AND TGT.CUSTOMER_ID = SRC.CUSTOMER_ID
AND TGT.TEMPLATE_ID = SRC.TEMPLATE_ID
)
WHEN MATCHED THEN UPDATE SET SRC.AUTHORIZATIONS = TGT.AUTHORIZATIONS
WHEN NOT MATCHED THEN INSERT VALUES (SRC.ENTITY, NEW_CUSTOMER_ID, SRC.TEMPLATE_ID, SRC.AUTHORIZATIONS)
WHERE TGT.CUSTOMER_ID = NEW_CUSTOMER_ID;
COMMIT;
END;
When running this statement I am getting this error:
Error report -
ORA-06550: line 16, column 13:
PL/SQL: ORA-01744: inappropriate INTO
ORA-06550: line 13, column 5:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
What am I doing wrong here? (I tried following instruction here https://www.tutorialspoint.com/plsql/plsql_variable_types.htm)
The SELECT ... INTO syntax is for putting the results of a query into PL/SQL variables; so you could do this:
DECLARE
OLD_CUSTOMER_ID VARCHAR(8);
NEW_CUSTOMER_ID VARCHAR(8);
T_ENTITY T_CUSTOMER_GRNT_TEMPLATE_BASE.ENTITY%TYPE;
C_CUSTOMER_ID T_CUSTOMER_PROFILE_BASE.CUSTOMER_ID%TYPE;
T_TEMPLATE_ID T_CUSTOMER_GRNT_TEMPLATE_BASE.TEMPLATE_ID%TYPE;
T_AUTHORIZATIONS T_CUSTOMER_GRNT_TEMPLATE_BASE.AUTHORIZATIONS%TYPE;
BEGIN
OLD_CUSTOMER_ID := '00000081';
NEW_CUSTOMER_ID := '00000587';
SELECT T.ENTITY, C.CUSTOMER_ID, T.TEMPLATE_ID, T.AUTHORIZATIONS
INTO T_ENTITY, C_CUSTOMER_ID, T_TEMPLATE_ID, T_AUTHORIZATIONS
FROM T_CUSTOMER_PROFILE_BASE C
JOIN T_CUSTOMER_GRNT_TEMPLATE_BASE T ON C.CUSTOMER_ID = T.CUSTOMER_ID
WHERE C.CUSTOMER_ID = OLD_CUSTOMER_ID;
-- do something with the variables
END;
But it is a PL/SQL extension of the SELECT statement. You aren't using a SELECT statement; you are using a MERGE statement which has a subquery - which means that SELECT is in a SQL context, not a PL/SQL context, and the PL/SQL extension isn't appropriate or meaningful.
So you can just remove the extra INTO clause, and the variables you don't need:
DECLARE
OLD_CUSTOMER_ID VARCHAR(8);
NEW_CUSTOMER_ID VARCHAR(8);
BEGIN
OLD_CUSTOMER_ID := '00000081';
NEW_CUSTOMER_ID := '00000587';
MERGE INTO T_CUSTOMER_GRNT_TEMPLATE_BASE TGT
USING (
SELECT T.ENTITY, C.CUSTOMER_ID, T.TEMPLATE_ID, T.AUTHORIZATIONS
FROM T_CUSTOMER_PROFILE_BASE C
JOIN T_CUSTOMER_GRNT_TEMPLATE_BASE T ON C.CUSTOMER_ID = T.CUSTOMER_ID
WHERE C.CUSTOMER_ID = OLD_CUSTOMER_ID
) SRC
ON ( TGT.ENTITY = SRC.ENTITY
AND TGT.CUSTOMER_ID = SRC.CUSTOMER_ID
AND TGT.TEMPLATE_ID = SRC.TEMPLATE_ID
)
WHEN MATCHED THEN UPDATE SET AUTHORIZATIONS = SRC.AUTHORIZATIONS
WHEN NOT MATCHED THEN INSERT VALUES (SRC.ENTITY, NEW_CUSTOMER_ID, SRC.TEMPLATE_ID, SRC.AUTHORIZATIONS)
WHERE TGT.CUSTOMER_ID = NEW_CUSTOMER_ID;
COMMIT;
END;
(Not really relevant, but you should be using VARCHAR2 rather than VARCHAR for your variable data types; or T_CUSTOMER_GRNT_TEMPLATE_BASE.CUSTOMER_ID%TYPE.)
Related
I receive the following error when I compile this function:
Compilation errors for PROCEDURE HAR.REPORT_INCOME_PROC PLS-00103:
Encountered the symbol "" when expecting one of the following
I have try to google for that, but I cant my fault...
CREATE OR REPLACE PROCEDURE REPORT_INCOME_PROC IS
BEGIN
DELETE FROM HAR.REPORT_INCOME;
INSERT INTO HAR.REPORT_INCOME RI
(RI.INCOME,
RI.AREA,
RI.INCOME_TYPE,
RI.DATA_DATE,
RI.CREATE_DATE,
RI.UPDATE_DATE)
SELECT SUM(YD.HJJE) DRSR,
MDYS.JYDQ SYB,
1,
TRUNC(YD.KDSJ) RQ,
(select sysdate from dual) XZSJ,
(select sysdate from dual) XGSJ
FROM HYDATA.LD_YD YD
LEFT JOIN HYDATA.LD_KHXX KHXX
ON YD.TYRBH = KHXX.KHBH
LEFT JOIN HYDATA.LD_GS GS
ON YD.QYDZBH = GS.GSBH
LEFT JOIN HAR.REPORT_JY_MDYS MDYS
ON YD.QYDZBH = MDYS.GSBH
WHERE YD.KDSJ >= TRUNC(ADD_MONTHS(SYSDATE, -12), 'yy')
AND (YD.YDZT != 5)
AND (YD.CYRQZ != '20000000000000000001' OR YD.CYRQZ IS NULL)
AND (KHXX.KHLB != 4 OR KHXX.KHLB IS NULL)
AND (GS.GSJC NOT LIKE '%F%' OR GS.GSJC IS NULL)
GROUP BY TRUNC(YD.KDSJ), MDYS.JYDQ
ORDER BY MDYS.JYDQ ASC, TRUNC(YD.KDSJ) DESC;
COMMIT;
END;
Here is the error
Error: PLS-00103: Encountered the symbol "" when expecting one of the
following:
begin function package pragma procedure subtype type use
<an identifier> <a double-quoted delimited-identifier> form
current cursor external language Line: 1
Hi I believe you need to use EXECUTE IMMEDIATE on a PLSQL BLOCK when doing DML statements.
try this:
CREATE OR REPLACE PROCEDURE REPORT_INCOME_PROC IS
BEGIN
EXECUTE IMMEDIATE 'DELETE FROM HAR.REPORT_INCOME';
EXECUTE IMMEDIATE 'INSERT INTO HAR.REPORT_INCOME RI <the rest of your codes>';
END;
I have some code that won't run because it expects an INTO clause in the select statement:
DECLARE
StatusCode VARCHAR2(255);
BEGIN
StatusCode := '';
SELECT acc.AccountNo,
acc.AccountTitle,
NVL(cus.Title,'') AS Title,
NVL(cus.Surname,'') AS Surname,
NVL(cus.Forename1,'') AS Forename1,
acc.GBP_Balance,
CASE
WHEN sc.ExcludeFromSCV = 1
THEN 'Yes'
ELSE 'No'
END AS ExcludedAccount
FROM DIM_FM_FSCS_Account acc
INNER JOIN DIM_FM_FSCS_CustomerAccLink lnk
ON acc.ID = lnk.FSCSAccountLink
LEFT JOIN DIM_FM_FSCS_Customer cus
ON lnk.FSCSCustomerLink = cus.ID
LEFT JOIN DIM_FM_FSCS_StatusCode sc
ON (acc.ExclusionCode = ''
AND sc.Code = acc.AccountStatusCode)
OR (sc.Code = acc.ExclusionCode)
WHERE (acc.AccountStatusCode = StatusCode
AND acc.ExclusionCode = '')
OR acc.ExclusionCode = StatusCode;
END;
However I am unsure how to add this and how it'll work with this script.
Can I have some help?
The error message is clear enough: in PL/SQL you can not make a SELECT query without fetching the result into some variable.
For example:
SQL> begin
2 select 1, 2 from dual;
3 end;
4 /
select 1, 2 from dual;
*
ERROR at line 2:
ORA-06550: riga 2, colonna 5:
PLS-00428: an INTO clause is expected in this SELECT statement
SQL> declare
2 v1 number;
3 v2 number;
4 begin
5 select 1, 2
6 into v1, v2
7 from dual;
8 end;
9 /
PL/SQL procedure successfully completed.
SQL>
So you need to define variable to handle the result(s) of your query.
Notice that in the example I used two scalar variables, but if your query can return more than one row, you will need to use some collection to fetch your data; for example:
declare
type tyListNum is table of number;
vList1 tyListNum;
vList2 tyListNum;
begin
select 1, 2
bulk collect into vList1, vList2
from dual
connect by level <= 2;
--
-- whatever you need to do with the fetched values
end;
What is the best practice for defining variables in sql? I've seen some of the other posts here and other places, but nothing I've tried as of yet has worked.
I'm using the below syntax, but the horse doesn't like the hay.
declare #variablename number(10)
set #variablename = (select COLUMN_NAME from TABLE_NAME where ANOTHER_COLUMN_NAME='something')
select MORE_COLUMN_NAMES from "NAME" where ANOTHER_NAME=#variablename;
This gives me some errors starting at "declare."
Error report -
ORA-06550: line 1, column 9:
PLS-00103: Encountered the symbol "#" when expecting one of the following:
begin function pragma procedure subtype type "an identifier"
"a double-quoted delimited-identifier" current cursor delete
exists prior
The symbol "#" was ignored.
I'm just starting out with very little database knowledge in so far as the application of things. I'm trying to become more versed in syntax and use.
Any help would be appreciated.
A PL/SQL block with variable declaration should be something like:
declare
var number;
var2 number;
begin
select count(1)
into var
from dual;
var2 := var * 2;
dbms_output.put_line('Var2 = ' || var2);
end;
In SQLPlus you can use bind variables:
variable var number
select count(1) into :var from dual;
select * from dual where rownum = :var;
or even substitution variables:
column var new_value valueFor_var
select count(1) as valueFor_var from dual;
select * from dual where rownum = &var;
Something is off but can't figure out what I am missing?
select
grade.sectionid,
grade.studentid,
course.courseid
FROM section
INNER JOIN grade
ON grade.sectionid = section.sectionid
INNER JOIN course
ON course.courseid = section.courseid;
DECLARE
CURSOR mycursor is
select
sectionid, studentid, courseid, coursename
FROM grade, course, section;
var_secID NUMBER(10);
var_studentID NUMBER (10);
var_gradeLetter CHAR(1);
var_coursetitle VARCHAR2(25);
BEGIN
OPEN mycursor;
LOOP
FETCH mycursor
INTO var_secID, var_studentID, var_gradeLetter, var_coursetitle;
EXIT WHEN mycursor%NOTFOUND;
If var_coursetitle(coursename,1) BETWEEN A AND F then
UPDATE grade
SET grade = 'A'
WHERE sectionid;
END IF;
END LOOP;
CLOSE mycursor;
END;
/
Keep getting this error:
ERROR at line 21:
ORA-06550: line 21, column 18:
PL/SQL: ORA-00920: invalid relational operator
ORA-06550: line 19, column 4:
PL/SQL: SQL Statement ignored
BETWEEN A AND F then
should perhaps be:
BETWEEN 'A' and 'F' then
You could do it without any PL/SQL, as:
update grade g set grade = 'A'
where g.sectionid in
( select s.sectionid from section s
join course c on c.courseid = s.courseid
where substr(c.coursename,-1, 1) between 'A' and 'F' );
However as a PL/SQL learning exercise, you could do it without any of the variable or cursor management:
begin
for r in (
select g.sectionid, g.studentid, c.courseid, c.coursename
, substr(c.coursename,-1, 1) as course_lastchar
from grade g
join section s on s.sectionid = g.sectionid
join course c on c.courseid = s.courseid
for update of grade
)
loop
if r.course_lastchar between 'A' and 'F' then
update grade set grade = 'A' where sectionid = r.sectionid;
end if;
end loop;
end;
(btw it's worth getting into the habit of laying code out neatly with a consistent indent size.)
I have nested for loop which iterates same table. In inner loop I update a column in same table. But in for loop condition I check that updated column and I need to check this column not in the beginning but dynamically, so my for loop iterations will maybe greatly decrease.
Am I doing this correct or is for statement will not see updated column?
declare
control number(1);
dup number(10);
res varchar2(5);--TRUE or FALSE
BEGIN
dup :=0;
control :=0;
FOR aRow IN (SELECT MI_PRINX, geoloc,durum, ROWID FROM ORAHAN where durum=0)
LOOP
FOR bRow IN (SELECT MI_PRINX, geoloc, ROWID FROM ORAHAN WHERE ROWID>aRow.ROWID AND durum=0)
LOOP
BEGIN
--dbms_output.put_line('aRow' || aRow.Mi_Prinx || ' bRow' || bRow.Mi_Prinx);
select SDO_GEOM.RELATE(aRow.geoloc,'anyinteract', bRow.Geoloc,0.02) into res from dual;
if (res='TRUE')
THEN
Insert INTO ORAHANCROSSES values (aRow.MI_PRINX,bRow.MI_PRINX);
UPDATE ORAHAN SET DURUM=1 where rowid=bRow.Rowid;
control :=1;
--dbms_output.put_line(' added');
END IF;
EXCEPTION
WHEN DUP_VAL_ON_INDEX
THEN
dup := dup+1;
--dbms_output.put_line('duplicate');
--continue;
END;
END LOOP;
IF(control =1)
THEN
UPDATE ORAHAN SET DURUM=1 WHERE rowid=aRow.Rowid;
END IF;
control :=0;
END LOOP;
dbms_output.put_line('duplicate: '||dup);
END ;
Note: I use oracle 11g and pl/sql developer
Sorry my english.
Yes, the FOR statement will not see the updated DURUM column because the FOR statement will see all data as they were when the query was started! This is called read consistency and Oracle accomplishes this by using the generated UNDO data. That means it'll have more and more work to do (==run slower) as your FOR loop advances and the base table is updated!
It also means that your implementation will eventually run into a ORA-01555: snapshot too old error when the UNDO tablespace is exhausted.
You'll be probably better off using a SQL MERGE statement which should also run much faster.
e.g.:
Merge Into ORAHANCROSSES C
Using (Select aROW.MI_PRINX aROW_MI_PRIX,
aROW.GEOLOC aROW_GEOLOC,
bROW.MI_PRINX bROW_MI_PRIX,
bROW.GEOLOC bROW_GEOLOC,
SDO_GEOM.RELATE(aRow.geoloc,'anyinteract', bRow.Geoloc,0.02) RES
From ORAHAN aROW,
ORAHAN bROW
Where aROW.ROWID < bROW.ROWID
) Q
On (C.MI_PRIX1 = Q.aROW_MI_PRIX
and C.MI_PRIX2 = Q.bROW_MI_PRIX)
When Matched Then
Delete Where Q.RES = 'FALSE'
When Not Matched Then
Insert Values (Q.aROW_MI_PRIX, Q.bROW_MI_PRIX)
Where Q.RES = 'TRUE'
;
I'm not sure what you're trying to accomplish by ROWID>aRow.ROWID though
To use a certain order (in this case MI_PRINX) use the following technique:
Merge Into ORAHANCROSSES C
Using (With D as (select T.*, ROWNUM RN from (select MI_PRINX, GEOLOC from ORAHAN order by MI_PRINX) T)
Select aROW.MI_PRINX aROW_MI_PRIX,
aROW.GEOLOC aROW_GEOLOC,
bROW.MI_PRINX bROW_MI_PRIX,
bROW.GEOLOC bROW_GEOLOC,
SDO_GEOM.RELATE(aRow.geoloc,'anyinteract', bRow.Geoloc,0.02) RES
From D aROW,
D bROW
Where aROW.RN < bROW.RN
) Q
On (C.MI_PRIX1 = Q.aROW_MI_PRIX
and C.MI_PRIX2 = Q.bROW_MI_PRIX)
When Matched Then
Delete Where Q.RES = 'FALSE'
When Not Matched Then
Insert Values (Q.aROW_MI_PRIX, Q.bROW_MI_PRIX)
Where Q.RES = 'TRUE'
;
In case the query is taking too long, you might select * from v$session_longops where seconds_remaining >0 to find out when it'll be finished.