inner join vs stored procedure or Function sql server - sql

I have this schema :
When I want to display the Attend table, instead of DoctorId and PatientId, Employee Name And Patient Name display.
Like this:
id
Patient name
Doctor Name [== Employee name]
Start
End
First way is to use an inner join :
select
a.Id, p.Name, a.Name, a.Start, a.End
from
Patient as p
inner join
(select
e.Name, at.Id, at.Start, at.End, at.PatientId
from
Attend as at
INNER JOIN
Employee as e on at.DoctorId = e.Id) as a on p.Id = a.PatientId
Second way is to use a function or stored procedure - send in the id and get back name
select
a.Id,
FindDoctor(a.DoctorId) as Doctor,
FindPatient(a.PatientId) as Patient,
a.Start, a.EndTime
from
Attend AS a
Which is the better? Which is the optimized approach?

In general, SQL engines do a better job of optimizing queries than of optimizing function calls. I would suggest that you stick with the query, at least at first. This also makes it easier to understand performance issues that might arise.
By the way, there is no need for a subquery for what you want to do. SQL Server is pretty smart, so it probably doesn't affect performance. However, you can write the query as:
select at.Id , p.Name , e.Name , at.Start, at.End
from Patient p inner join
Attend at
on p.Id = at.PatientId inner join
Employee as e
on at.DoctorId = e.Id;
Some people like to embed such queries in stored procedures. If you want to encapsulate this logic, I would suggest a view or table-valued function instead.

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

Need help understanding a Simple SQL query to retrieve data

I am having trouble creating a SQL query that will list the names of manager(s) whose employee(s) handle less than two orders.
Here is a picture of the database, I tried to put an output of the database, but had trouble.
http://s22.postimg.org/spou700b5/printout.jpg
SELECT O.Name
FROM Employee E
JOIN Employee O ON O.EmployeeID = E.ManagerID
LEFT OUTER JOIN OrderT T ON T.EmployeeID = E.EmployeeID
GROUP BY O.Name
HAVING COUNT(T.OrderID) < 2

SQL Solving with Subqueries?

I'm a beginner trying to learn and practice SQL with tables based on this schema:
EMPLOYEE - ID, Name
ASSIGNMENT - ID, Country, Start, End
The primary keys are Employee.ID and all four columns shown for ASSIGNMENT; and ASSIGNMENT.ID is a reference to EMPLOYEE.ID. The domain of start and end is in years.
Problem: I'm trying to write a query that will display all the employees (by name) where they were assigned to an assignment in the USA directly after they had completed an assignment in Canada.
This is my current attempt, which fails to compute. I believe I am heading in the correct direction but there are syntactical mistakes.
SELECT
E.Name
FROM
EMPLOYEE E
INNER JOIN
ASSIGNMENT A ON E.ID = A.ID
WHERE
(SELECT End FROM ASSIGNMENT
WHERE Country = 'Canada') = (SELECT Start FROM ASSIGNMENT
WHERE COUNTRY = 'USA')
GROUP BY
E.Name;
Any critique to benefit my understanding of my misconceptions are welcome. My errors are coming from the combination of the subqueries in the WHERE clause
At most one record can be returned by this subquery.
Perhaps someone can show me another way to compute this?
This query is being tested in MS Access since I found it easy to build a database and relationships quickly.
Instead of subqueries use another join and add constraints to the join conditions:
SELECT
E.Name
FROM
EMPLOYEE E
INNER JOIN
ASSIGNMENT A ON ( E.ID = A.ID
AND A.Country = 'Canada' )
INNER JOIN
ASSIGNMENT B ON ( E.ID = B.ID
AND B.Country = 'USA'
AND B.Start = A.End )
GROUP BY
E.Name;
Update
The OP reported an error from MS Access complaining about the composite join condition for the above version. However, you may safely move inner join conditions to the where clause. The interim resultsets will grow, though, since the product of the tables is produced first with less constraints and filtered thereafter (A good query optimizer might avoid the unnecessary generation of records, but I do not know about the capabilities of MS Access in this regard).
SELECT
E.Name
FROM
EMPLOYEE E
INNER JOIN
ASSIGNMENT A ON ( E.ID = A.ID )
INNER JOIN
ASSIGNMENT B ON ( E.ID = B.ID )
WHERE
A.Country = 'Canada'
AND B.Country = 'USA'
AND B.Start = A.End
GROUP BY
E.Name;

How do I compose this sql query in Oracle?

I have got an sql query that pulls out all sorts of information. Part of it is the following
select gsm.mobile_no, emp.employee_id, d.department_id
from data gsm, employees emp, department d
where gsm.code = e.code
and d.id = e.id
Now there's a column called roaming in another table called "call" . Here's the problem. There's information from the call table for only some of the mobile numbers so when I join gsm.code = call.id like below
select gsm.mobile_no, emp.employee_id, d.department_id, roaming.name
from data gsm, employees emp, department d, call roaming
where gsm.code = e.code
and d.id = e.i
and roaming.id = gsm.code
Then I lose information about employees and departments since only the records that satisfy the condition roaming.id = gsm.code are retrieved so I lose info about departments, employees and all other mobile numbers. I want to retrieve all records from all tables including roaming.id for the mobile numbers where applicable and if there's no data available for some of the mobile numbers then display null but I want all of the records displayed.
How could I do that?
Your time has come to move to the world of modern join syntax. Put your join conditions in the on clause and remember the simple rule: Never use a comma in the from clause.
What you need is a left outer join. You can't really do that in the where clause. Well, you can in Oracle, but it is not pretty and not as good as a real left outer join.
select gsm.mobile_no, emp.employee_id, d.department_id, roaming.name
from employes left outer join
data gsm
on gsm.code = e.code left join
department d
on d.id = e.i left outer join
call roaming
on roaming.id = gsm.code;
Although you can mix inner and outer joins, you want to keep all employees. So start with that table and make all the joins left outer join.

Three tables join given me the all combination of records

When i written the query like the following.. It's written the combination of all the records.
What's the mistake in the query?
SELECT ven.vendor_code, add.address1
FROM vendor ven INNER JOIN employee emp
ON ven.emp_fk = emp.id
INNER JOIN address add
ON add.emp_name = emp.emp_name;
Using inner join, you've to put all the links (relations) between two tables in the ON clause.
Assuming the relations are good, you may test the following queries to see if they really make the combination of all records:
SELECT count(*)
from vendor ven
inner join employee emp on ven.emp_fk = emp.id
inner join address add on add.emp_name = emp.emp_name;
SELECT count(*)
add.address1
from vendor ven, employee emp, address add
If both queries return the same result (which I doubt), you really have what you say.
If not, as I assume, maybe you are missing a relation or a restriction to filter the number of results.