Need to count the filtered employees - sql

I wrote a query which need filter out the employee data on behalf on their employee codes.
For instance, in my XYZ table i have 200 employees, i need to insert these 200 employee in ABC table, but before inserting, i need to check whether all 200 employees are existed in the system,I first filter out the employee and then insert into my ABC table.
suppose, 180 out of 200 employee matched, then i will insert 180 in the ABC table.
Now i want the count 200-180=20, so i need that difference count.
I wrote a query but it fetches only the matched record, not those employee count who filters out.
Select distinct SD.EMP_code
FROm SALARY_DETAIL_REPORT_012018 SD /*219 Employees*/
JOIN
(SELECT * FROM EMPLOYEE) tbl
ON tbl.EMP_CODE=to_char(SD.EMP_CODE)
WHERE SD.REFERENCE_ID like '1-%';
final output : 213 employees
I want 219-213=6
i want those 6 employees. I also tried INTERSECT but i got same result.
Select distinct to_char(SD.EMP_code)
FROm SALARY_DETAIL_REPORT_012018 SD
WHERE SD.REFERENCE_ID like '1-%'
INTERSECT
SELECT EMP_CODE FROm EMPLOYEE;
OUTPUT
213 Employees
Kindly help me to find out the count of filtered employees

You can use NOT EXISTS :
SELECT DISTINCT SD.EMP_code
FROM SALARY_DETAIL_REPORT_012018 sd
WHERE NOT EXISTS (SELECT 1 FROM EMPLOYEE e WHERE e.EMP_CODE = TO_CHAR(SD.EMP_CODE)) AND
SD.REFERENCE_ID LIKE '1-%';

use except opertaor
Select distinct to_char(SD.EMP_code)
FROM SALARY_DETAIL_REPORT_012018 SD
WHERE SD.REFERENCE_ID like '1-%'
except
SELECT EMP_CODE FROm EMPLOYEE;

Related

Postgresql : Removing Duplicates after performing UNION ALL

I have a requirement where i need to remove some rows after Joining two tables using UNION ALL.
Here are the Tables
Accounts1
id
username
department
salary
1
Sam
IT
2000
2
Frodo
Accounts
1000
3
Natan
Service
800
4
Kenworth
Admin
900
Accounts2
id
username
department
salary
5
Sam
IT
1600
6
Frodo
Accounts
800
Expected Result of the UNION should be
id
username
department
salary
5
Sam
IT
1600
6
Frodo
Accounts
800
3
Natan
Service
800
4
Kenworth
Admin
900
As seen the expected result should contain the records of the least salary from the accounts2 table replacing the records from the accounts1. I have tried with Distinct but that doesnot resolve the requirement. Any help is greatly appreciated
You can use union all with filtering:
select a2.*
from accounts2 a2
union all
select a1.*
from accounts1 a1
where not exists (select 1
from accounts2 a2
where a2.username = a1.username and a2.department = a1.department
);
EDIT:
If you want one row per username or username/department from either table with the minimum salary, then I would suggest union all with distinct on:
select distinct on (username, department) a.*
from ((select a1.*
from accounts a1
) union all
(select a2.*
from accounts a2
)
) a
order by username, department, salary;
Remove department accordingly if you want one row per employee.
After UNIONing the two sets, I would calculate a Row_number() ON (Group By department, username Order By salary, id). Then I would wrap that one in one more Select to filter and retain only row_number = 1.
A little more code, but very explicit as to what is being performed and it has the advantage that if either data set happens to contain multiple values for a user you still get the one with the lowest salary.
This is a problem that comes up often where there are multiple records within a group domain and you want to choose "the best" one even if you can't say exactly which one that is. The row_number() window function allows your Order By to make the best choice float to the top where it will assign the row_number of 1. You can then filter and retain only the row_numbers=1 as the "best" choice within each domain. This always means at least two Select statements because window functions are evaluated after Where and Having clauses.

SQL - result in one record

I am new to SQL (first time) and I try to get my result in 1 record:
I have a table with 3 entries: city_name, company_name, and employee number
Basically, in my table I have a company which repeats 2 times: city_name: Rome, company_name: ABC, employee number: 100 --> this entry is 2 times in the table
How can I make this 2 entries to be shown in the table as a single record and to sum my employee numbers. I need that 2x100 empolyee to be in a single shown as 200? So I will have something like this:
city_name company_name employee
Rome ABC 200
You are describing group by:
select city_name, company_name, sum(empoyee_number)
from t
group by city_name, company_name

how to get combine from Two select statements

my table is,
ID First_Name Last_name manager_ID Unique_ID
12 Jon Doe 25 CN=Jon Doe, DC=test,DC=COM
25 Steve Smith 39 CN=steve smith, DC=test,dc=com
I want to write a sql that will give me manager's unique ID,
select manager_id from test where ID = '12'
this will give me users manager_ID
select unique_id from test where ID = '25'
can i combine above sql in one statement that will give me user's manager's unique_id as output?
You are looking for a self-join:
select m.unique_id
from test t join
test m
on t.manager_id = m.id
where t.ID = 12;
Note that I remove the single quotes around 12. Presumably, id is an integer. You should not be comparing an integer to a string.
Instead of joining it to the same table, you can also make a nested subquery statement like this.
SELECT unique_id FROM test WHERE ID =(SELECT manager_id FROM test WHERE ID = 12);
The inner query outputs the manager_id where id of person equals 12 and the outer query gives the unique_id of the related manager.

Sql COALESCE entire rows?

