dense_rank() function equivalent in access database - sql

As we have dense_rank function in sql server do we any equivalent in access?
I have a table
employee_name employee_address
RON 23-B, TORONTO
PETER 15-C, NY
TED 23-C, LONDON
RON 23-B, TORONTO
I have to add new column to this table as follows:
employee_name employee_address employee_no
RON 23-B, TORONTO 1
PETER 15-C, NY 2
TED 23-C, LONDON 3
RON 23-B, TORONTO 1

I assume you want to port in Access a SQL Server query like this:
SELECT *
,DENSE_RANK() OVER(ORDER BY employee_name, employee_address) AS DenseRank
FROM Employee.
The main idea is to generate a list with distinct employee_name & employee_address values and then we generate row numbers without gaps for every distinct tuple. At final step, we make a JOIN between the initial data set (Employee table) and the last data set (which has row numbers for every distinct employee_name & employee_address tuple).
Solution 1
Query0
CREATE TABLE Employee
(
employee_id INT PRIMARY KEY
,employee_name VARCHAR(100) NOT NULL
,employee_address VARCHAR(100) NOT NULL
);
Query1
INSERT INTO Employee (employee_id, employee_name, employee_address)
VALUES (1,'RON','23-B, TORONTO');
Query2
INSERT INTO Employee (employee_id, employee_name, employee_address)
VALUES (2,'PETER','15-C, NY');
Query3
INSERT INTO Employee (employee_id, employee_name, employee_address)
VALUES (3,'TED','23-C, LONDON');
Query4
INSERT INTO Employee (employee_id, employee_name, employee_address)
VALUES (4,'SORIN','09-S, VASCAUTI');
Query5
INSERT INTO Employee (employee_id, employee_name, employee_address)
VALUES (5,'RON','23-B, TORONTO');
Query6
INSERT INTO Employee (employee_id, employee_name, employee_address)
VALUES (6,'PETER','15-C, NY');
Query7
INSERT INTO Employee (employee_id, employee_name, employee_address)
VALUES (7,'SORIN','09-S, VASCAUTI');
Query8
INSERT INTO Employee (employee_id, employee_name, employee_address)
VALUES (8,'PETER','15-C, NY');
So, the Employee content will be:
employee_id employee_name employee_address
----------- ---------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------
1 RON 23-B, TORONTO
2 PETER 15-C, NY
3 TED 23-C, LONDON
4 SORIN 09-S, VASCAUTI
5 RON 23-B, TORONTO
6 PETER 15-C, NY
7 SORIN 09-S, VASCAUTI
8 PETER 15-C, NY
Query9 We generate row numbers for every employee_name & employee_address tuple
CREATE TABLE TmpEmployee
(
rownumber COUNTER(1,1) PRIMARY KEY
,employee_name VARCHAR(100) NOT NULL
,employee_address VARCHAR(100) NOT NULL
);
(COUNTER(1,1) is Access/SQL AutoNumber data type; before every Query10 execution you need to recreate TmpEmployee table or you need to compact Access DB to reset rownumber counter to 1) and
Query10
INSERT INTO TmpEmployee (employee_name, employee_address)
SELECT e.employee_name, e.employee_address
FROM Employee e
GROUP BY e.employee_name, e.employee_address
Results:
rownumber employee_name employee_address
----------- ---------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------
1 PETER 15-C, NY
2 RON 23-B, TORONTO
3 SORIN 09-S, VASCAUTI
4 TED 23-C, LONDON
Query11 The final results:
SELECT e.*, t.RowNumber AS DenseRank
FROM Employee e
INNER JOIN TmpEmployee t ON e.employee_name = t.employee_name AND e.employee_address = t.employee_address
ORDER BY e.employee_name, e.employee_address
Results:
2 PETER 15-C, NY 1
6 PETER 15-C, NY 1
8 PETER 15-C, NY 1
5 RON 23-B, TORONTO 2
1 RON 23-B, TORONTO 2
4 SORIN 09-S, VASCAUTI 3
7 SORIN 09-S, VASCAUTI 3
3 TED 23-C, LONDON 4
Solution 2
Query9 The final results:
SELECT e.*, c.RowNumber
FROM Employee e INNER JOIN
(
SELECT a.employee_name, a.employee_address, COUNT(b.employee_name) AS RowNumber
FROM
(
SELECT e.employee_name, e.employee_address
FROM Employee e
GROUP BY e.employee_name, e.employee_address
) a,
(
SELECT e.employee_name, e.employee_address
FROM Employee e
GROUP BY e.employee_name, e.employee_address
) b
WHERE a.employee_name > b.employee_name OR a.employee_name = b.employee_name AND a.employee_address >= b.employee_address
GROUP BY a.employee_name, a.employee_address
) c ON e.employee_name = c.employee_name AND e.employee_address = c.employee_address
ORDER BY c.employee_name, c.employee_address

