this code has to sum salary of employees of department_id 100.so it gives this error "missing right parenthesis"
DECLARE
v_department_name VARCHAR(100);
v_department_manager VARCHAR(100);
v_totalsalary NUMBER(30);
BEGIN
SELECT departments.department_name, concat(employees.first_name,
employees.last_name), employees.salary INTO v_department_name,
v_department_manager, v_totalsalary
FROM employees JOIN departments ON employees.department_id =
departments.department_id
WHERE employees.salary = (SELECT departments.department_id,
sum(employees.salary)
FROM EMPLOYEES
where departments.department_id=100
GROUP BY DEPARTMENT_ID
ORDER BY DEPARTMENT_ID);
DBMS_OUTPUT.PUT_LINE ('Department Name is : ' || v_department_name || 'And
Department Manager is : ' || v_department_manager || 'Total Amount of Salary
is : ' || v_totalsalary );
END;
The "missing right parenthesis" error is clearly caused by the ORDER BY clause in the subquery (where it is not allowed).
Once you clear that error, you get the "too many values" error, because you are comparing a single variable (salary) to the output from a subquery that returns two values (department_id AND sum(salary)). Not sure why you thought you need to include the department_id in the SELECT clause of the subquery.
When you include error messages in your question, include the full text of the message (which shows the line number and position at which the error occurred - a crucial detail!)
Take it one small step at a time. Forget for the moment PL/SQL; are you able to write the correct query in SQL, which will return the department name, the manager's name and the sum of the salaries of all the employees in the department? If you can do that, then the PL/SQL around it is easy.
Here is one way to get all the values in one SQL statement:
select d.department_name,
m.first_name || ' ' || m.last_name as manager_name,
sum(e.salary) as sum_salary
from departments d
join
employees m on d.manager_id = m.employee_id
join
employees e on d.department_id = e.department_id
where d.department_id = 100
group by d.department_id, d.department_name, m.first_name, m.last_name
;
DEPARTMENT_NAME MANAGER_NAME SUM_SALARY
--------------- --------------- ----------
Finance Nancy Greenberg 51608
Perhaps 80% of writing good PL/SQL code is simply writing good, efficient SQL statements. If you have any difficulty with this query, you should probably spend the majority of your time writing SQL statements, for the next few days or weeks; return to PL/SQL when you feel this query (in my answer) is "simple", "easy", "standard" (which it is!)
Related
I have created a cursor that has two queries joined with inner join, but query is not compiling their is error at the end of first query but the same query is getting executed without cursor.
cursor data is
select * from
select rid,id, order from table1
inner join
select pid, name, order from table2
on table1.order = table2.order
original query is much bigger and complicated but end result would be this.
Their are compilation errors at the end of first query and those are generic nature, I guess may be syntax for creating a two joined queries is wrong (this is a wild guess though)
Error:
SQL statement ignored //at select word of first query
Missing right parenthesis //at the last word of first query
Example based on Scott's schema:
SELECT should contain column aliases if columns returned by those inline views share the same name; otherwise, you won't know which one you're using
inline views should have their own aliases; basically, that's always a good idea - prefix columns with table aliases, otherwise you'll soon forget which column belongs to which table
SQL> declare
2 cursor data is
3 select a.empno a_empno, b.ename b_ename
4 from (select empno, ename, deptno from emp) a
5 inner join
6 (select empno, ename, deptno from emp) b
7 on a.deptno = b.deptno
8 where rownum < 5;
9 begin
10 for data_r in data loop
11 dbms_output.put_line(data_r.b_ename);
12 end loop;
13 end;
14 /
SMITH
JONES
SCOTT
ADAMS
PL/SQL procedure successfully completed.
SQL>
You have to put your subqueries in parenthesis and add aliases for the subqueries:
cursor data is
select * from
(select rid,id, order from table1) table1
inner join
(select pid, name, order from table2) table2
on table1.order = table2.order
Here is another answer for you, with just small differences and with an example:
CREATE OR REPLACE PROCEDURE p_test(n_test in number)
AS
CURSOR data
IS
SELECT *
FROM
(SELECT rid
, id
, "order" or1
FROM table1) tab1
INNER JOIN
(SELECT pid
, name
, "order" or1
FROM table2 ) tab2
ON tab1.or1 = tab2.or1;
BEGIN
FOR data_i IN data LOOP
DBMS_OUTPUT.PUT_LINE(data_i.rid);
END LOOP;
END p_test;
Here is the DEMO
Here is what I am supposed to do. Assume that the tables are created, and all the columns are correctly named
"Using stored procedures and cursors, display the location (including street, zip code, city and country) of the managers with job id of either IT_PROG or SA_MAN and with salary greater than 3000".
Here is the code I have written so far but the sql statement for the cursor doesn't seem to want to work. For the DEPARTMENTS Table the FK's are MANAGER_ID and LOCATION_ID, for the EMPLOYEES Table the FK is JOB_ID and the LOCATIONS table has no FK. All the primary keys are set
Here is the code:
create or replace procedure mgtLocation
is
cursor getLoc is
select LOCATIONS.STREET_ADDRESS, LOCATIONS.POSTAL_CODE, LOCATIONS.CITY,
LOCATIONS.COUNTRY, LOCATIONS.LOCATIONS_ID, LOCATIONS.LOCATIONS_ID
from LOCATIONS
inner join DEPARTMENTS on DEPARTMENTS.MANAGER_ID = EMPLOYEES.EMPLOYEE_ID
inner join LOCATIONS on LOCATIONS.LOCATION_ID = DEPARTMENTS.LOCATION_ID
where EMPLOYEES.Job_ID in (select Job_ID from EMPLOYEES where Job_ID = 'IT_PROG' or Job_ID = 'SA_MAN' and SALARY > 3000);
EmpLoc getLoc%rowtype;
begin
dbms_output.put_line('=================');
open getLoc;
loop
fetch getLoc into EmpLoc;
EXIT WHEN getLoc%NOTFOUND;
dbms_output.put_line('Street: ' || EmpLoc.STREET_ADDRESS ||
' Zip Code: ' || EmpLoc.POSTAL_CODE ||
' City: ' || EmpLoc.CITY ||
' Country: ' || EmpLoc.COUNTRY);
end loop;
dbms_output.put_line('=================');
close getLoc;
end;
/
execute mgtLocation;
I get an error for the inner joins and I cannot seem to figure out how to fix them in order for this to work.
You could try this:
cursor getLoc is
select LOCATIONS.STREET_ADDRESS,
LOCATIONS.POSTAL_CODE, LOCATIONS.CITY,
LOCATIONS.COUNTRY, LOCATIONS.LOCATIONS_ID,
LOCATIONS.LOCATIONS_ID
from LOCATIONS
inner join DEPARTMENTS on
DEPARTMENTS.LOCATION_ID = LOCATIONS.LOCATION_ID
inner join EMPLOYEES on
EMPLOYEES.EMPLOYEE_ID =
DEPARTMENTS.MANAGER_ID
where (EMPLOYEES.Job_ID = 'IT_PROG' or
EMPLOYEES.Job_ID = 'SA_MAN')
and SALARY > 3000;
I am running below query
Select location, sum(units) as Units
from
( Select a.from_loc as location, sum(units) as units
from emp a, dept b
where a.id=b.id
Union all
Select a.to_loc as location, sum(units) as units
feom emp a, dept b
where a.id=b.id)
group by location;
Above query is giving me data in below format.
Location | sum(Units)
--------------------
100 | 350
200 | 450
Now i need to update another table Class with units given by above query.
Class is having Location as primary key column and units column also.
I tried to create a cursor but its throwing error, for update cannot be used
Here is snippet of cursor code
Declare
V_location number(20);
V_units (20),
Cursor c1 is
Select location, sum(units) as Units
from
( Select a.from_loc as location, sum(units) as units
from emp a, dept b
where a.id=b.id
Union all
Select a.to_loc as location, sum(units) as units
from emp a, dept b
where a.id=b.id)
group by location -----above select query
for update;
Begin
Open c1;
Loop
Fetch c1 into v_location, v_units;
Exit when c1%notfound;
Update class set units=v_units
where location=v_location;
End loop;
Close c1;
End;
Its throwing For update of this query expression is not allowed
Could someone please let me know what i am doing wrong in here. Or some other approach to update the class table
Would this do any good?
I presume that the FOR UPDATE clause causes problems
I removed the whole DECLARE section and used your SELECT statement in a cursor FOR loop as it is easier to maintain (no opening, closing, exiting, ...)
BEGIN
FOR cur_r IN ( SELECT location, SUM (units) AS units
FROM (SELECT a.from_loc AS location, SUM (units) AS units
FROM emp a, dept b
WHERE a.id = b.id
UNION ALL
SELECT a.to_loc AS location, SUM (units) AS units
FROM emp a, dept b
WHERE a.id = b.id)
GROUP BY location)
LOOP
UPDATE class
SET units = cur_r.units
WHERE location = cur_r.location;
END LOOP;
END;
[EDIT, after reading a comment]
IF-THEN-ELSE is to be done using CASE (or DECODE); for example:
update class set
units = case when location between 1 and 100 then cur_r.units / 10
else cur_r.units / 20
end
where location = cur_r.location
I have 2 tables - one with 1 million records, and the other with 40000 records.
I need to compare for each record in a table if there's a similar string on the other table.
the thing is that this procedure is very slow
I need optimize this procedure
for tablea in
( select first_name||' '||last_name as fullname from employee )
loop
SELECT COUNT(*)
INTO num_coincidencias
FROM table b
WHERE utl_match.jaro_winkler_similarity(b.name ,tablea .fullname) > 98
dbms_output.put_line(num_coincidencias);
end loop;
You do realize you are doing 40 billion comparisons? This is going to take a long time no matter what method you use.
Turning this into a SQL statement will eliminate context switches, I don't know if your computer has the resources to do it all in a single SQL statement:
SELECT COUNT (*) c, a.first_name || ' ' || a.last_name full_name
FROM employee a CROSS JOIN tableb b
WHERE UTL_MATCH.jaro_winkler_similarity (b.first_name, a.first_name || a.last_name) > 98
GROUP BY a.first_name || ' ' || a.last_name
I am attempting to write a query that returns the the number of employees, the average salary, and the number of employees paid below the average.
The query I have so far is:
select trunc(avg(salary)) "Average Pay",
count(salary) "Total Employees",
(
select count(salary)
from employees
where salary < (select avg(salary) from employees)
) UnderPaid
from employees;
But when I run this I get the ora-00937 error in the subquery.
I had thought that maybe the "count" function is what is causing the issue, but even running a simpler sub query such as:
select trunc(avg(salary)) "Average Pay",
count(salary) "Total Employees",
(
select avg(salary) from employees
) UnderPaid
from employees;
still returns the same error. As both AVG and COUNT seem to be aggregate functions, I'm not sure why I'm getting the error?
Thanks
When you use scala subquery, which is a subquery in the select list, it should return only one row.
In general, subquery can return multiple rows. So when you use it in the select list with aggregation function, you should wrap it with aggregation function that has no side effect.
select count(*), (select count(*) from emp) from emp
-- ERROR. Oracle doesn't know that the subquery returns only 1 row.
select count(*), max((select count(*) from emp)) from emp
-- You know that the subquery returns 1 row, applying max() results the same.
Or you can rewrite the query like this:
select avg(salary), count(*), count(case when salary < sal_avg then 1 end)
from (select salary, avg(salary) over () sal_avg from emp);
ntalbs' answer works (thanks, ntalbs!), but see question "ORA-00937: Not a single-group group function - Query error" for a more complete explanation if you want one.