I just learned about COALESCE and I'm wondering if it's possible to COALESCE an entire row of data between two tables? If not, what's the best approach to the following ramblings?
For instance, I have these two tables and assuming that all columns match:
tbl_Employees
Id Name Email Etc
-----------------------------------
1 Sue ... ...
2 Rick ... ...
tbl_Customers
Id Name Email Etc
-----------------------------------
1 Bob ... ...
2 Dan ... ...
3 Mary ... ...
And a table with id's:
tbl_PeopleInCompany
Id CompanyId
-----------------
1 1
2 1
3 1
And I want to query the data in a way that gets rows from the first table with matching id's, but gets from second table if no id is found.
So the resulting query would look like:
Id Name Email Etc
-----------------------------------
1 Sue ... ...
2 Rick ... ...
3 Mary ... ...
Where Sue and Rick was taken from the first table, and Mary from the second.
SELECT Id, Name, Email, Etc FROM tbl_Employees
WHERE Id IN (SELECT ID From tbl_PeopleInID)
UNION ALL
SELECT Id, Name, Email, Etc FROM tbl_Customers
WHERE Id IN (SELECT ID From tbl_PeopleInID) AND
Id NOT IN (SELECT Id FROM tbl_Employees)
Depending on the number of rows, there are several different ways to write these queries (with JOIN and EXISTS), but try this first.
This query first selects all the people from tbl_Employees that have an Id value in your target list (the table tbl_PeopleInID). It then adds to the "bottom" of this bunch of rows the results of the second query. The second query gets all tbl_Customer rows with Ids in your target list but excluding any with Ids that appear in tbl_Employees.
The total list contains the people you want — all Ids from tbl_PeopleInID with preference given to Employees but missing records pulled from Customers.
You can also do this:
1) Outer Join the two tables on tbl_Employees.Id = tbl_Customers.Id. This will give you all the rows from tbl_Employees and leave the tbl_Customers columns null if there is no matching row.
2) Use CASE WHEN to select either the tbl_Employees column or tbl_Customers column, based on whether tbl_Customers.Id IS NULL, like this:
CASE WHEN tbl_Customers.Id IS NULL THEN tbl_Employees.Name ELSE tbl_Customers.Name END AS Name
(My syntax might not be perfect there, but the technique is sound).
This should be pretty performant. It uses a CTE to basically build a small table of Customers that have no matching Employee records, and then it simply UNIONs that result with the Employee records
;WITH FilteredCustomers (Id, Name, Email, Etc)
AS
(
SELECT Id, Name, Email, Etc
FROM tbl_Customers C
INNER JOIN tbl_PeopleInCompany PIC
ON C.Id = PIC.Id
LEFT JOIN tbl_Employees E
ON C.Id = E.Id
WHERE E.Id IS NULL
)
SELECT Id, Name, Email, Etc
FROM tbl_Employees E
INNER JOIN tbl_PeopleInCompany PIC
ON C.Id = PIC.Id
UNION
SELECT Id, Name, Email, Etc
FROM FilteredCustomers
Using the IN Operator can be rather taxing on large queries as it might have to evaluate the subquery for each record being processed.
I don't think the COALESCE function can be used for what you're thinking. COALESCE is similar to ISNULL, except it allows you to pass in multiple columns, and will return the first non-null value:
SELECT Name, Class, Color, ProductNumber,
COALESCE(Class, Color, ProductNumber) AS FirstNotNull
FROM Production.Product
This article should explain it's application:
http://msdn.microsoft.com/en-us/library/ms190349.aspx
It sounds like Larry Lustig's answer is more along the lines of what you need though.

How do I write a standard SQL GROUP BY that includes columns not in the GROUP BY clause

Let's say I have a table called Customer, defined like this:
Id Name DepartmentId Hired
1 X 101 2001/01/01
2 Y 102 2002/01/01
3 Z 102 2003/01/01
And I want to retrieve the date of the last hiring in each department.
Obviously I would do this
SELECT c.DepartmentId, MAX(c.Hired)
FROM Customer c
GROUP BY c.DepartmentId
Which returns:
101 2001/01/01
102 2003/01/01
But what do I do if I want to return the name of the guy hired? I.e. I would want this result set:
101 2001/01/01 X
102 2003/01/01 Z
Note that the following does not work, as it would return three rows rather than the two I'm looking for:
SELECT c.DepartmentId, c.Name, MAX(c.Hired)
FROM Customer c
GROUP BY c.DepartmentId
I can't remember seeing a query that achieves this.
NOTE: It's not acceptable to join on the Hired field, as that would not be guaranteed to be accurate.
A subselect would do the job and would handle the case where more than one person was hired in the same department on the same day:
SELECT c.DepartmentId, c.Name, c.Hired from Customer c,
(SELECT DepartmentId, MAX(Hired) as MaxHired
FROM Customer
GROUP BY DepartmentId) as sub
WHERE c.DepartmentId = sub.DepartmentId AND c.Hired = sub.MaxHired
Standard Sql:
select *
from Customer C
where exists
(
-- Linq to Sql put NULL instead ;-)
-- In fact, you can even put 1/0 here and would not cause division by zero error
-- An RDBMS do not parse the select clause of correlated subquery
SELECT NULL
FROM Customer
where c.DepartmentId = DepartmentId
GROUP BY DepartmentId
having c.Hired = MAX(Hired)
)
If Sql Server happens to support tuple testing, this is the most succint:
select *
from Customer
where (DepartmentId, Hired) in
(select DepartmentId, MAX(Hired)
from Customer
group by DepartmentId)
SELECT a.*
FROM Customer AS a
JOIN
(SELECT DepartmentId, MAX(Hired) AS Hired
FROM Customer GROUP BY DepartmentId) AS b
USING (DepartmentId,Hired);