Related

Update using joins by finding the previous value in sql

I have two tables and I have to update the address field in the emp table by looking up in the emphistory table with previous value i.e USA for employee John
Table emp
EId ename sal Address AccountId
-------------------------------
101 John 100 U X12
102 Peter 500 Null X13
Table emphistory
emphisid EId AccountId Address Date (use row_number to find the second record for that eid and accountid)
-----------------------------------------------------
1 101 X12 U 11-01-2020 09:45:00
2 102 X13 Null 11-01-2020 09:46:00
3. 101 X12 USA 11-01-2020 09:30:00
I have to join the tables with account id and eid.
This works in Postgresql & Sql Server
UPDATE emp
SET Address = hist.Address
FROM (
SELECT h.EId, h.AccountId, h.Address
, ROW_NUMBER() OVER (PARTITION BY h.EId, h.AccountId
ORDER BY h.Date DESC) AS Rn
FROM emphistory h
JOIN emp e
ON e.EId = h.EId
AND e.AccountId = h.AccountId
WHERE h.Address IS NOT NULL
) hist
WHERE emp.EId = hist.EId
AND hist.Rn = 2

Remove duplicate rows in Postgres

I have two tables:
Employee:
ID
Name
Surname
143
Amy
Flowers
245
Natasha
Smith
365
John
Alexander
445
Natasha
Smith
565
Monica
Withhouse
644
Amy
Flowers
1023
Amy
Alexander
And employee_details:
ID
Employee_id
Document_numer
1
644
XXXXXXXXX
2
245
XXXXXX
3
365
XXXXXX
I need to remove duplicate records that are in the Employee table and that are not related to the employee_details table. In the example data, I would like to delete the employee doublet with the id 143 and 445.
And I must admit that I have no idea how to do it.Could you give me a hint?
The base is postgres
Delete from Employee
Where id not in (
Select Employee_id
from employee_details
)
and name in (
Select name
from Employee
Group by name having count(name) > 1
)
Though the question is already answered I am adding two different answers here using cte.
create table Employee(ID int, Name varchar(50), Surname varchar(50));
insert into Employee values(143, 'Amy', 'Flowers');
insert into Employee values(245, 'Natasha', 'Smith');
insert into Employee values(365, 'John', 'Alexander');
insert into Employee values(445, 'Natasha', 'Smith');
insert into Employee values(565, 'Monica', 'Withhouse');
insert into Employee values(644, 'Amy', 'Flowers');
insert into Employee values(1023, 'Amy', 'Alexander');
create table employee_details ( ID int, Employee_id int, Document_numer varchar(50));
insert into employee_details values(1, 644, 'XXXXXXXXX');
insert into employee_details values(2, 245, 'XXXXXX');
insert into employee_details values(3, 365, 'XXXXXX');
Delete query 1:
with duplicate_employees as
(
select * , count(id)over(partition by name,surname) duplicate_count from Employee
)
delete from Employee where id in(
select id from duplicate_employees de
where duplicate_count >1
and not exists
(
select 1 from employee_details e where e.Employee_id = de.ID
)
)
select * from employee
Output:
id
name
surname
245
Natasha
Smith
365
John
Alexander
565
Monica
Withhouse
644
Amy
Flowers
1023
Amy
Alexander
db<>fiddle here
Delete query 2:
with cte as
(
Select *, count(*)over(partition by name,surname) duplicate_count,
(case when exists
(
select 1 from employee_details ed where ed.Employee_id = e.ID
)
then 1 else 0 end) exist_in_details
from Employee e
)
delete from Employee where id in (select id from cte where duplicate_count>1 and exist_in_details=0 )
select * from Employee
Output:
id
name
surname
245
Natasha
Smith
365
John
Alexander
565
Monica
Withhouse
644
Amy
Flowers
1023
Amy
Alexander
db<>fiddle here

How to get Details of all Department(dept_id, name, dept_manager and total_employees) from tables(Department, Employee)?

