How can i write hired the same month employees and order? - sql

Sql, which gives the number of employees hired in the same month (or year) grouped and sequentially on date basis.
I tried to write this code, but i didn't find same hired and order.
SELECT hire_date,COUNT(hire_date)
FROM employees
GROUP BY hire_date;

This is how I understood the question.
Sample data:
SQL> select ename, hiredate from emp order by hiredate;
ENAME HIREDATE
---------- ----------
SMITH 17_12_1980
ALLEN 20_02_1981
WARD 22_02_1981
JONES 02_04_1981
BLAKE 01_05_1981
CLARK 09_06_1981
TURNER 08_09_1981
MARTIN 28_09_1981
KING 17_11_1981
JAMES 03_12_1981
FORD 03_12_1981
MILLER 23_01_1982
SCOTT 09_12_1982
ADAMS 12_01_1983
14 rows selected.
Employed in the same month:
SQL> select to_char(hiredate, 'mm.yyyy') hire_month,
2 count(*)
3 from emp
4 group by to_char(hiredate, 'mm.yyyy')
5 order by 1;
HIRE_MO COUNT(*)
------- ----------
01.1982 1
01.1983 1
02.1981 2
04.1981 1
05.1981 1
06.1981 1
09.1981 2
11.1981 1
12.1980 1
12.1981 2
12.1982 1
11 rows selected.
SQL>
Hired in the same year:
SQL> select extract(year from hiredate) hire_year,
2 count(*)
3 from emp
4 group by extract(year from hiredate)
5 order by 1;
HIRE_YEAR COUNT(*)
---------- ----------
1980 1
1981 10
1982 2
1983 1
SQL>

Related

SQL subquery COUNT for Oracle

In my Oracle database, I have two tables T1 with primary key k1, and T2 with a composite primary key k1, k2. I would like to select all columns in T1 along with the number of lines in T2 such as T1.k1 = T2.k1.
It seems simple, but I can't figure how to use the COUNT function to get this result, any idea ?
I don't have your tables so I'll try to illustrate it using Scott's sample emp and dept tables:
SQL> select * from dept t1 order by t1.deptno;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL> select deptno, empno, ename from emp order by deptno;
DEPTNO EMPNO ENAME
---------- ---------- ----------
10 7782 CLARK --> 3 employees in deptno 10
10 7839 KING
10 7934 MILLER
20 7566 JONES --> 5 employees in deptno 20
20 7902 FORD
20 7876 ADAMS
20 7369 SMITH
20 7788 SCOTT
30 7521 WARD --> 6 employees in deptno 30
30 7844 TURNER
30 7499 ALLEN
30 7900 JAMES
30 7698 BLAKE
30 7654 MARTIN
--> 0 employees in deptno 40
14 rows selected.
SQL>
A few options you might try:
Correlated subquery:
SQL> select t1.*,
2 (select count(*) from emp t2 where t2.deptno = t1.deptno) cnt
3 from dept t1
4 order by t1.deptno;
DEPTNO DNAME LOC CNT
---------- -------------- ------------- ----------
10 ACCOUNTING NEW YORK 3
20 RESEARCH DALLAS 5
30 SALES CHICAGO 6
40 OPERATIONS BOSTON 0
SQL>
(Outer) join with the COUNT function and the GROUP BY clause:
SQL> select t1.*, count(t2.rowid) cnt
2 from dept t1 left join emp t2 on t2.deptno = t1.deptno
3 group by t1.deptno, t1.dname, t1.loc
4 order by t1.deptno;
DEPTNO DNAME LOC CNT
---------- -------------- ------------- ----------
10 ACCOUNTING NEW YORK 3
20 RESEARCH DALLAS 5
30 SALES CHICAGO 6
40 OPERATIONS BOSTON 0
SQL>
(Outer) join with the COUNT function in its analytic form:
SQL> select distinct t1.*,
2 count(t2.rowid) over (partition by t1.deptno) cnt
3 from dept t1 left join emp t2 on t2.deptno = t1.deptno
4 order by t1.deptno;
DEPTNO DNAME LOC CNT
---------- -------------- ------------- ----------
10 ACCOUNTING NEW YORK 3
20 RESEARCH DALLAS 5
30 SALES CHICAGO 6
40 OPERATIONS BOSTON 0
SQL>

list values ​that are duplicated more than 4 times

