Either in not both clause in select sql - sql

Find the names of all departments located either in BOSTON or in DALLAS" and not in both cities.
I having the code like this
SELECT D.DNAME
FROM DEPARTMENT D
INNER JOIN DEPTLOC L ON L.DNAME = D.DNAME
WHERE L.CITY='BOSTON'
OR L.CITY='DALLAS' ;
But this will show the department that located in BOSTON OR DALLAS . But i just want either in, what should i put in order to get the result.
Example:
in my DEPTLOC TABLE
//DEPTLOC
DNAME CITY
----------------
ACCOUNTING BOSTON
ACCOUNTING DALLAS
SALES DALLAS
TRANSPORT BOSTON
TRANSPORT DALLAS
So in my DEPARTMENT
i should get output like
DNAME
----------
SALES

Group them, then calculate the total count for each departments, then filter all departments which has only one location.
SELECT D.DNAME
FROM DEPARTMENT D
INNER JOIN DEPTLOC L ON L.DNAME = D.DNAME
WHERE L.CITY='BOSTON'
OR L.CITY='DALLAS'
GROUP BY
D.DNAME
HAVING COUNT(1) = 1

You could write:
SELECT department.dname
FROM department
JOIN deptloc
ON department.dname = deptloc.dname
WHERE deptloc.city IN ('BOSTON', 'DALLAS')
GROUP
BY department.dname
HAVING COUNT(DISTINCT deptloc.city) = 1
;
For that matter, since each value in deptloc.dname presumably also occurs in department.name, you can dispense with the join and just write:
SELECT dname
FROM deptloc
WHERE city IN ('BOSTON', 'DALLAS')
GROUP
BY dname
HAVING COUNT(DISTINCT city) = 1
;

Try something like this
--take only those that ara in one city
SELECT DNAME_WITH_COUNT.DNAME FROM
--count how many times it occurs
(SELECT DNAME, COUNT(DNAME) CNT FROM
--your select with both cities
(SELECT D.DNAME
FROM DEPARTMENT D
INNER JOIN DEPTLOC L ON L.DNAME = D.DNAME
WHERE L.CITY='BOSTON'
OR L.CITY='DALLAS'
)
)DNAME_WITH_COUNT
WHERE CNT>1;

Try this:
SELECT D.DNAME
FROM DEPARTMENT D
INNER JOIN DEPTLOC L ON L.DNAME = D.DNAME
GROUP BY D.DNAME
HAVING 1 = SUM(CASE WHEN L.CITY IN ('BOSTON', 'DALLAS') THEN 1 ELSE 0 END);

You could join the department table with an aggregate query that returns only one location per department:
SELECT d.dname
FROM department d
INNER JOIN (SELECT dname
FROM deptloc
WHERE city IN ('BOSTON', 'DALLAS')
GROUP BY dname
HAVING COUNT(*) = 1) l ON l.dname = d.dname

Related

Am I right? I don't know the answer I wrote is right or wrong. (SQL)assignment

For each department headed by a female manager, list the department name, and the number of employees who work for that department.
My Answer:
SELECT E.SEX
FROM EMPLOYEE AS E
WHERE E.Ssn IN (SELECT Essn
FROM DEPENDENT AS D
WHERE E.Sex = D.Sex);
enter image description here
I think your answer is probably wrong. My solution is below:
select aa.name,
count(*) as cnt
(select a.dname
,dnumber
from department as a
inner join employee as b
on a.mgr_ssn = b.ssn
where a.sex = female
) as aa
inner join empoyee as bb
on aa.dnumber = bb.dno
group by aa.name
The logic is following:
1, find all departments which are headed by a female manager. the code is follwing
select a.dname
,dnumber
from department as a
inner join employee as b
on a.mgr_ssn = b.ssn
where a.sex = female
2, group by the department name and count the number of employees who work for that department.
You'll want to study up on it inner joins, aliases/correlation names, and groups/aggregates.
select d.dname, count(*)
from dept d inner join emp em on em.ssn = dept.mgr_ssn
inner join emp e on e.dno = d.dnumber
where em.sex = 'F'
group by d.dname

