Use asterisk in count with table alias T-SQL - sql

How do we use an aggregate function, like COUNT, with * in conjunction with an alias? COUNT allows table alias to be used with column names but not *.
This works:
select e.*, COUNT(e.MGR)
from EMP as e
left outer join EMP as e1 on e.EMPNO = e1.EMPNO
group by e.[EMPNO], e.[ENAME], e.[JOB], e.[MGR], e.[HIREDATE], e.[SAL], e.[COMM], e.[DEPTNO]
but this does not:
select e.*, COUNT(e.*)
from EMP as e
left outer join EMP as e1 on e.EMPNO = e1.EMPNO
group by e.[EMPNO], e.[ENAME], e.[JOB], e.[MGR], e.[HIREDATE], e.[SAL], e.[COMM], e.[DEPTNO]
This example being used above is a made up one to demonstrate the case. There is no NOT-NULL column in either table. So how do we count the number of rows in left hand side table of a left outer join

This answers the original version of the question.
Use either the primary key or one of the columns used in the JOIN:
select e.*, COUNT(e1.EMPNO)

There is no NOT-NULL column in either table. So how do we count the
number of rows in left hand side table of a left outer join
This should not happen, because every table should have a primary key, guaranteeing at least one NOT NULL column.
Without such a column you can create one at runtime by joining onto a derived table that projects a NOT NULL constant and counting that column.
select e.*, COUNT(e.Flag)
from (SELECT, *, 1 AS Flag FROM EMP) as e
left outer join EMP as e1 on e.EMPNO = e1.EMPNO
group by ...

Related

SQL Joins and Corelated subqueries with column data

