Group by, avg difficulties in SQLPlus - oracle

I'm trying to get an sqlplus table to give me the workers of each company who make more than the average salary of that company.
(Ex. First National Bank's average salary is $50,000. James and Jane work there and make $80,000, Billy makes $40,000. Fredco's average salary is $30,000. Employee Mark makes $35,000, and Timmy has $25,000 salary. James, Jane, and Mark's names are given as a result.)
However, I've gotten every error under the sun from trying to get it to run correctly. Any help or hints would be very appreciated.
Here's the code for the table's creation. (Ignore the foreign key references: linking to other tables that don't have any of the data needed for this query.)
create table works
(employee_name varchar(20) PRIMARY KEY,
company_name varchar(30) NOT NULL,
salary numeric(9, 2) NOT NULL,
foreign key (employee_name) references employee,
foreign key (company_name) references company);
And here's what I have. As of right now, error ORA-01427 is the response. (single row subquery returns more than one row.)
select employee_name
from works
where salary > (select avg(salary)
from works
group by company_name);
Thank you for any hints or help in advance.

use below query:
select w.employee_name from works w
join (select company_name,avg(salary) salary
from works
group by company_name) q on w.company_name=q.company_name and w.salary > q.salary;
SQLFIDDLE DEMO

How about something like:
select employee_name
from (select employee_name, salary, avg(salary) over (partition by company_name) avg_co_salary
from works)
where salary > avg_co_salary;
It may be faster than doing two passes through the works table, but then again, perhaps not - it all depends on your data, indexes etc. You'd have to test.

Related

ORACLE SQL:Can someone explain me the difference between these two?

I'm a student and this is my first year of learning Oracle SQL. On the exam, I used this code:
SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING INSTR(TO_CHAR(department_id),'5')!=1 AND MAX(salary)<1000;
and the professor said that I should be using something like
SELECT DEPARTMENT_ID, MAX(SALARY)
FROM EMPLOYEES
WHERE SUBSTR(TO_CHAR(DEPARTMENT_ID),1,1)<>'5'
GROUP BY DEPARTMENT_ID
HAVING MAX(SALARY) < 1000;
We got the same table so my question is when these two can display different results. I'm aware that data processing is different but as he said that was not the problem. The problem is not is using the INSTR function but not using WHERE.
The Where clause workn on the raw contents of the rows
so you filter the dataset that is evaluated for the select clause
WHERE SUBSTR(TO_CHAR(DEPARTMENT_ID),1,1)<>'5'
don't select the rows with
SUBSTR(TO_CHAR(DEPARTMENT_ID),1,1)='5'
so these rows are not used for
SELECT DEPARTMENT_ID, MAX(SALARY) ..GROUP BY DEPARTMENT_ID
HAVING work on the result of the selected result so also the rows with SUBSTR(TO_CHAR(DEPARTMENT_ID),1,1)='5' should be processed
in your case each value for the column DEPARTMENT_ID is always selected because is mentioned in group by and then both the query should return the same result

Oracle view that passes values from a table to a function?

I am trying to create an Oracle view that will show two columns:
Employee_ID, Department_ID
To get department_id, I need to pass an employee_id into a function which I am doing today with:
select * from TABLE(user.fn_department('dept',employee_id)
This will give me only a list of department_ids for the employee_id I pass into it.
I can get a list of unique employees from the employee table.
How do I combine these two outputs?
Thank you!
You can use something like
CREATE OR REPLACE VIEW USER_DEPT_VIEW AS
SELECT e.EMPLOYEE_ID,
USER.FN_DEPARTMENT('dept', e.EMPLOYEE_ID) AS DEPARTMENT_ID
FROM EMPLOYEE e;
which you could then use as e.g.
SELECT *
FROM USER_dEPT_VIEW
WHERE EMPLOYEE_ID = 1234
Best of luck.
Try this,
SELECT b.employee_id, a.department_id
FROM employees b, table(user.fn_department('dept',b.employee_id)) a
ORDER by b.employee_id

Sybase insert into temp table with identity column

I'm trying to insert records for couple of columns from a physical table into a temp table with customized IDENTITY. It creates the identity column (field name = idnum), but the values are 0 for all rows. I'm using below code. If anyone can help me what I'm doing wrong would be greatly appreciated.
Note: I'm trying this is Sybase ASE 15.7
SELECT
* INTO #achu_test
FROM (SELECT TOP 10
idnum = IDENTITY(8),
First_Name,
Last_Name
FROM Employees) myTable
My bad! I misplaced the IDENTITY. instead of using it before "* INTO", I used inside the Subquery.
SELECT idnum = IDENTITY(8),* INTO #achu_test
FROM (SELECT TOP 10 First_Name, Last_Name FROM Employees) myTable
A good sleep might have given the result for me :)

Fetch data from a table in oracle sql

I've two table in the database, the first one is Person and the second is Pilot. as following:
Person Table:
CREATE TABLE person(
person_id NUMBER PRIMARY KEY,
last_name VARCHAR2(30) NOT NULL,
first_name VARCHAR2(30) NOT NULL,
hire_date VARCHAR2(30) NOT NULL,
job_type CHAR NOT NULL,
job_status CHAR NOT NULL
);
/
INSERT INTO person VALUES (1000, 'Smith', 'Ryan', '04-MAY-90','F', 'I');
INSERT INTO person VALUES (1170, 'Brown', 'Dean', '01-DEC-92','P', 'A');
INSERT INTO person VALUES (2010, 'Fisher', 'Jane', '12-FEB-95','F', 'I');
INSERT INTO person VALUES (2080, 'Brewster', 'Andre', '28-JUL-98', 'F', 'A');
INSERT INTO person VALUES (3190, 'Clark', 'Dan', '04-APR-01','P', 'A');
INSERT INTO person VALUES (3500, 'Jackson', 'Tyler', '01-NOV-05', 'F', 'A');
INSERT INTO person VALUES (4000, 'Miller', 'Mary', '11-JAN-08', 'F', 'A');
INSERT INTO person VALUES (4100, 'Jackson', 'Peter', '08-AUG-11', 'P','I');
INSERT INTO person VALUES (4200, 'Smith', 'Ryan', '08-DEC-12', 'F','A');
COMMIT;
/
Pilot Table:
CREATE TABLE pilot(
person_id NUMBER PRIMARY KEY,
pilot_type VARCHAR2(100) NOT NULL,
CONSTRAINT fk_person_pilot FOREIGN KEY (person_id)
REFERENCES person(person_id)
);
/
INSERT INTO pilot VALUES (1170, 'Commercial pilot');
INSERT INTO pilot VALUES (2010, 'Airline transport pilot');
INSERT INTO pilot VALUES (3500, 'Airline transport pilot');
COMMIT;
/
I'm asked to write a pl/sql block of code that accepts the last name from the user and return the result as following:
1) if the last name is not in the table, it returns all the rows in the table.
2) if the last name is in the table, it shows all of the employee's information.
So far I'm doing well with the code, but I got stuck in the case that there are two employees with the last name. here is the cursor that I wrote:
cursor person_info is
select last_name, first_name, hire_date, job_type, job_status, nvl(pilot_type, '-----------')
from person
full outer join pilot
on person.person_id = pilot.person_id
where upper(last_name) = upper(v_last_name)
group by last_name, first_name, hire_date, job_type, job_status, pilot_type
order by last_name, first_name, hire_date asc;
Logically, there are three cases to be covered:
the first case, when the entered last name is in the table, I return all the rows in the table and that's done.
The second case when there is only one employee with the entered last name, and this case is done as well. The last case when there are more than one employee having the same last name like for example 'Jackson' or 'Smith' in this case, my program crashes and give me the error that my select into statement returns more than one row.
select person_id
into v_n
from person
where upper(last_name) = upper(v_last_name);
if v_n = 1 then
open person_info;
fetch person_info into v_last_name, v_first_name, v_hire_date, v_job_type, v_job_status, v_pilot_type;
Can someone help me in guiding me how to fetch the data correctly? I'm not allowed to create any temporary tables or views.
I'm so sorry for making the problem longer than it should, but I was trying to be as clear as possible in explaining the problem.
Thank you in advance.
if the error is
"ORA-01422 exact fetch returns more than requested number of rows" then I think your answer is here https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:981494932508
If you EXPECT the query to return more than one row, you would code:
for x in ( select * from t where ... )
loop
-- process the X record here
end loop;
Your immediate issue is that you're selecting the matching person_id into a variable, and then seeing if that specific ID is 1. You don't have an actual ID 1 anyway so that check would never match; but it is that querying matching multiple rows that gets the error, as you can't put two matching IDs into a single scalar variable.
The way you've structured it looks like you are trying to count how many matching rows there are, rather than looking for a specific ID:
select count(person_id)
into v_n
from person
where upper(last_name) = upper(v_last_name);
if v_n = 1 then
....
When you do have multiple matches then you will need to use the same mechanism to return all of those as you do when there are no matches and you return all employees. You may find the logic should be in the cursor query rather then in PL/SQL logic. It depends on the details of the assignment though, and how it expects you to return the data in both (or all three) scenarios.
It's also possible you just aren't expected to hit this problem - it isn't clear if the assignment is finding all employees, or only those that are pilots. The issue still exists in general, but with the data you show there aren't any duplicate pilot last names. If you haven't learned about this kind of error yet perhaps you're getting a bit ahead of what your tutor expects.

