CONNECT BY Function not working with column of DATE datatype? - sql

I am trying to build a table of another table by using the connect by prior and connect by root function (ORACLE) so that I have a table that shows all employees and their manager but also the manager of the manager to the ceo (so if the employee has 5 managers above him in the hierarchy, there are 5 rows for this employee). As part of a larger cte, it works fine. Now however, I want to include a date column from the base table.
The base table kinda looks like this:
employeeID
employeeName
managerID
managerName
dateColumn
12345
Miller
45454
Hawkins
21/02/2021
Now I am creating a new table out of this base table:
SELECT distinct employeeID, employeeName, managerName, CONNECT_BY_ROOT managerID as managerID
FROM basetable
CONNECT BY PRIOR employeeID = managerID
Now this works perfectly fine and I get the results I expected (load is < 1 second).
HOWEVER, when I include dateColumn (Datatype: DATE) inside the select, It will not stop loading (I waited 40 minutes), why is this the case?
Edit:
As requested by MT(), a few more details:
This is the CTE I am trying to use. Without dateColumn, it is working fine.
insert into targettable(EMP_ID, EMP_FORENAME, EMP_SURNAME, MGR_SURNAME, MGR_ID, date_Column)
with employees as (
select employeeID,
employeeForename,
employeeSurname,
managerName,
managerID,
trunc(dateColumn) as dateColumn
from basetable
where employeeSurname is not null
),
hierarchy as (
SELECT distinct employeeID,
employeeForename,
employeeSurname,
managerName,
CONNECT_BY_ROOT managerID as managerID,
trunc(dateColumn) as dateColumn
FROM employees e1
CONNECT BY PRIOR employeeID = managerID
),
base as (
select distinct e1.employeeID, e1.employeeForename, e1.employeeSurname, e2.employeeForename || ' ' || e2.employeeSurname managerName, e1.managerID, trunc(e1.dateColumn) as dateColumn
from hierarchy e1
left join employees e2 on e1.managerID = e2.employeeID)
select *
from base
where managerID is not null;

One reason may be that, in Oracle, a DATE data type is a binary data-type that consists of 7 bytes representing century, year-of-century, month, day, hour, minute and second. it ALWAYS has those 7 components and it is NEVER stored in any particular human-readable format.
When you are displaying the results, your client application appears to be defaulting to only display the century through day components and is not displaying the hour through second components; however those components still exist.
Therefore, when you do:
SELECT distinct
employeeID,
employeeName,
managerName,
CONNECT_BY_ROOT managerID as managerID,
dateColumn
FROM basetable
CONNECT BY PRIOR employeeID = managerID
You are getting the DISTINCT values down to the precision of a second in dateColumn but are only displaying the values to the precision of the day. This means that you are likely going to be returning a much larger data-set than you intend and the performance issues are possibly because rather than loading 100 rows for unique employees and days, instead, you are loading 100,000,000 rows for unique employees and seconds and that is going to take much more time.
You can try TRUNCating the date back to midnight:
SELECT distinct
employeeID,
employeeName,
managerName,
CONNECT_BY_ROOT managerID as managerID,
TRUNC(dateColumn) AS dateColumn
FROM basetable
CONNECT BY PRIOR employeeID = managerID

Related

SQL query which contains the order in which employees joined against each manager

I want to write a query against this table, such that it will return the list of employees in an order of date of joining as per the sequence of Manager_ID.
It should be able to tell the reportee that joined most recently for each manager.
You can try this:
SELECT *
FROM
<TABLE>
INNER JOIN
(
SELECT MANAGER_ID
, MAX(DATE_OF_JOINING) AS MAX_DATE
FROM <TABLE>
GROUP BY MANAGER_ID
) MAX_MANAGER
ON <TABLE>.MANAGER_ID = MAX_MANAGER.MANAGER_ID
AND <TABLE>.DATE_OF_JOINING = MAX_MANAGER.MAX_DATE
If two employees were hired the same day for the same manager you have two rows.

Count and group by not working as expected

select count(*),manager_id
from departments
group by manager_id;
this is my idea of how to, but it dosent gives me the amount of employees for each manager
I suspect you are selecting from the wrong table, the logic seems correct but the fact that you are selecting from a table call departments is a little suspicious.
Do you have an employee tables? Does it contains a manager_id column? If so:
select count(*),manager_id
from employees
group by manager_id;
If employee tables has only department_id column then :
SELECT d.manager_id,count(*)
FROM employees e
INNER JOIN departments d
ON(e.department_id = d.id)
Using the sample table from the HR schema
select MANAGER_ID, count(*), count(distinct EMPLOYEE_ID)
from HR.EMPLOYEES
group by MANAGER_ID
order by 1 nulls first;
gives
MANAGER_ID COUNT(*) COUNT(DISTINCTEMPLOYEE_ID)
---------- ---------- --------------------------
1 1
100 14 14
101 5 5
102 1 1
Note the first row, with manager IS NULL - i.e. there is a one employee without a manager.
Not also that I use both count(*)and count(distinct EMPLOYEE_ID). This is not relevant for this table, where EMPLOYEE_ID is PK, but in general case the former returns the number of record the latter the number of employees (which can be lower).
I have faced a similar problem of yours.
Try adding inside the count the id that you are counting ie employeeid.
If it still doesnt work after that try adding the same id in the group by.