I am facing an issue in terms of understanding the joins. Lets say for an example we have two tables employee and sales and now I have a query where we have sales of an employee using the id of the employee
select e.employeename
,s.city
,SUM(s.sales)
from employee e
left join (select sales,eid from sales) s on s.eid = e.id
group by 1,2
I'd like to understand why s.city wasn't showing up? and also would like to understand what is this concept called? Is it co related sub queries on Joins? Please help me down over here.
select
e.employeename
,s.city
,SUM(s.sales)
from employee e
left join (select sales,eid,city from sales) s on s.eid = e.id
group by 1,2
in the left join above you have to add city as well. The query Imagine select sales,eid,city from sales is a table itself and then from this table you are selecting city (your second column s.city) this will run error as your table doesn't have a city column yet.
It is much easier to use CTE (common table expressions than CTE's) You can also do the above question as
select
e.employeename
,s.city
,SUM(s.sales)
from employee e
left join sales as s
on e.id = s.id
group by 1,2
here I have added e.id = s.id instead of s.id = e.id it is better to reference the key of the main table first.
you could use CTE (although used when you have to do a lot of referencing but you can see how it works):
With staging as (
select
e.employeename
,s.city
,s.sales
from employee e
left join sales as s
on e.id = s.id
),
sales_stats as (
select
staging.employeename,
staging.city,
sum(staging.sales)
from staging
group by 1,2
#here you will select from staging again consider staging as a separate table so you will have to have all the columns in the staging that you want to use further. Also you will have to reference columns using staging.x
)
select * from sales_stats
-- here you could have combined the steps but I wanted to show you how cte works, Hope this works for you

Join a table in SQL based off two columns?

I have two tables:
Employees (columns: ID, Name)
and
employee partners (EmployeeID1, EmployeeID2, Time)
I want to output EmployeName1, EmployeeName2, Time instead of imployee ids.
(In other words, replace the ids with names, but in two columns at a time)
How would I do this? Would JOIN be the appropriate command?
you need to join the employee table 2 times as the employee partners table acts as many to many connection.
The select should be:
SELECT emp1.name, emp2.name, em.time
FROM Employees emp1
JOIN employee_partners em ON emp1.id = EmployeeID1
JOIN Employees emp2 on emp2.id = EmployeeID2
Often in these situations, you want to use LEFT JOIN:
SELECT e1.name as name1, e2.name as name2, em.time
FROM employee_partners ep LEFT JOIN
Employees e1
ON e1.id = ep.EmployeeID1 LEFT JOIN
Employees e2
ON e2.id = ep.EmployeeID2;
Notes:
The LEFT JOINs ensure that you do not lose rows if either of the employee columns is NULL.
Use tables aliases; they make the query easier to write and to read.
Qualify all columns names; that is, include the table name so you know where the column is coming from.
I also added column aliases so you can distinguish between the names.

How to select records with no matches in the foreign table (Left outer join)

I have one table that holds my ressources:
Ressource | Ressource-ID
And a table that holds the associations
Ressource-ID | Employee-ID
How to select the ressources of an Employee that are available, i.e. not in the association table?
I've tried this, but it's not working:
select r.ress, r.ress_id
FROM Ressource r
LEFT outer JOIN Ressource_Employee_Association a ON r.ress_id = a.ress_id
WHERE a.emp_id = 'ID00163efea66b' and a.ress_id IS NULL
Any ideas?
Thanks
Thomas
After writing my above comments, and looking at the proposed solutions: I think I've got some more understanding of what you are trying to do.
Assuming you have unlimited quantity of resources in your resources table, you want to select the un-assigned resources per employee (based on their non-existence for any specific employee in the resource association table).
In order to accomplish this (and get a comprehensive list of employees) you'll need a 3rd table, in order to reference the complete list of employees. You'll also need to CROSS JOIN all of the resources onto the list of employees (assuming every employee has access to every resource), then you LEFT JOIN (LEFT OUTER JOIN whatever) your association list onto the query where the resource_id and employee_id match the resource_id in the resources table, and the employee_id in the employees table (respectively). THEN you add your where clause that filters out all the records that assign an employee to a resource. This leaves you with the resources that are available to the employee, which they also do not have signed out. This is convoluted to say, so hopefully the query sheds more light:
SELECT e.employee_id, e.employee, r.res_id, r.res
FROM employees e
CROSS JOIN resources r
LEFT JOIN assigned_resources ar
ON ar.employee_id = e.employee_id AND r.res_id = ar.res_id
WHERE ar.res_id IS NULL
If you don't have an employees table, you can accomplish the same by using the assigned resources table, but you will be limited to selecting employees who already have some resources allocated. You'll need to add a GROUP BY query because of the possible existence of multiple employee definitions in the association table. Here's what that query would look like:
SELECT e.employee_id, r.res_id, r.res
FROM assigned_resources e
CROSS JOIN resources r
LEFT JOIN assigned_resources ar
ON ar.employee_id = e.employee_id AND r.res_id = ar.res_id
WHERE ar.res_id IS NULL
GROUP BY e.employee_id, r.res_id
Does this work?
select r.ress, r.ress_id
from resource r
where not exists
(
select 1 from ressource_emplyee_association a
where a.emp_id = '...' and a.ress_id = r.ress_id
)
EDIT
Before that I had the following, but changed it according to the comments below:
select r.ress, r.ress_id
from resource r
where not exists
(
select top 1 1 from ressource_emplyee_association a
where a.emp_id = '...' and a.ress_id = r.ress_id
)
The WHERE clause is applied after the LEFT JOIN. This means that you are currently trying to get results where there is NO matching record in Ressource_Employee_Association, but where the emp_id equals 'ID00163efea66b'.
But if there is no matching record, how can emp_id be anything other than NULL?
One option is to move part of the WHERE clause into the join...
SELECT
r.ress, r.ress_id
FROM
Ressource r
LEFT OUTER JOIN
Ressource_Employee_Association a
ON r.ress_id = a.ress_id
AND a.emp_id = 'ID00163efea66b'
WHERE
a.ress_id IS NULL
This will list all resources that are not associated to employee 'ID00163efea66b'.
EDIT
Your comment implies that what you want is...
- A view listing all employees
- For each employee list each resource that they DON'T have
This requires an extra table listing all of your employees.
SELECT
*
FROM
Employee
CROSS JOIN
Ressource
WHERE
NOT EXISTS (SELECT * FROM Ressource_Employee_Association
WHERE emp_id = Employee.id
AND ress_id = Ressource.id)
SELECT *
FROM Ressource
WHERE ress_id IN (
SELECT ress_id,
FROM Ressource
MINUS
SELECT ress_id
FROM Ressource_Employee_Association
WHERE emp_id = 'ID00163efea66b'
);

How to use "IN" for more than one column

This question might be trivial or even silly but I was wondering if there is a way to use "IN" on more than one column on one to one matching.
For example I use
select emp_id from employee where emp_id IN (select emp_id from employee_other)
How could I achieve something like
select emp_id from employee where emp_id,emp_org IN (select emp_id,emp_org from employee_other)
I know I cant be using the following because it will simply do the union whereas I want a selection based on one to one record matching.
select emp_id from employee where emp_id IN (select emp_id from employee_other) and emp_org in (select emp_org from employee)
Please note that I am reluctant to use EXCEPT.
Thanks guys
You may want to use the EXISTS operator
select e.emp_id
from employee e
where EXISTS
(
SELECT *
FROM employee_other eo
WHERE e.emp_id = eo.emp_id
AND e.emp_org = eo.emp_org
)
IN in Microsoft SQL Server only works with a single column, ie. you can only write X IN (...), never anything remotely like X,Y IN (...).
There are two ways to handle this, depending on your data:
Joining with a sub-query
Using EXISTS
To JOIN, do this:
select emp_id
from employee
inner join (select emp_id,emp_org from employee) as x
on employee.emp_id = x.emp_id and employee.emp_org = x.emp_org
Your example is a bit lousy, however, since you're using the same table.
To use EXISTS, do this:
select emp_id
from employee
where exists (
select emp_id,emp_org from employee e2
where e2.emp_id = employee.emp_id and e2.emp_org = employee.emp_org)
This, in the same way as the join, links the main table to the "sub-query" table, but whereas the join will produce duplicate rows if the "sub-query" produces multiple hits, the EXISTS clause will not.
I don't understand what you are trying to accomplish with emp_org in (select emp_org from employee) isn't that always true?
does this work?
select emp_id from employee e
where exists (select 1 from employee_other eo
WHERE e.emp_id =eo.emp_id and
AND e.emp_org = eo.emp_org )
You had it almost completely right in your second example. You just need to add parens around your column names.
select emp_id
from employee
where (emp_id,emp_org) IN (select emp_id,emp_org from employee)
Use Inner Join
select e1.emp_id from employee e1
inner join employee_other e2 on e1.emp_id = e1.emp_id and e1.emp_org = e2.emp_org
You may have to use Distinct in case the employee_other table causes dups.
select Distinct e1.emp_id from employee e1
inner join employee_other e2 on e1.emp_id = e1.emp_id and e1.emp_org = e2.emp_org

Explanation of self-joins

I don't understand the need for self-joins. Can someone please explain them to me?
A simple example would be very helpful.
You can view self-join as two identical tables. But in normalization, you cannot create two copies of the table so you just simulate having two tables with self-join.
Suppose you have two tables:
Table emp1
Id Name Boss_id
1 ABC 3
2 DEF 1
3 XYZ 2
Table emp2
Id Name Boss_id
1 ABC 3
2 DEF 1
3 XYZ 2
Now, if you want to get the name of each employee with his or her boss' names:
select c1.Name , c2.Name As Boss
from emp1 c1
inner join emp2 c2 on c1.Boss_id = c2.Id
Which will output the following table:
Name Boss
ABC XYZ
DEF ABC
XYZ DEF
It's quite common when you have a table that references itself. Example: an employee table where every employee can have a manager, and you want to list all employees and the name of their manager.
SELECT e.name, m.name
FROM employees e LEFT OUTER JOIN employees m
ON e.manager = m.id
A self join is a join of a table with itself.
A common use case is when the table stores entities (records) which have a hierarchical relationship between them. For example a table containing person information (Name, DOB, Address...) and including a column where the ID of the Father (and/or of the mother) is included. Then with a small query like
SELECT Child.ID, Child.Name, Child.PhoneNumber, Father.Name, Father.PhoneNumber
FROM myTableOfPersons As Child
LEFT OUTER JOIN myTableOfPersons As Father ON Child.FatherId = Father.ID
WHERE Child.City = 'Chicago' -- Or some other condition or none
we can get info about both child and father (and mother, with a second self join etc. and even grand parents etc...) in the same query.
Let's say you have a table users, set up like so:
user ID
user name
user's manager's ID
In this situation, if you wanted to pull out both the user's information and the manager's information in one query, you might do this:
SELECT users.user_id, users.user_name, managers.user_id AS manager_id, managers.user_name AS manager_name INNER JOIN users AS manager ON users.manager_id=manager.user_id
Imagine a table called Employee as described below. All employees have a manager which is also an employee (maybe except for the CEO, whose manager_id would be null)
Table (Employee):
int id,
varchar name,
int manager_id
You could then use the following select to find all employees and their managers:
select e1.name, e2.name as ManagerName
from Employee e1, Employee e2 where
where e1.manager_id = e2.id
They are useful if your table is self-referential. For example, for a table of pages, each page may have a next and previous link. These would be the IDs of other pages in the same table. If at some point you want to get a triple of successive pages, you'd do two self-joins on the next and previous columns with the same table's id column.
Without the ability for a table to reference itself, we'd have to create as many tables for hierarchy levels as the number of layers in the hierarchy. But since that functionality is available, you join the table to itself and sql treats it as two separate tables, so everything is stored nicely in one place.
Apart from the answers mentioned above (which are very well explained), I would like to add one example so that the use of Self Join can be easily shown.
Suppose you have a table named CUSTOMERS which has the following attributes:
CustomerID, CustomerName, ContactName, City, Country.
Now you want to list all those who are from the "same city" .
You will have to think of a replica of this table so that we can join them on the basis of CITY. The query below will clearly show what it means:
SELECT A.CustomerName AS CustomerName1, B.CustomerName AS CustomerName2,
A.City
FROM Customers A, Customers B
WHERE A.CustomerID <> B.CustomerID
AND A.City = B.City
ORDER BY A.City;
There are many correct answers here, but there is a variation that is equally correct. You can place your join conditions in the join statement instead of the WHERE clause.
SELECT e1.emp_id AS 'Emp_ID'
, e1.emp_name AS 'Emp_Name'
, e2.emp_id AS 'Manager_ID'
, e2.emp_name AS 'Manager_Name'
FROM Employee e1 RIGHT JOIN Employee e2 ON e1.emp_id = e2.emp_id
Keep in mind sometimes you want e1.manager_id > e2.id
The advantage to knowing both scenarios is sometimes you have a ton of WHERE or JOIN conditions and you want to place your self join conditions in the other clause to keep your code readable.
No one addressed what happens when an Employee does not have a manager. Huh? They are not included in the result set. What if you want to include employees that do not have managers but you don't want incorrect combinations returned?
Try this puppy;
SELECT e1.emp_id AS 'Emp_ID'
, e1.emp_name AS 'Emp_Name'
, e2.emp_id AS 'Manager_ID'
, e2.emp_name AS 'Manager_Name'
FROM Employee e1 LEFT JOIN Employee e2
ON e1.emp_id = e2.emp_id
AND e1.emp_name = e2.emp_name
AND e1.every_other_matching_column = e2.every_other_matching_column
Self-join is useful when you have to evaluate the data of the table with itself. Which means it'll correlate the rows from the same table.
Syntax: SELECT * FROM TABLE t1, TABLE t2 WHERE t1.columnName = t2.columnName
For example, we want to find the names of the employees whose Initial Designation equals to current designation. We can solve this using self join in following way.
SELECT NAME FROM Employee e1, Employee e2 WHERE e1.intialDesignationId = e2.currentDesignationId
One use case is checking for duplicate records in a database.
SELECT A.Id FROM My_Bookings A, My_Bookings B
WHERE A.Name = B.Name
AND A.Date = B.Date
AND A.Id != B.Id
SELF JOIN:
Joining a table by itself is called as Self Join.
We can perform operations on a single table.
When we use self join we should create alias names on a table otherwise we cannot implement self join.
When we create alias name on a table internally system is preparing virtual table on each alias name of a table.
We can create any number of alias names on a table but each alias name should be different.
Basic Rules of self join:
CASE-I: Comparing a single column values by itself with in the table
CASE-II: Comparing two different columns values to each other with in the table.
Example:
SELECT * from TEST;
ENAME
RICHARD
JOHN
MATHEW
BENNY
LOC
HYDRABAD
MUMBAI
HYDRABAD
CHENNAI
SELECT T1. ENAME, T1. LOC FROM TEST.T1, TEST T2 WHERE T1.LOC=T2.LOC AND T2.ENAME='RICHARD';
It's the database equivalent of a linked list/tree, where a row contains a reference in some capacity to another row.
Here is the exaplanation of self join in layman terms. Self join is not a different type of join. If you have understood other types of joins (Inner, Outer, and Cross Joins), then self join should be straight forward. In INNER, OUTER and CROSS JOINS, you join 2 or more different tables. However, in self join you join the same table with itslef. Here, we don't have 2 different tables, but treat the same table as a different table using table aliases. If this is still not clear, I would recomend to watch the following youtube videos.
Self Join with an example