I am making a join between 2 tables, where they bring me number_phone that have a relationship and I bring the times that these are repeated, however, I am trying to make a condition to the count, so that it only lists those that are repeated more than 4 times, I tried with having account and it brings me the counter all in null.
It is worth mentioning that I did not occupy group by for the count because it brought me wrong values.
SELECT
REPLACE(REPLACE(t.id_contrato,'0999',''),'0998','')as contrato ,
t.num_telefono,
conc.valor_actual,
(
SELECT COUNT('x')
FROM TBL_TELEFONO ct
WHERE ct.num_telefono = t.num_telefono
AND ct.origen_tel='TELEFONO CONTRATO'
-- HAVING COUNT(*) > 4
) as counter
FROM TBL_TELEFONO t
INNER JOIN CAM_TBL_ALERTA_CONCENTRADO conc ON t.num_telefono = conc.valor_actual
WHERE id_contrato IS NOT NULL
AND id_contrato NOT IN ('N/A')
ORDER BY 4 DESC
How can I list only those that are repeated more than 4 times?
I don't like debugging code with no sample data, so I'll try to illustrate it on Scott's sample EMP table. "Jobs" will act like your "telephone numbers".
SQL> select deptno, ename, job
2 from emp
3 order by job;
DEPTNO ENAME JOB
---------- ---------- ---------
20 SCOTT ANALYST --> 2 analysts
20 FORD ANALYST
10 MILLER CLERK --> 4 clerks
30 JAMES CLERK
20 SMITH CLERK
20 ADAMS CLERK
30 BLAKE MANAGER --> 3 managers
20 JONES MANAGER
10 CLARK MANAGER
10 KING PRESIDENT --> 1 president
30 TURNER SALESMAN --> 4 salesmen
30 MARTIN SALESMAN
30 WARD SALESMAN
30 ALLEN SALESMAN
14 rows selected.
SQL>
According to that, we'd like to fetch all clerks and salesmen as there are 4 (or more) of them.
Instead of count aggregate function, use count in its analytic form:
SQL> select deptno, ename, job,
2 count(*) over (partition by job) cnt
3 from emp
4 order by job;
DEPTNO ENAME JOB CNT
---------- ---------- --------- ----------
20 SCOTT ANALYST 2
20 FORD ANALYST 2
10 MILLER CLERK 4
30 JAMES CLERK 4
20 SMITH CLERK 4
20 ADAMS CLERK 4
30 BLAKE MANAGER 3
20 JONES MANAGER 3
10 CLARK MANAGER 3
10 KING PRESIDENT 1
30 TURNER SALESMAN 4
30 MARTIN SALESMAN 4
30 WARD SALESMAN 4
30 ALLEN SALESMAN 4
14 rows selected.
SQL>
Now things become easier: use that query as a CTE (or a subquery), and apply where clause:
SQL> with temp as
2 (select deptno, ename, job,
3 count(*) over (partition by job) cnt
4 from emp
5 )
6 select deptno, ename, job
7 from temp
8 where cnt >= 4
9 order by job;
DEPTNO ENAME JOB
---------- ---------- ---------
10 MILLER CLERK
30 JAMES CLERK
20 SMITH CLERK
20 ADAMS CLERK
30 TURNER SALESMAN
30 MARTIN SALESMAN
30 WARD SALESMAN
30 ALLEN SALESMAN
8 rows selected.
SQL>
Applied to your query (again, can't test it without any sample data):
with temp as
(select
replace(replace(t.id_contrato,'0999',''),'0998','')as contrato ,
t.num_telefono,
conc.valor_actual,
count(*) over (partition by t.num_telefono) as counter
from tbl_telefono t
inner join cam_tbl_alerta_concentrado conc on t.num_telefono = conc.valor_actual
where id_contrato is not null
and id_contrato not in ('N/A')
)
select contrato, num_telefono, valor_actual
from temp
where counter >= 4;
Join to the selection that have more than 4
SELECT
REPLACE(REPLACE(t.id_contrato,'0999',''),'0998','')as contrato ,
t.num_telefono,
conc.valor_actual,
ct.counter
FROM TBL_TELEFONO t
INNER JOIN (
SELECT num_telefono, COUNT(*) AS counter
FROM TBL_TELEFONO
WHERE origen_tel='TELEFONO CONTRATO'
GROUP BY num_telefono
HAVING COUNT(*) > 4
) ct
ON ct.num_telefono = t.num_telefono
INNER JOIN CAM_TBL_ALERTA_CONCENTRADO conc
ON t.num_telefono = conc.valor_actual
WHERE id_contrato IS NOT NULL
AND id_contrato NOT IN ('N/A')
ORDER BY ct.counter DESC
Wrap the query in another to return only where count > 4
select *
from (
<your query, but without order by>
) x
where count > 4
order by count desc

About "group function is not allowed here"

I have a table with job, salary and date columns. I am writing the following query in PL/SQL, but I am getting an error
group function is not allowed here
delete employees where date = '06-05-2020 'and avg (salary)> 5500;
How can I solve this problem?
Your query makes no sense (to me, at least). What does that average salary represent? Whose average salary?
Here's an example based on Scott's EMP table; I'm going to delete employees who were hired on 3th of December 1981 and work in department whose employees' average salary is higher than 2000.
Sample data:
SQL> select deptno, ename, sal, hiredate from emp order by deptno, ename;
DEPTNO ENAME SAL HIREDATE
---------- ---------- ---------- ----------
20 ADAMS 1100 12.01.1983
20 FORD 3000 03.12.1981 --> this
20 JONES 2975 02.04.1981
20 SCOTT 3000 09.12.1982
20 SMITH 800 17.12.1980
30 ALLEN 1600 20.02.1981
30 BLAKE 2850 01.05.1981
30 JAMES 950 03.12.1981 --> this
30 MARTIN 1250 28.09.1981
30 TURNER 1500 08.09.1981
30 WARD 1250 22.02.1981
11 rows selected.
Averege salaries per department:
SQL> select deptno, avg(sal) avg_salary
2 from emp
3 group by deptno
4 order by avg_salary desc;
DEPTNO AVG_SALARY
---------- ----------
20 2175 --> higher than 2000
30 1566,66667
So: I'm looking for employees who work in department 20 (as only that department has average salaries higher than 2000) and who were hired on 03.12.1981 (James and Ford, but only Ford works in department 20):
SQL> delete from emp
2 where hiredate = date '1981-12-03'
3 and deptno in (select deptno
4 from emp
5 group by deptno
6 having avg(sal) > 2000
7 );
1 row deleted.
Is Ford still in there?
SQL> select * From emp where ename = 'FORD';
no rows selected
SQL>
Nope, deleted.
Now, your turn.

How to use rank to get the latest bonus record

currently I am using the below query to get the previous year’s bonus amount for the employees. But I am facing some issues, so I am trying to get the latest element entry value(screen entry value) for the element ‘xyz bonus’ using the RANK() function. Please help. Thanks.
Select
Pam.assignment_number,
Peev.screen_entry_value as bonus_amount
From
Per_all_assignments_m Pam,
Pay_element_entries_f peef,
Pay_element_types_tl petl,
Pay_element_entry_values_f peev
Where
Pam.Person_id=peef.person_id
and peef.element_type_id = petl. element_type_id
And peef.element_entry_id = peev. element_entry_id
And petl.language=‘US’
And to_char(peef.effective_start_date,’yyyy’)=(to_char(sysdate,’yyyy’)-1)
And to_char(peev.effective_start_date,’yyyy’)=(to_char(sysdate,’yyyy’)-1)
And petl.element_name = ‘xyz bonus’
As I don't have your tables, I'm using Scott's sample EMP table.
In there, rows sorted by salaries per department look like this:
SQL> select deptno,
2 ename,
3 sal,
4 rank() over (partition by deptno order by sal desc) rn
5 from emp
6 order by deptno,
7 sal desc;
DEPTNO ENAME SAL RN
---------- ---------- ---------- ----------
10 KING 10000 1
10 CLARK 2450 2
10 MILLER 1300 3
20 SCOTT 3000 1
20 FORD 3000 1
20 JONES 2975 3
20 ADAMS 1100 4
20 SMITH 920 5
30 BLAKE 2850 1
30 ALLEN 1600 2
30 TURNER 1500 3
30 MARTIN 1250 4
30 WARD 1250 4
30 JAMES 950 6
14 rows selected.
SQL>
If you want to fetch the highest salary per department, you'd then
SQL> select deptno, ename, sal
2 from (select deptno,
3 ename,
4 sal,
5 rank() over (partition by deptno order by sal desc) rn
6 from emp
7 )
8 where rn = 1;
DEPTNO ENAME SAL
---------- ---------- ----------
10 KING 10000
20 SCOTT 3000
20 FORD 3000
30 BLAKE 2850
SQL>
I guess that's what you are looking for.
Your query might then look like this:
Select
Pam.assignment_number,
Peev.screen_entry_value as bonus_amount,
rank() over (partition by pam.assignment_number order by peev.screen_entry_value desc) rn
From
...
Now, use it as an inline view (or a CTE) and fetch desired values.
If that's not what you are looking for, please, post sample data and desired result.

select rows between two values in Oracle 11g

This is a common question I saw in many places, but don't know yet it possible or not. I'm trying to select rows between 2 and 5 in following way using oracle sql developer tool.
As of result this query, this should select 3rd and 4th query according to below query
SELECT * FROM MyTable
WHERE ROWNUM > 2 AND ROWNUM < 5
but it's not selecting the 3rd and 4th rows,
Then I tried the following query
SELECT * FROM MyTable
WHERE RN BETWEEN 2 AND 5
This also syntactically and progrmatically correct, but not selecting the exact columns.
Use a subquery:
SELECT t.*
FROM (SELECT t.*, ROWNUM as rn
FROM MyTable t
) t
WHERE rn > 2 AND rn < 5;
Note that tables represent unordered sets. There is no such thing as a first or second row. You should have an ORDER BY clause to specify the ordering.
The reason that your version doesn't work is that rownum starts at 1 when the first row is put into the result set. If no row is put in, the value never increments. So, it never hits 2 or 3.
I should also note that between in SQL is inclusive. So >= and <= are more appropriate.
EDIT:
I should note that Oracle 12+ supports FETCH/OFFSET:
select t.*
from mytable t
offset 2 -- start on the third row
fetch first 2 rows only -- fetch two rows in total
An order by is still recommended in this case.
A little bit of analytics.
Salaries in the EMP table, sorted by $$$, look like this:
SQL> select ename, sal
2 from emp
3 order by sal;
ENAME SAL
---------- ----------
SMITH 800
JAMES 950 2 you want to return James ...
WARD 1250 3
MARTIN 1250 4
MILLER 1300 5 ... to Miller
TURNER 1500
ALLEN 1600
CLARK 2450
BLAKE 2850
JONES 2975
FORD 3000
KING 5000
12 rows selected.
SQL>
If you do it as follows, you'd get what you wanted:
SQL> select ename, sal, rn
2 from (select ename, sal, row_number() over (order by sal) rn
3 from emp
4 )
5 where rn between 2 and 5;
ENAME SAL RN
---------- ---------- ----------
JAMES 950 2
WARD 1250 3
MARTIN 1250 4
MILLER 1300 5
SQL>
However, as you can see, Ward and Martin earn the same $1250. So, should we count them as having the same salary and include Turner into the list, or not? Yet two another analytic functions might help you decide: RANK and DENSE_RANK:
SQL> select ename, sal,
2 row_number() over (order by sal) rn,
3 rank() over (order by sal) rnk,
4 dense_rank() over (order by sal) drnk
5 from emp
6 order by sal;
ENAME SAL RN RNK DRNK
---------- ---------- ---------- ---------- ----------
SMITH 800 1 1 1
JAMES 950 2 2 2 2nd isn't questionable, but ...
WARD 1250 3 3 3
MARTIN 1250 4 3 3
MILLER 1300 5 5 4 ... which one is 5th? Miller (RN and RNK), ...
TURNER 1500 6 6 5 ... or Turner (DRNK column)?
ALLEN 1600 7 7 6
CLARK 2450 8 8 7
BLAKE 2850 9 9 8
JONES 2975 10 10 9
FORD 3000 11 11 10
KING 5000 12 12 11
12 rows selected.
SQL>
To be fair, DENSE_RANK is probably the best option in such cases:
SQL> select ename, sal, drnk
2 from (select ename, sal, dense_rank() over (order by sal) drnk
3 from emp
4 )
5 where drnk between 2 and 5;
ENAME SAL DRNK
---------- ---------- ----------
JAMES 950 2
WARD 1250 3
MARTIN 1250 3
MILLER 1300 4
TURNER 1500 5
SQL>
Now you have several options; pick the one that suits you best.