Updating a view in oracle

Below, I have defined some tables, for the relevant ones I have typed in the definitions. Pretty simple, though now I'm trying to raise the salaries for those two employees in the view, and I can't complete the update having that error message you will see below. Anyone could guide me a bit, please??
Definitions for tables employees, projects and employees_projects:
create table employee
(
id number,
name varchar2(20),
mobile varchar2(10),
address varchar2(30),
salary number(6,2),
hire_date date,
department_id number
);
create table project
(
id number,
name varchar2(20),
budget number(10,2),
start_date date,
finish_date date
);
create table employee_projects
(
id number,
employee_id number,
project_id number
);
View definition is:
create view lucky_employees as
select e.name,e.salary from employees e, project p, employee_projects ep
where e.project_id=p.id and e.id=ep.employee_id and p.budget > 1000000.00 ;
SQL> select * from lucky_employees;
ID NAME SALARY
1 Maria 1365.28
2 Sonja 1365.28
Then, I try to update the view by 10%, which is something I know it's possible to do under certain conditions:
SQL>
update lucky_employees set salary = salary * 1.1;
update lucky_employees set salary = salary * 1.1
*
ERROR at line 1:
ORA-01779: cannot modify a column which maps to a non key-preserved table
How would it be to succesfully update it??
Thanks very much, sorry for the inconveniences!!
create view lucky_employees as
select e.name from employees e, project p, employee_projects ep
where e.project_id=p.id and e.id=ep.employee_id and p.budget > 1000000.00 ;
This error is occurring because each salary of your view doesnot uniquely map to a salary of your employees table.
More information from oracle docs is here.
Anoter explanation from Burleson here.

Resources