Here are the details of the tables:
Employee :
emp_ID | Primary Key
emp_name | Varchar
emp_email | varchar <br>
emp_dept_id | Foreign Key
Departments :
dept_ID | Primary Key
dept_name | Varchar
emp_id | Foreign Key
Manager details are already there in the employee table.
I am using Oracle Database.
Employee:
emp_ID emp_name emp_email emp_dept_id
1 Cyrus abc#xyz.com 10
2 Andrew xyz#abc.com 20
3 Mark xyz#abc.com 10
4 Tony xyz#abc.com 10
5 Elvis xyz#abc.com 20
6 Rock xyz#abc.com 10
7 George xyz#abc.com 20
8 Mary xyz#abc.com 10
9 Thomas xyz#abc.com 20
10 Martin xyz#abc.com 10
Depqartments:
dept_id dept_name emp_id
10 Accounts 4
20 Development 9
These are the data in the tables. In Department table, emp_id(Foreign key) indicates the head/manager of the department .
You can try following query:
SELECT
D.DEPT_ID,
D.DEPT_NAME,
D.EMP_ID AS MANAGER_ID,
E.EMP_NAME AS MANAGER_NAME,
E.EMP_EMAIL AS MANAGER_EMAIL,
E.CNT AS "number of employees"
FROM
DEPARTMENT D
JOIN (
SELECT
EMP_ID,
EMP_NAME,
EMP_EMAIL,
EMP_DEPT_ID,
COUNT(1) OVER(
PARTITION BY EMP_DEPT_ID
) AS CNT
FROM
EMPLOYEE
) E ON ( E.DEPT_ID = D.EMP_DEPT_ID
AND E.EMP_ID = D.EMP_ID );
Cheers!!
This is pretty straightforward. You want to get the department details (1) and also include the employees associated with that department (2).
Get the department details:
SELECT <dept_col1>, <dept_col2>, ...
FROM Department
Get a summary of employees per department:
SELECT dept_ID, <aggregation> AS MyAgg
FROM department
GROUP BY dept_ID
Here you replace <aggregation> with whatever you're trying to find. In your case it would be COUNT(*).
Combine the two results. You want to join the data from (2) to (1). How are these two tables related? Here you write a LEFT JOIN to connect them on the PK/FK relationship:
SELECT
dept.<col1>, dept.<col2>, ...,
COALESCE(emp.MyAgg,0) AS MyAgg
FROM Department dept
LEFT JOIN (
SELECT dept_ID, <aggregation> AS MyAgg
FROM department
GROUP BY dept_ID
) emp ON dept.<FK> = emp.<PK>
Get the department manager's info by adding another LEFT JOIN:
SELECT
dept.<col1>, dept.<col2>, ...,
mgr.<col1>,
COALESCE(emp.MyAgg,0) AS MyAgg -- In case there are 0 employees
FROM Department dept
LEFT JOIN employee mgr ON dept.<FK> = mgr.<PK>
LEFT JOIN (
SELECT dept_ID, <aggregation> AS MyAgg
FROM department
GROUP BY dept_ID
) emp ON dept.<FK> = emp.<PK>
Give it a try and see how far you get. If you get stuck let me know.

How to increase the salary of an employee based on the number of children in SQL ORACLE 10G?

