How to find out employees having same department but different shifts - sql

I have a table employee which has different attributes like emp_code, naeme,...., deptt.
There is another table called nightShift which has fields- emp_code, shift_time.
Any employee which is not in nightShift table is automatically assumed to be in day shift.
Now I have to find out those deptt which has some employees working in night shift and some in normal shift
What can be a query for this.
Example
**Employees**
----------------------------------------
emp_code| Name | deptt
----------------------------------------
e1 John Ops
e2 Martin Ops
e3 Gary Infra
e4 John Facilities
e5 Michael Ops
e6 Alan Ops
e7 Tony Facilites
e8 Alex Infra
e9 Peter Infra
e10 Ron Ops
**nightShift**
----------------------------------------
emp_code | shift_time
----------------------------------------
e1 shiftA
e2 shiftA
e5 shiftB
e4 shiftB
e7 shiftC
Now in the output, I want only Deptt Ops, as some of its employees are in night shift(e1,e2,e5) and some in normal shift(e6,e10)
The output should NOT contain Infra as all employees(e3,e8,e9) are in normal shift and none in night shift.
The output should NOT contain Facilities as all employees(e4,e7) are in night shift and none in normal shift.
Can somebody help me with this?

Here is a group by version - join both tables in a left join and count nightShifts per department. If count is greater than zero but not equal to count of all workers in department, we have a match.
select employees.deptt
from employees
left join nightShift
on employees.emp_code = nightShift.emp_code
group by employees.deptt
having count (nightShift.emp_code) > 0
and count (employees.emp_code) <> count (nightShift.emp_code)
Test it on Sql Fiddle.

You could try something along these lines
select
distinct e.deptt
from
Employees e
inner join
NightShift n
on
n.emp_code = e.emp_code
Where
e.deptt not in ('Facilities', 'Facilites')
The inner join will eliminate everyone not working night shifts, then in the where we find any results not working in deptt Facilities

I think you need to count the number of night shift workers for each department, and the number of day shift workers for each department, and you're concerned with those departments where both counts are bigger than zero.
Stage 1: Night shift workers per department:
SELECT e.deptt, COUNT(*) AS headcount
FROM Employees AS e
JOIN NightShift AS n
ON n.emp_code = e.emp_code
GROUP BY e.deptt
Stage 2: Day shift workers per department
There are various possible strategies for this. One is to count the total workers for each department and subtract the number of nightshift workers:
SELECT d.deptt, (d.headcount - n.headcount) AS headcount
FROM (SELECT e2.deptt, COUNT(*) AS headcount
FROM Employees AS e2
GROUP BY e2.deptt
) AS d
JOIN (SELECT e.deptt, COUNT(*) AS headcount
FROM Employees AS e
JOIN NightShift AS n
ON n.emp_code = e.emp_code
GROUP BY e.deptt
) AS n
ON d.deptt = e.deptt
Stage 3: Pick those departments where the headcounts on the dayshift and night shift are both non-zero:
SELECT d.deptt, (d.headcount - n.headcount) AS dayshift, n.headcount AS nightshift
FROM (SELECT e2.deptt, COUNT(*) AS headcount
FROM Employees AS e2
GROUP BY e2.deptt
) AS d
JOIN (SELECT e.deptt, COUNT(*) AS headcount
FROM Employees AS e
JOIN NightShift AS n
ON n.emp_code = e.emp_code
GROUP BY e.deptt
) AS n
ON d.deptt = e.deptt
WHERE d.headcount > 0
AND n.headcount > 0
There might be a more succinct formulation, but I'm fairly sure this would give the correct answer.
Subject to the note that this has not been anywhere near an actual SQL DBMS so there could be some syntax errors in it.
I'm also assuming you're using a supported version of Informix (and not Informix OnLine or Informix SE). Some older versions of Informix would not support all this syntax but I believe all the 11.x versions (which are all currently supported) should all handle these queries.
You can probably simplify this along the lines of Nikola Markovinović's answer.

Related

Sum functions doesn't show total values in single row after grouping