Write a query to display the name of the department that has the maximum staff count order by department name

select max(count(department_id))
from staff
group by department_id
ERROR at line 4:
ORA-00918: column ambiguously defined
Select department_name
from staff s
inner join department d on s.department_id=d.department_id
having count(s.department_id) in (Select max(count(department_id))
from staff) group by department_id
--- Expected output ---
DEPARTMENT_NAME
------------------------------
SE
```none
---Difference in Output---
(select max(count(department_id)) from staff)group by departmentDEPARTMENT_idNAME
*------------------------------
SERROR at line 4:
ORA-00918: column ambiguously defined
Summary of tests
+------------------------------+
| 2 tests run / 0 test passed |
+------------------------------+
Query:
select dept.DEPARTMENT_NAME, count(dept.DEPARTMENT_NAME) as staff_count from
hr.departments dept, hr.employees emp
where dept.DEPARTMENT_ID=emp.DEPARTMENT_ID(+)
group by dept.DEPARTMENT_NAME
order by count(dept.DEPARTMENT_NAME) desc
FETCH FIRST 1 ROW ONLY;
You can run the above query in https://livesql.oracle.com/
And the for more information on Fetch can be found on link
https://oracle-base.com/articles/12c/row-limiting-clause-for-top-n-queries-12cr1
On multiple places, You missed alias and I have added it as following:
SELECT
D.DEPARTMENT_NAME -- ADDED ALIAS HERE
FROM
STAFF S
INNER JOIN DEPARTMENT D ON S.DEPARTMENT_ID = D.DEPARTMENT_ID
GROUP BY
D.DEPARTMENT_ID -- ADDED ALIAS HERE
HAVING
COUNT(S.DEPARTMENT_ID) IN (
SELECT
MAX(COUNT(DEPARTMENT_ID))
FROM
STAFF
);
Also, You can achieve the same result using the following query:
SELECT
D.DEPARTMENT_NAME
FROM
DEPARTMENT D
JOIN (
SELECT
S.DEPARTMENT_ID,
COUNT(1)
FROM
STAFF S
ORDER BY
2 DESC
FETCH FIRST ROWS ONLY
) S ON S.DEPARTMENT_ID = D.DEPARTMENT_ID;
Cheers!!
select department_id, count(*) from staff group by department_id
having count(*) = (select max(count(*))
from staff group by department_id )
check it out
select department_name from (select d.department_name,count(s.staff_id) as c from department d join staff s on d.department_id=s.department_id
group by d.department_name) mx where c=(select max(count(staff_id)) from staff group by department_id) order by department_name;
SELECT department_name
FROM department
WHERE department_id IN
(SELECT department_id
FROM staff
HAVING COUNT(department_id) IN
(SELECT MAX(COUNT(department_id))
FROM staff
GROUP BY department_id)
GROUP BY department_id);

SQL QUERY: The locations of each department and the number of employees working in each location

I'm trying to solve this query, I have to find the locations for each department and the number of employees per location (not for department, common query for this database)
SELECT DE.DLOCATION, count(E.DNO)
FROM DEPARTMENT D
INNER JOIN EMPLOYEE E ON D.DNUMBER = E.DNO
INNER JOIN DEPT_LOCATIONS DE ON DE.DNUMBER = E.DNO
GROUP BY DE.DLOCATION
/
This works but this shows me the number of employees per department (with possible repetitions of the value)
How can i get the number of employees for locations and not for department?
EDIT: The query works, i actually get the number of employees per location but in every city there is more than one department so if in the 'software' department of Houston there are 14 employees, then again in the 'software' department of Sugarland it shows me 14 employees so the query works but not per location, it works per department. Thank you anyway for your help i appreciate it
You are closer to the solution. Since you haven't posted about other columns in these tables like employee ID or number. Going by what you have, try:
SELECT E.DNO, DE.DLOCATION, count(E.DNO)
FROM DEPARTMENT D
INNER JOIN EMPLOYEE E
ON D.DNUMBER = E.DNO
INNER JOIN DEPT_LOCATIONS DE
ON DE.DNUMBER = E.DNO
GROUP BY E.DNO,DE.DLOCATION
Your query should work as written what you need is distinct if i am not wrong.
SELECT DE.DLOCATION, COUNT(distinct E.DNO) as NoOfEmps
FROM DEPARTMENT D INNER JOIN
EMPLOYEE E
ON D.DNUMBER = E.DNO INNER JOIN
DEPT_LOCATIONS DE
ON DE.DNUMBER = E.DNO
GROUP BY DE.DLOCATION;
Perhaps you need :
SELECT DE.DLOCATION, COUNT(*) as NoOfEmps
. . .
SQL> SELECT D.loc, COUNT(E.Deptno) as NoOfEmps
2 FROM DEPT D INNER JOIN EMP E
3 ON D.DEPTNO = E.DEPTNO
4 GROUP BY D.LOC;
LOC NOOFEMPS
------------- ----------
NEW YORK 3
CHICAGO 6
DALLAS 5

SELECT clause with MINUS INTERSECT and UNION

In my database, i created a table name DEPTLOC
//DEPTLOC
DNAME CITY
----------------------------
RESEARCH BOSTON
IT PARIS
SCIENCE LONDON
RESEARCH LONDON
SALES NEWYORK
RESEARCH PARIS
RESEARCH NEWYORK
MARKETING NEWYORK
So i used the following query
SELECT CITY FROM DEPTLOC
INTERSECT
(
SELECT CITY FROM DEPTLOC WHERE DNAME='SALES'
UNION
SELECT CITY FROM DEPTLOC WHERE DNAME='RESEARCH'
);
But my output is all the CITY will be displayed. My question is want find which of the DNAME='SALES' OR DNAME='RESEARCH' has its location in all cities.
So from the table above, all distinct city are
CITY
-------
BOSTON
PARIS
LONDON
NEWYORK
Since 'RESEARCH' have all the location but 'SALES' Only have some, my output should be display like this
DNAME
---------
RESEARCH
What should i change for my query in order to get the correct output
Here's a shorter (than my previous answer) query that checks only between DNAMES SALES and RESEARCH to see which DNAME has all CITIES. Set operators UNION ALL and MINUS are used.
SELECT DNAME
FROM
(
SELECT 'SALES' DNAME, COUNT(*) MISSING_CITIES
FROM
(
SELECT DISTINCT CITY FROM DEPTLOC
MINUS
SELECT CITY FROM DEPTLOC WHERE DNAME = 'SALES'
)
UNION ALL
SELECT 'RESEARCH', COUNT(*) FROM
(
SELECT DISTINCT CITY FROM DEPTLOC
MINUS
SELECT CITY FROM DEPTLOC WHERE DNAME = 'RESEARCH'
)
)
WHERE MISSING_CITIES = 0;
One way of doing this is to count the distinct locations, and join it on the departments query:
SELECT dname
FROM (SELECT dname, COUNT(*) AS dept_city_count
FROM deptloc
GROUP BY dname) d
JOIN (SELECT COUNT (DISTINCT city) AS city_count
FROM deptloc) ON city_count = dept_cirt_count
Here is a query using joins. First all Cities are selected. Then, a CROSS JOIN is made between all Departments and all Cities. Then, a LEFT JOIN is made to select Departments that do not have all Cities. Then, another LEFT JOIN is made to select Departments that do have all Cities.
SELECT DISTINCT
DL.DNAME
FROM
DEPTLOC DL
LEFT JOIN
(
SELECT
ALL_COMBOS.DNAME dname
FROM
(
SELECT DISTINCT
D1.DNAME DNAME,
D2.CITY CITY
FROM
DEPTLOC D1
CROSS JOIN
(
SELECT DISTINCT
CITY
FROM
DEPTLOC
)
D2 --All distinct Cities
)
ALL_COMBOS --All Departments with all Locations
LEFT JOIN DEPTLOC D2
ON
ALL_COMBOS.DNAME = D2.DNAME
AND ALL_COMBOS.CITY = D2.CITY
WHERE
D2.DNAME IS NULL
)
NOT_ALL_LOCATIONS --Departments that do not have all Locations
ON DL.DNAME = NOT_ALL_LOCATIONS.DNAME
WHERE
NOT_ALL_LOCATIONS.DNAME IS NULL; --Departments that have all Locations
As it can be observed, this method does not rely on the count of the Cities, but on the actual values of the Cities themselves.
Assuming that the key in deptloc is (dname, city) then the following would work:
select dname
from deptloc
group by dname
having count(*) = (select count(distinct city) from deptloc);
The query works by creating one group for every department. The count(*) would be the nr of cities that the department is located in. Each such count is compared with the nr of unique Cities cited in the same table.
Edited: Saw your comment now, that this was the solution you did not want :)
Here is another version of "relational division"
select departments.dname
from (select distinct dname from deptloc) departments
where not exists(
select 'x'
from (select distinct city from deptloc) cities
where not exists(
select 'x'
from deptloc x
where x.city = cities.city
and x.dname = departments.dname));

"Double Group By" in Oracle SQL?

As I was learning SQL statements I encountered one example (regarding the demo SCOTT database), I have no idea how to solve.
In which department(s) are all salgrades present?
My most promising approach is to group all salgrades and departments in the joined tables emp, dept and salgrade:
SELECT s.grade AS "Salgrade",
d.dname AS "Department ID"
FROM emp e INNER JOIN dept d ON(e.deptno = d.deptno)
INNER JOIN salgrade s ON(e.sal BETWEEN s.losal AND s.hisal)
GROUP BY d.dname, s.grade
Executing this gives me the following results:
If I could group this another time by department, COUNT(*) could give me the number of different salgrades per department. Then I could compare this number (with HAVING) to the following subselect:
(SELECT COUNT(*)
FROM salgrade)
Is there any possibility to group a table which already contains
GROUP BY?
Is there another (better) approach I could use?
I am using an apex-oracle-server with "Application Express 4.2.4.00.07"
Minor change from your version, by removing the grouping inside, and this version, first generates, salgrade and department of all employees, and then doing a grouping outside, counting distinct salary grades.
SELECT Department_ID
FROM
(
SELECT s.grade AS Salgrade,
d.dname AS Department_ID
FROM emp e
INNER JOIN dept d ON(e.deptno = d.deptno)
INNER JOIN salgrade s ON(e.sal BETWEEN s.losal AND s.hisal)
)
GROUP BY Department_ID
HAVING COUNT(distinct Salgrade) = ( SELECT count(1) FROM salgrade);
I found an even easier solution now:
SELECT d.dname
FROM emp e INNER JOIN dept d ON(e.deptno = d.deptno)
INNER JOIN salgrade s ON(e.sal BETWEEN s.losal AND s.hisal)
GROUP BY d.dname
HAVING COUNT(DISTINCT s.grade) = (SELECT COUNT(*) FROM salgrade);
Simple way would be - if performance is not a problem.
SELECT
COUNT(DISTINCT [Salgrade]) AS [COUNT]
,[Department ID]
FROM (SELECT s.grade AS "Salgrade",
d.dname AS "Department ID"
FROM emp e INNER JOIN dept d ON(e.deptno = d.deptno)
INNER JOIN salgrade s ON(e.sal BETWEEN s.losal AND s.hisal)
GROUP BY d.dname, s.grade) DEPT_SALE
GROUP BY [Department ID]
There could be better solutions though if we know more of your base tables - emp & salegrade