I have two tables: employee and dependent
Structure
- Table employee
Name Null? Type
EMPLOYEEID NOT NULL NUMBER(3)
LNAME NOT NULL VARCHAR2(15)
FNAME NOT NULL VARCHAR2(15)
POSITIONID NUMBER(1)
SUPERVISOR NUMBER(3)
HIREDATE DATE
SALARY NUMBER(6)
COMMISSION NUMBER(5)
DEPTID NUMBER(2)
QUALID NUMBER(1)
- Table Dependent
Name Null? Type
EMPLOYEEID NOT NULL NUMBER(3)
DEPENDENTID NOT NULL NUMBER(1)
DEPDOB NOT NULL DATE
RELATION NOT NULL VARCHAR2(8)
Data
- Table employee
EMPLOYEEID LNAME FNAME POSITIONID SUPERVISOR HIREDATE SALARY COMMISSION DEPTID QUALID
111 Smith John 1 15/04/60 265000 35000 10 1
246 Houston Larry 2 111 19/05/67 150000 10000 40 2
123 Roberts Sandi 2 111 02/12/91 75000 10 2
543 Dev Derek 2 111 15/03/95 80000 20000 20 1
433 McCall Alex 3 543 10/05/97 66500 20 4
135 Garner Stanley 2 111 29/02/96 45000 5000 30 5
200 Shaw Jinku 5 135 03/01/00 24500 3000 30
222 Chen Sunny 4 123 15/08/99 35000 10 3
- Table Dependent
EMPLOYEEID DEPENDENTID DEPDOB RELATION
543 1 28/09/58 Spouse
543 2 14/10/88 Son
200 1 10/06/76 Spouse
222 1 04/02/75 Spouse
222 2 23/08/97 Son
222 3 10/07/99 Daughter
111 1 12/12/45 Spouse
And I have two employees: One employee has one child, and the other has two children. I got it with the following query:
Query
SELECT employee.employeid, lname, fname, salary, dependent.relation
FROM employee INNER JOIN dependent
ON employee.employeeid = dependent.employeeid
WHERE dependent.relation = 'Daughter' OR dependent.relation = 'Son';
Result
EMPLOYEEID LNAME FNAME SALARY RELATION
543 Dev Derek 80000 Son
222 Chen Sunny 35000 Son
222 Chen Sunny 35000 Daughter
And my homework is increase the salary $ 100 per child, and I tried with the following code:
UPDATE employee
SET SALARY = salary + 100
WHERE employee.employeeid IN (
SELECT employee.EMPLOYEEID FROM employee INNER JOIN dependent
ON employee.employeeid = dependent.employeeid
WHERE dependent.relation = 'Daughter' OR dependent.relation = 'Son' );
But, i donĀ“t get the expect result. The employee "Chen" has two children, but his salary only increase once, no twice. Her final salary is $ 35100, no $ 35200.
Can anybody help me?
I can't test on Oracle version 10, but this should work fine:
Well, apparently, it doesn't work in Oracle 10 (though it does work correctly in Oracle 12). I added an alternative at the bottom of the post using merge that should work correctly.
update (
select e.salary,
d.childcnt * 100 as increase
from employee e
join (select d.employeeid, count(*) as childcnt
from dependent d
where d.relation in ('Son', 'Daughter')
group by d.employeeid) d
on d.employeeid = e.employeeid
) set salary = salary + increase
Here is another way of achieving the same thing using the merge command. This should work correctly in Oracle 10:
merge into employee dest
using (
select employeeid,
count(*) * 100 as increase
from dependent d
where relation in ('Son', 'Daughter')
group by employeeid
) src
on (src.employeeid = dest.employeeid)
when matched then
update set dest.salary = dest.salary + src.increase

oracle duplicate rows based on a single column

How can I find out duplicate rows based on a single column. I have a table in oracle which has data as given below and it has duplicates. I'm trying to select and view all rows with duplicate employee ids as explained below
EMP table:
EmpId Fname Lname Mname Jobcode Status exp_date
1 Mike Jordan A IT W 12/2014
1 Mike Jordan A IT A 12/2014
2 Angela ruth C sales P 12/2015
2 Angela ruth C IT W 12/2015
3 Kelly Mike B sales W 12/2015
From the above table i want to select all rows which duplicate empids such as below
EmpId Fname Lname Mname Jobcode Status exp_date
1 Mike Jordan A IT W 12/2014
1 Mike Jordan A IT A 12/2014
2 Angela ruth C sales P 12/2015
2 Angela ruth C IT W 12/2015
How can I do this? thank you!
SELECT a.*
FROM TableName a
INNER JOIN
(
SELECT EmpID
FROM TableName
GROUP BY EmpID
HAVING COUNT(*) > 1
) b ON a.EmpID = b.EmpID
SQLFiddle Demo
Another way, although I prefer above, is to use IN
SELECT a.*
FROM TableName a
WHERE EmpId IN
(
SELECT EmpId
FROM TableName
GROUP BY EmpId
HAVING COUNT(*) > 1
)
SQLFiddle Demo
Here's another option using a subquery and COUNT OVER PARTITION BY since you're using Oracle 11:
SELECT *
FROM (
SELECT EmpId, Fname, Lname, Mname, Jobcode, Status, exp_date,
COUNT(EmpId) OVER (PARTITION BY EmpId) EmpCount
FROM TableName
) T
WHERE EmpCount > 1
SQL Fiddle Demo (Borrowed from JW)