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

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

Related

Delete data based on the count & timestamp using pl\sql

I'm new to PL\SQL programming and I'm from DBA background. I got one requirement to delete data from both main table and reference table but need to follow below logic while deleting data because we need to delete 30M of data from the tables so we're reducing data based on the "State_ID" column below.
Following conditions need to consider
1. As per sample data given below(Main Table), sort data based on timestamp with desc order and leave the first 2 rows of data for each "State_id" and delete rest of the data from the both tables based on "state_id" column.
2. select state_id,count() from maintable group by state_id order by timestamp desc Having count()>2;
So if state_id=1 has 5 rows then has to delete 3 rows of data by leaving first 2 rows for state_id=1 and repeat for other state_id values.
Also same matching data should be deleted from the reference table as well.
Please someone help me on this issue. Thanks.
enter image description here
Main table
You should be able to do each table delete as a single SQL command. Anything else would essentially force row-by-row processing, which is the last thing you want for that much data. Something like this:
delete from main_table m
where m.row_id not in (
with keep_me as (
select row_id,
row_number() over (partition by state_id
order by time_stamp desc) id_row_number
from main_table where id_row_number<3)
select row_id from keep_me)
or
delete from main_table m
where m.row_id in (
with delete_me as (
select row_id,
row_number() over (partition by state_id
order by time_stamp desc) id_row_number
from main_table where id_row_number>2)
select row_id from delete_me)

Print column2 from row with max(column1) without including column2 in group by clause

I know it is a silly question and may be already answered somewhere, please guide me to the link if it is.
I want to print a column which is not included in group by clause. Oracle says that it should be included in group by expression, but I want value to be from the same row from which max() value for the other column was selected.
For example: if I have a table with following columns:
Employee_Name, Action_code, Action_Name
I want to see the name of action with maximum action_code for each employee, also I cannot use subquery in the condition.
I want some thing like this:
select employee_name, max(action_code), action_name --for max code
from emp_table
group by employee_name
This action_name in select statement is causing problem, if I add action_name in group by clause then it will show action name for each action for each employee, which will make the query meaningless.
Thanks for support
You can use a keep .. last pattern:
select employee_name,
max(action_code) as action_code,
max(action_name) keep (dense_rank last order by action_code) as action_name
from emp_table
group by employee_name
The documentation explains this more fully under the sister function first().

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 :)

Group by, avg difficulties in SQLPlus

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.

Resources