I have to showcase the total hours worked for each employee that worked on different dates.
I can use group by and sum function but I have multiple columns to showcase and it gives the same result sum with multiple rows. Additionally, I don't want to write every column name in group by clause as its not proper way of query writing.
I managed to get employees working hours from different tables using joins but couldn't sum up them in single row as a record. However it shows sum in multiple rows.
The script I used to get all the data is given below:
Select e.employeecode, Isnull(e.PreferredName,e.FirstNames) + '
' + e.LastName as [Name], w.Position
, sum(h.TotalHours) over (partition by e.employeecode order by e.employeecode)[TotalHours]
, e.Salary, e.startdate
From employee e
Left join Appointment ap on ap.EmployeeCode = e.EmployeeCode
left join Work w on w.WorkCode = ap.workCode
left join HistoricalAllowance h on h.EmployeeCode = e.EmployeeCode
left join TransPerPaySequence TP on tp.PaySequence = h.PaySequence
Where tp.PeriodEnd between '2021-04-24' and '2021-05-07'
and h.AllowanceCode in ('99','1000') and
and ap.isactive ='1'
group by e.EmployeeCode
It looks right now after writing a script:
employeecode
Name
Position
TotalHours
Salary
StartDate
1234
Anna
employee-Com
63.45
500
40792
1234
Anna
employee-Com
486.45
500
40792
2345
Jacky
Manager
126.9
700
41395
2345
Jacky
Manager
961.05
700
41395
2345
Jacky
Manager
67.05
700
41395
3456
Mahato
HR
402.3
570
41933
3456
Mahato
HR
67.05
570
41933
3456
Mahato
HR
126.9
570
41933
3456
Mahato
HR
126.9
570
41933
The way I wanted
employeecode
Name
Position
TotalHours
Salary
StartDate
1234
Anna
employee-Com
549.9
500
40792
2345
Jacky
Manager
1155
700
41395
3456
Mahato
HR
723.15
570
41933
Please help and let me know what I am missing.
Thanks In advance
I can appreciate not wanting to list all the columns for the GROUP BY . . . but for a slightly different reason: If you can avoid the aggregation then the query is likely to be faster.
And SQL Server offers a convenient solution, using OUTER APPLY:
select e.employeecode,
coalesce(e.PreferredName, e.FirstNames) + ' ' + e.LastName as Name,
w.Position,
h.TotalHoursTotalHours, e.Salary, e.startdate
From employee e Left join
Appointment ap
on ap.EmployeeCode = e.EmployeeCode left join
Work w
on w.WorkCode = ap.workCode outer apply
(select sum(h.TotalHours) as TotalHours
from HistoricalAllowance h join
TransPerPaySequence TP
on tp.PaySequence = h.PaySequence
where h.EmployeeCode = e.EmployeeCode and
tp.PeriodEnd between '2021-04-24' and '2021-05-07' and
h.AllowanceCode in ('99','1000')
) h
where ap.isactive = '1';
Remove the OVER(...) clause and then put every other (non SUMmed) column mentioned in the SELECT, into the GROUP BY also
Adhering to your it's not proper way of query writing rule is tripping you up on this one
ps, I've a doubt that the posted query in your question even runs - SQL server is not, to my knowledge, one of the few databases that will allow you to limit group by columns to just those on which all other selected, non aggregated columns are functionally dependent. Your query as posted should give a "column x in the select list is invalid because it is not an aggregate/in the group by" error

My SQL Join is only producting half the right aggregate output

SELECT E.DNO as DeptNum, COUNT(E.SSN) as EmployeeCount, COUNT(D.ESSN) as DependentCount
FROM Dependent D
RIGHT OUTER JOIN Employee E ON D.ESSN = E.SSN
GROUP BY E.DNO
The goal is to find the total number of employees and total number of dependents for every department. I am utilizing an Employee Table that features Employee, SSN, Department Number and a Dependent Table that has Dependent SSN, Birthdate, and Gender.
The output should be as follows
Dept Num Employee Count DependentCount
1 1 0
2 3 7
3 5 2
But, instead I am getting
Dept Num Employee Count DependentCount
1 1 0
2 9 7
3 4 2
One thing of note is the dependent's SSN is equivalent to the parent's SSN - that is the only way to define the relationship between the tables. Also, I know I need an outer join because we want to list ALL departments, despite the fact there are 0 mentions of it for Dept 1 in Dependent Table.
Can anyone tell me why this isn't working?
Try using distinct so things don't get double counted:
SELECT E.DNO as DeptNum, COUNT(DISTINCT E.SSN) as EmployeeCount,
COUNT(DISTINCT D.ESSN) as DependentCount
FROM Employee E LEFT JOIN
Dependent D
ON D.ESSN = E.SSN
GROUP BY E.DNO

R) Using join in R