select column from table with only matched data from another table

I need to select 2 column from table with matched data from another table or cell be null ,
table 1 named "emp" contain emp_name ,emp_id
table 2 named "salary" contain emp_sal, emp_id
I need to create select query
have all emp_name, emp_id and emp_sal (for only the employees will take sale) or be Null
thanks for help now ((((update ))))
first thanks for help
i used
SELECT emp.emp_id,emp.emp_name,salary.emp_sal FROM emp LEFT JOIN salary ON emp.emp_id = salary.emp_id;
it work but with a lot of duplication and i need to make this query with day ...
i create another table named "day" i need query appear day i entered in this table
this table have only one column and i record ((day user entered and saved in "day.user_day"))
i need to link this three tables
together
and lets make it easy we will change salary to attendance ...
i need to query all names and id in date and apear all employee what ever thy have time or not
like when i search only in day 4/8/2014
name id time
john 1 04/08/2014 06:00
man 2 null
scsv 3 04/08/2014 07:00
You want a LEFT JOIN:
SELECT * FROM emp LEFT JOIN salary ON emp.emp_id = salary.emp_id;
This will return all employees along with their emp_sal, which will be NULL if it's not in the salary table.
If what I read is right, you want to get the employee name and salary, returning all employees regardless if they have an entry in salary. If that is correct, this should work:
SELECT
e.emp_name,
e.emp_id,
s.emp_sal
FROM
emp AS e
LEFT JOIN salary AS s ON e.emp_id = s.emp_id
If, however, you only wanted the employees with an entry in the salary table, change LEFT JOIN to be INNER JOIN.

Sql Server In statement with Null values

I have the following:
select Firstname, LastName, Department
from Employee
where
Department is null
or Department in (
select Department
from Employee
group by Department
having COUNT(1) < 5)
This takes a /long/ time (over 10 minutes) and I'm assuming it's eventually time out.
I can change it to:
select Firstname, LastName, Department
from Employee
where
coalesce(Department,'') in (
select coalesce(Department,'')
from Employee
group by Department
having COUNT(1) < 5)
which, in this case, gives me what I need. It returns in 2 seconds.
If I just doing the first query with either part of the where clause returns quick. I also unioned them and it return quickly as well. Any insight on why it's freaking out when i combine them?

How to write a query to get the latest employee record given the effective date in oracle?

I have a employee and employee_history table. For every update on employee table, I insert a record into the employee_history table.
Both the tables have a column called as effective date which indicates that the employee status as on that effective date.
Below are my two tables.
I need to get the employee record latest as on that effective date.
e.g If I need to get the employee as on 16 may I should get the emp_hist_id = 2 record from history table. As on 5 june I should get the emp_hist_id = 4 from hist table.
And as on 15th August I should get the record from employee table itself.
Please help.
You could try something like
SELECT * FROM (
SELECT * FROM (
(SELECT emp_id, name, email, title, region, division, "effective date"
FROM employee
WHERE emp_id = desired_id)
UNION
(SELECT emp_id, name, email, title, region, division, "effective date"
FROM employee _history
WHERE emp_id = desired_id)
) t
WHERE t."effective date" <= desired_date
ORDER by t."effective date" DESC) p
WHERE ROWNUM = 1
The idea is to take records related to desired user from both tables, then take dates lower than desired one and finally catch the first
You can solve this problem without analytic functions. The subquery here calculates the most recent effective date in the history record before the employee effective date:
select e.*
from employee_history eh join
(select e.employee_id, max(eh.effective_date) as latest_effective_date
from employee e join
employee_history eh
on e.employee_id = eh.employee_id and
e.effective_date >= eh.effective_date
) ehl
on eh.employee_id = ehl.employee_id and
eh.effective_date = ehl.effective_date
This solution assumes that there are no duplicate effective dates in the history table. If there are, then you have another option. Assuming the employee_history_ids are assigned sequentially, take the max of that id instead of the date.
There are alternative formulations of the solution using Oracle's analytic functions.
Try the following :
SELECT *
FROM
(SELECT e.emp_id,
e.name,
e.email,
e.title,
e.region,
e.division,
e.effective_date,
row_number() over (partition BY e.emp_id
ORDER BY e.effective_date DESC) rn
FROM employee e
UNION ALL
SELECT eh.emp_id,
eh.name,
eh.email,
eh.title,
eh.region,
eh.division,
eh.effective_date,
row_number() over (partition BY eh.emp_id
ORDER BY eh.effective_date DESC) rn
FROM employee_history eh)
WHERE effective_date < to_date('15/06/2012','DD/MM/YYYY')
AND rn = 1
you can see a better example here