Given database is down below,
> dbReadTable(jamesdb, "EMPLOYEE")
EMP_NO NI_NO NAME AGE DEPT_NO
1 E1 123 SMITH 21 D1
2 E2 159 SMITH 31 D1
3 E3 5432 BROWN 65 D2
4 E5 7654 GREEN 52 D3
> dbReadTable(jamesdb, "DEPARTMENT")
DEPT_NO NAME MANAGER
1 D1 Accounts E1
2 D2 Stores E3
3 D3 Sales E5
> dbReadTable(jamesdb, "PRODUCT")
PROD_NO NAME COLOR
1 p1 PANTS BLUE
2 p2 PANTS KHAKI
3 p3 SOCKS GREEN
4 p4 SOCKS WHITE
5 p5 SHIRTS WHITE
> dbReadTable(jamesdb, "STOCK_TOTAL")
PROD_NO QUANTITY
1 p1 2000
2 p2 1000
3 p3 1500
4 p4 200
5 p5 800
And down below is what I got so far but I think I have a misunderstanding of using join.
How should I fix them?
Retrieve the employment number of the sales department manager.
dbGetQuery(jamesdb, 'SELECT EMPLOYEE.EMP_NO FROM DEPARTMENT JOIN EMPLOYEE
WHERE DEPARTMENT.NAME = "Sales"')
Who works in Department D2?
dbGetQuery(jamesdb, 'SELECT MANAGER FROM DEPARTMENT WHERE DEPT_NO = "D2"')
How many white-colored products are in stock?
dbGetQuery(jamesdb, 'SELECT SUM(QUANTITY) FROM PRODUCT JOIN STOCK_TOTAL
WHERE PRODUCT.COLOR = "WHITE"')
Joins are typically done matching one (or more) fields from one table with a corresponding field(s) of another table. For instance, I'm inferring that DEPARTMENT.MANAGER is actually a foreign key to EMPLOYEE.EMP_NO, so when you join, you should be very specific about that relationship:
SELECT e.EMP_NO
FROM DEPARTMENT d
LEFT JOIN EMPLOYEE e on d.MANAGER = e.EMP_NUM
WHERE d.NAME = "Sales"
Notes:
Many databases allow you to be sloppy, where they will infer field associations (foreign keys) based on common field names. First, I don't like allowing that inference; second, it doesn't work here.
I personally prefer to be explicit about the type of join, whether left join, inner join, etc. It's a style, you may choose just join if you prefer.
I'm introducing table aliases here (d and e), a way to shorten long table names. However, they are stylistic, not required.
I personally dislike databases that lack a dictionary of foreign keys and have unintuitive names to associate them. For instance, I'm inferring from the contents of the tables that DEPARTMENT.MANAGER is linked to EMPLOYEE.EMP_NUM. If I'm wrong on this inference, then answers below are likely skewed.
For your first question, though, I don't know why you need a join: since MANAGER is already the employee number, this should be simply
select d.MANAGER
from DEPARTMENT d
where d.NAME='Sales'
Similarly, your second question needs no join.
select e.*
from EMPLOYEE e
where e.DEPT_NO='D2'
The last one needs a join, and can be done in a number of ways. One such is:
select sum(case when st.Quantity > 0 then 1 else 0 end) as Count
from STOCK_TOTAL st
left join PRODUCT pr on st.PROD_NO=pr.PROD_NO
where pr.COLOR='WHITE'

how to count different values from different tuples into the same sceme in sql

I have a table of hospitals details, department details linked to it, types of workers (the staff) in different tables, and their salary information.
I want to extract the following for each hospital: the average and the sum of the salaries, the number of nurses, the number of research doctors and the number of beds in all the departments of a specific hospital.
I built this view of all the workers salary information:
CREATE VIEW workers AS
SELECT hospcod, docsal as sal, 'treatdoc' as typework
FROM doc NATURAL JOIN treatdoc NATURAL JOIN dept
UNION
SELECT hospcod, nursal, 'nurse'
FROM nurse NATURAL JOIN dept
UNION
SELECT hospcod, docsal, 'rsrchdoc'
FROM doc NATURAL JOIN rsrchdoc NATURAL JOIN lab;
the departments and the labs have the hospital code column to correlate a worker information to a specific hospital.
so I have one sceme for all the staff with their rules workers(hospital_code, salary, type_of_worker)
here is the query I'm trying to build:
SELECT hospname, sum(workers.sal), avg(workers.sal), count(dept.numbed),
(SELECT count(typework) from workers where typework = 'nurse') nurse_num,
(SELECT count(typework) from workers where typework = 'rsrchdoc') rsrchdoc_num
FROM hosp NATURAL JOIN dept NATURAL JOIN workers
GROUP BY hospname;
I want to count for each hospital, the number of nurses and the number of research doctors
but it should be correlated somehow to the different hospitals (in the above it gives me the same number of nurses / rsrchdocs for each hospital) , there should be columns that is grouped by hospnames and should get all the tuples like the salary info (avg, sum), as I got properly, but the workers information should be grouped HAVING typework = 'nurse' for the nurse_num, and for the column rsrchdoc_numit should be HAVING typework = 'rsrchdoc_num'
does someone have an idea how can I combine thouse columns in one query?
thank you!
There is an error in your query, I will try to explain.
When you do:
(SELECT count(typework) from workers where typework = 'nurse') nurse_num,
You are getting a constant, that is not affected by the "group by" you are doing after.
What you have to do is a JOIN (like you did in the view) and link the nurse and the rsrchdoc to an specific hospital.
I will give an example is pseudo code
SELECT hosp_name, sum(nurse.salary) , avg(nurse.salary)
FROM hosp
JOIN nurse ON nurse.hosp_name = hosp.hosp_name
GROUP BY hosp.hosp_name
This query will give you 1 row for each nurse in each hospital (assuming that a nurse may work in more than one hospital).
Then you have to do the same thing also for doctors, in a different operation.
SELECT hosp_name, sum(doctors.salary) , avg(doctors.salary)
FROM hosp
JOIN doctors ON doctors.hosp_name = hosp.hosp_name
GROUP BY hosp.hosp_name
And finally you will have to join both ( you may perform the sum first to make it more readable.
SELECT hosp_name, sum_sal_doc, avg_sal_doc, sum_nur_doc, avg_nur_doc
FROM hosp
LEFT JOIN ( SELECT doctors.hosp_name, sum(doctors.salary) as sum_sal_doc, avg(doctors.salary) as avg_sal_doc
FROM doctors
GROUP BY doctors.hosp_name
) t1 ON t1.hosp_name = hosp.hosp_name
LEFT JOIN ( SELECT nurses.hosp_name, sum(nurses.salary) as sum_nur_doc, avg(nurses.salary) as avg_nur_doc
FROM nurses
GROUP BY nurses.hosp_name
) t2 ON t2.hosp_name = hosp.hosp_name
There must be 1 to many relationship between hosp --> dept and hosp --> workers so if you join these 3 tables then you will definitely find the duplicates for dept and workers so you must have to create sub-query for one of the dept or workers to fetch single grouped record group by hospital as follows:
SELECT h.hospname,
sum(w.sal) total_all_worker_sal,
avg(w.sal) avg_all_workers_sal,
d.numbed,
count(case when w.typework = 'nurse' then 1 end) nurse_num,
count(case when w.typework = 'rsrchdoc' then 1 end) rsrchdoc_num
FROM hosp h
JOIN (select hospital_code , sum(numbed) numbed
-- used SUM as numbed must be number of bed in department
-- COUNT will give you only number of department if you use count(d.numbed)
from dept
group by hospital_code) d ON h.hospital_code = d.hospital_code
JOIN workers w ON h.hospital_code = d.hospital_code
GROUP BY h.hospital_code , h.hospname, d.numbed;
-- used h.hospital_code to separate the records if two hospitals have same name

SQL inquiry, tried absolutely everything I know, sql, four tables

I cant get this inquiry, tried like every thing
TABLE: ARTIST
JMBG NAME AGE ADRESA
--------------------------------------
J1 Ladygaga 35 HOLIVUDHILZ
J2 DUSKO 13 BB
J3 EMINEM 40 REVOLUCIJA 5
J4 BAGI 22 KURAC
J5 MARKO 33 ULICA
TABLE:HALL
DID CAPACITY CITY
---------------------------------
D1 500 PODGORICA
D2 300 NIS
D3 1000 BAR
D4 2000 NEWYORK
D5 750 BEOGRAD
TABLE: CITY
-----------------------------------------
BAR montenegro 5000
BEOGRAD Serbia 2000000
BUDVA montenegro 50000
NEWYORK AMERICA 7000000
NIS Serbia 1000000
PODGORICA montenegro 250000
TABLE: CONCERT
ID JMBG HALL
------------------------
K1 J3 D4
K2 J4 D1
K3 J1 D1
K4 J1 D5
K5 J1 D1
K6 J3 D1
K7 J5 D1
The inquiry is: Find the countries where the artist with the most held concerts
has performed in. I really did spend a lot of time on this and energy. I would greatly appreciate if someone could do this that has experience, and doesnt find it too difficult.
I tried this:
SELECT DISTINCT COUNTRY FROM CITY G, HALL D, CONCERT K
WHERE K.DID = D.DID AND D.NAZIV = G.NAZIV AND EXISTS(
SELECT JMBG FROM CONCERT K1,HALL D1, CITY G1
WHERE K.KID=K1.KID
GROUP BY JMBG
HAVING COUNT (*) >= ALL(SELECT COUNT(*) FROM CONCERT
GROUP BY JMBG))
Break it down. The artist with the most held concerts... Which artist had the most held concerts? (We're going to assume that we're interested in the total number of concerts held overall (in all countries), not the number of concerts held in a particular country.
How many concerts did each artist hold?
SELECT c.jmbg
, COUNT(1) AS cnt
FROM concert c
GROUP BY c.jmbg
Which artist held the most concerts? MySQL and MS SQL Server both have some convenient short cuts we can use here. A question we should ask here, what if there are two or more artists held the same number of concerts? Do we want to return both (or all) of those artists, or just return one of them? Which one? (We'd prefer the query to be deterministic... to return the same result given the same rows in the tables.)
Assuming that we want to return just one artist that held the most concerts...
For MySQL:
SELECT c.jmbg
FROM concert c
GROUP BY c.jmbg
ORDER BY COUNT(1) DESC, c.jmbg DESC
LIMIT 1
For SQL Server:
SELECT TOP 1 c.jmbg
FROM concert c
GROUP BY c.jmbg
ORDER BY COUNT(1) DESC, c.jmbg DESC
So that gets us the artist.
The other part of the "inquiry"... which countries did the artist hold concerts in.
Given a particular artist, we could write a query that performs join operations on the concert, hall and city tables. We'll just take a guess at the name of that first column in the city table (since it isn't provided in the question).
SELECT i.country
FROM city i
JOIN hall h
ON h.city = i.cid
JOIN concert o
ON o.hall = h.did
WHERE o.jmbg = 'Ladygaga'
GROUP BY i.country
To combine the two queries, we could use the first as a subquery. My preference is to use an inline view.
SELECT g.country
FROM city g
JOIN hall h
ON h.city = g.cid
JOIN concert o
ON o.hall = h.did
JOIN (
SELECT c.jmbg
FROM concert c
GROUP BY c.jmbg
ORDER BY COUNT(1) DESC, c.jmbg DESC
LIMIT 1
) m
ON m.jmbg = o.jmbg
GROUP BY g.country
Obviously, there are obviously other query patterns that will return an equivalent result.
As I noted in a comment on the question, the specification for this "inquiry" is a bit ambiguous, as to what is meant by "where the artist with the most held concerts has performed in".
There is another interpretation of that specification. If we're interested in getting and analyzing a count of "how many concerts were held in each country by each artist", that's a different query.
FOLLOWUP
"... not allowed to use TOP DESC"
Then just write the query differently. Here's a different way to get the "largest number of concerts held by any artist", and use that to get all the artists that all held that number of concerts.
SELECT n.jmbg
FROM ( -- largest number of concerts by artist
SELECT MAX(p.cnt) AS maxcnt
FROM (
SELECT COUNT(1) AS cnt
FROM concert d
GROUP BY d.jmbg
) p
) o
JOIN ( -- count of concerts by artist
SELECT c.jmbg
, COUNT(1) AS cnt
FROM concert c
GROUP BY c.jmbg
) n
ON n.cnt = o.maxcnt
Since that has the potential to return more than one row (more than one artist), your outer query may want to return a list of countries for each of the returned artists. That is to say, rather than just GROUP BY g.country, you'll likely want to return the artist in the SELECT list, and
GROUP BY m.jmbg, g.country
ORDER BY m.jmbg, g.country
This is a basic question that looks like coming out of school type of question. This answer will give you some hints but you need to work it out for yourself.
JOIN is your friend, find source below:
JOIN - MySQL
JOIN - SQL Server
What you need to do:
join CONCERT table with HALL table by HALL ID
join HALL table to CITY table by CITY name
sum the count of country appearance or hall capacity (either one you need) grouped by artist
order descending by the sum of count if you need it
Good luck