Académique Documents
Professionnel Documents
Culture Documents
Inner Join
Inner join is the most common type of Join which is used to combine the rows from two tables
and create a result set containing only such records that are present in both the tables based on
the joining condition (predicate).
Inner join returns rows when there is at least one match in both tables
If none of the record matches between two tables, then INNER JOIN will return a NULL set.
Below is an example of INNER JOIN and the resulting set.
SELECT dept.name DEPARTMENT, emp.name EMPLOYEE
FROM DEPT dept, EMPLOYEE emp
WHERE emp.dept_id = dept.id
Department
Employee
HR
Inno
HR
Privy
Engineering
Robo
Engineering
Hash
Engineering
Anno
Engineering
Darl
Marketing
Pete
Marketing
Meme
Sales
Tomiti
Sales
Bhuti
Outer Join
Outer Join can be full outer or single outer
Outer Join, on the other hand, will return matching rows from both tables as well as any
unmatched rows from one or both the tables (based on whether it is single outer or full outer join
respectively).
Notice in our record set that there is no employee in the department 5 (Logistics). Because of this
if we perform inner join, then Department 5 does not appear in the above result. However in the
below query we perform an outer join (dept left outer join emp), and we can see this department.
SELECT dept.name DEPARTMENT, emp.name EMPLOYEE
FROM DEPT dept, EMPLOYEE emp
WHERE dept.id = emp.dept_id (+)
Department
Employee
HR
Inno
HR
Privy
Engineering
Robo
Engineering
Hash
Engineering
Anno
Engineering
Darl
Marketing
Pete
Marketing
Meme
Sales
Tomiti
Sales
Bhuti
Logistics
The (+) sign on the emp side of the predicate indicates that emp is the outer table here. The
above SQL can be alternatively written as below (will yield the same result as above):
SELECT dept.name DEPARTMENT, emp.name EMPLOYEE
FROM DEPT dept LEFT OUTER JOIN EMPLOYEE emp
ON dept.id = emp.dept_id
What is the difference between JOIN and UNION?
SQL JOIN allows us to lookup records on other table based on the given conditions between
two tables. For example, if we have the department ID of each employee, then we can use this
department ID of the employee table to join with the department ID of department table to
lookup department names.
UNION operation allows us to add 2 similar data sets to create resulting data set that contains all
the data from the source data sets. Union does not require any condition for joining. For
example, if you have 2 employee tables with same structure, you can UNION them to create one
result set that will contain all the employees from both of the tables.
SELECT * FROM EMP1
UNION
SELECT * FROM EMP2;
What is the difference between UNION and UNION ALL?
UNION and UNION ALL both unify for add two structurally similar data sets, but UNION
operation returns only the unique records from the resulting data set whereas UNION ALL will
return all the rows, even if one or more rows are duplicated to each other.
In the following example, I am choosing exactly the same employee from the emp table and
performing UNION and UNION ALL. Check the difference in the result.
SELECT * FROM EMPLOYEE WHERE ID = 5
UNION ALL
SELECT * FROM EMPLOYEE WHERE ID = 5
ID
MGR_ID
DEPT_ID
NAME
SAL
DOJ
5.0
2.0
2.0
Anno
80.0
01-Feb-2012
5.0
2.0
2.0
Anno
80.0
01-Feb-2012
MGR_ID
DEPT_ID
NAME
SAL
DOJ
5.0
2.0
2.0
Anno
80.0
01-Feb-2012
WHERE and HAVING both filters out records based on one or more conditions. The difference
is, WHERE clause can only be applied on a static non-aggregated column whereas we will need
to use HAVING for aggregated columns.
To understand this, consider this example.
Suppose we want to see only those departments where department ID is greater than 3. There is
no aggregation operation and the condition needs to be applied on a static field. We will use
WHERE clause here:
SELECT * FROM DEPT WHERE ID > 3
ID
NAME
Sales
Logistics
Next, suppose we want to see only those Departments where Average salary is greater than 80.
Here the condition is associated with a non-static aggregated information which is average of
salary. We will need to use HAVING clause here:
SELECT dept.name DEPARTMENT, avg(emp.sal) AVG_SAL
FROM DEPT dept, EMPLOYEE emp
WHERE dept.id = emp.dept_id (+)
GROUP BY dept.name
HAVING AVG(emp.sal) > 80
DEPARTMENT
AVG_SAL
Engineering
90
As you see above, there is only one department (Engineering) where average salary of
employees is greater than 80.
What is the difference among UNION, MINUS and INTERSECT?
UNION combines the results from 2 tables and eliminates duplicate records from the result set.
MINUS operator when used between 2 tables, gives us all the rows from the first table except the
rows which are present in the second table.
INTERSECT operator returns us only the matching or common rows between 2 result sets.
To understand these operators, lets see some examples. We will use two different queries to
extract data from our emp table and then we will perform UNION, MINUS and INTERSECT
operations on these two sets of data.
UNION
SELECT * FROM EMPLOYEE WHERE ID = 5
UNION
SELECT * FROM EMPLOYEE WHERE ID = 6
ID
MGR_ID
DEPT_ID
NAME
SAL
DOJ
2.0
Anno
80.0
01-Feb-2012
2.0
Darl
80.0
11-Feb-2012
DEPT_ID
NAME
SAL
DOJ
Hash
100.0
01-Jan-2012
Robo
100.0
01-Jan-2012
MINUS
SELECT * FROM EMPLOYEE
MINUS
SELECT * FROM EMPLOYEE WHERE ID > 2
ID
MGR_ID
1
2
INTERSECT
SELECT * FROM EMPLOYEE WHERE ID IN (2, 3, 5)
INTERSECT
SELECT * FROM EMPLOYEE WHERE ID IN (1, 2, 4, 5)
ID
MGR_ID
DEPT_ID
NAME
SAL
DOJ
Anno
80.0
01-Feb-2012
Robo
100.0
01-Jan-2012
MANAGER
Pete
Hash
Darl
Hash
Inno
Hash
Robo
Hash
Tomiti
Robo
Anno
Robo
Privy
Robo
Meme
Pete
Bhuti
Tomiti
Hash
The only reason we have performed a left outer join here (instead of INNER JOIN) is we have
one employee in this table without a manager (employee ID = 1). If we perform inner join, this
employee will not show-up.
How can we transpose a table using SQL (changing rows to column or vice-versa) ?
The usual way to do it in SQL is to use CASE statement or DECODE statement.
SAL
ROW_NUM
Anno
80
Bhuti
60
Darl
80
Hash
100
Inno
50
Meme
60
Pete
70
Privy
50
Robo
100
Tomiti
70
10
The column that is used in the row number generation logic is called sort key. Here sort key is
name column. For this technique to work, the sort key needs to be unique. We have chosen the
column name because this column happened to be unique in our Employee table. If it was not
unique but some other collection of columns was, then we could have used those columns as our
sort key (by concatenating those columns to form a single sort key).
Also notice how the rows are sorted in the result set. We have done an explicit sorting on the
row_num column, which gives us all the row numbers in the sorted order. But notice that name
column is also sorted (which is probably the reason why this column is referred as sort-key). If
you want to change the order of the sorting from ascending to descending, you will need to
change >= sign to <= in the query.
As I said before, this method is not very generic. This is why many databases already implement
other methods to achieve this. For example, in Oracle database, every SQL result set contains a
hidden column called ROWNUM. We can just explicitly select ROWNUM to get sequence
numbers.
How to select first 5 records from a table?
This question, often asked in many interviews, does not make any sense to me. The
problem here is how do you define which record is first and which is second. Which
record is retrieved first from the database is not deterministic. It depends on many
uncontrollable factors such as how database works at that moment of execution etc. So the
question should really be how to select any 5 records from the table? But whatever it
is, here is the solution:
In Oracle,
SELECT *
FROM EMP
WHERE ROWNUM <= 5;
In SQL Server,
SELECT TOP 5 * FROM EMP;
Generic solution,
I believe a generic solution can be devised for this problem if and only if there exists at least one
distinct column in the table. For example, in our EMP table ID is distinct. We can use that
distinct column in the below way to come up with a generic solution of this question that does
not require database specific functions such as ROWNUM, TOP etc.
SELECT name
FROM EMPLOYEE o
WHERE (SELECT count(*) FROM EMPLOYEE i WHERE i.name < o.name) < 5
Name
Inno
Anno
Darl
Meme
Bhuti
I have taken name column in the above example since name is happened to be unique in this
table. I could very well take ID column as well.
In this example, if the chosen column was not distinct, we would have got more than 5 records
returned in our output.
Do you have a better solution to this problem? If yes, post your solution in the comment.
What is the difference between ROWNUM pseudo column and ROW_NUMBER()
function?
ROWNUM is a pseudo column present in Oracle database returned result set prior to ORDER
BY being evaluated. So ORDER BY ROWNUM does not work.
ROW_NUMBER() is an analytical function which is used in conjunction to OVER() clause
wherein we can specify ORDER BY and also PARTITION BY columns.
Suppose if you want to generate the row numbers in the order of ascending employee salaries for
example, ROWNUM will not work. But you may use ROW_NUMBER() OVER() like shown
below:
SELECT name, sal, row_number() over(order by sal desc) rownum_by_sal
FROM EMPLOYEE o
name
Sal
ROWNUM_BY_SAL
Hash
100
Robo
100
Anno
80
Darl
80
Tomiti
70
Pete
70
Bhuti
60
Meme
60
Inno
50
Privy
50
10
Sal
RANK_BY_SAL
Hash
100
Robo
100
Anno
80
Darl
80
Tomiti
70
Pete
70
Bhuti
60
Meme
60
Inno
50
Privy
50
DENSE_RANK, like RANK, does not assign unique numbers, but it does assign contiguous
numbers. Even though two records tied for second place, there is a third-place record. See below:
SELECT name, sal, dense_rank() over(order by sal desc) dense_rank_by_sal
FROM EMPLOYEE o
name
Sal
DENSE_RANK_BY_SAL
Hash
100
Robo
100
Anno
80
Darl
80
Tomiti
70
Pete
70
Bhuti
60
Meme
60
Inno
50
Privy
50
lastname
firstname location
class
13232
Baker
Roland
New York
Car
18431
Smythe
Michael
Miami
Truck
41948
Jacobs
Abraham
Seattle
Car
81231
Ryan
Jack
Annapolis
vehicles
tag
location
class
D824HA
Miami
Truck
H122JM
New York
Car
Car
J291QR
Seattle
Car
L990MT
Seattle
Truck
P091YF
Miami
Car
Ads
PHP Forumwww.daniweb.comFree community help & discussion Engage with savvy web
developers
OPC To Sqlwww.matrikonopc.com/OPCDatabasesEasily store OPC to databases. Easy to use,
Free to try.
Find & Remove Duplicateswww.cloudingo.comGet rid of duplicates in your CRM From the
makers of DupeCatcher!
In the previous article, we looked at methods used to retrieve data from single tables. For
example, we could use simple SELECT statements to answer questions such as:
Which drivers are located in New York?
How many cars are in each city?
Which drivers assigned to drive trucks are located in Miami?
Practical applications often require the combination of data from multiple tables. Our vehicle
managers might make requests like the following:
List all of the vehicle/driver pairings possible without relocating a vehicle or driver
List all of the drivers authorized to drive vehicles located in Miami
Granted, it would be possible to create complex SELECT statements using subqueries to fulfill
these requests. However, there's a much simpler method -- the use of inner and outer joins. We'll
explore each of these concepts in the next two sections of this article. Read on!
Retrieving Data from Multiple Tables with SQL Joins
Part 2: Inner Joins (Equijoins)
More of this Feature
not make a difference as the columns are identical and they are joined using an
equijoin. However, if the columns contained different data this distinction would be
critical. Here are the results of this query:
lastname FirstName
Tag
Class
-------- --------- ------Baker
Roland
H122JM
Car
Smythe
Michael
D824HA
Truck
Jacobs
Abraham
J291QR
Car
Notice that the rows pairing Michael Smythe to a car and Abraham Jacobs to a truck have been
removed.
You can also use inner joins to combine data from three or more tables.
Outer joins allow database users to include additional information in the query results. We'll
explore them in the next section of this article. Read on!
Next page > Outer Joins > Page 1, 2, 3
Smythe
Jacobs
Jacobs
Ryan
Michael
Miami
P091YF
Abraham
Seattle J291QR
Abraham
Seattle L990MT
Patrick
Annapolis
This time our results include the stranded Patrick Ryan and our vehicle management department
can now dispatch a vehicle to pick him up.
Note that there are other possible ways to accomplish the results seen in this article and syntax
may vary slightly from DBMS to DBMS. These examples were designed to work with Oracle
databases, so your mileage may vary. Furthermore, as you advance in your knowledge of SQL
youll discover that there is often more than one way to accomplish a desired result and
oftentimes one way is just as good as another. Case in point, it is also possible to specify a join
condition in the FROM clause rather than the WHERE clause. For example, we used the
following SELECT statement earlier in this article:
Ads
Database Synchronizationwww.pervasync.comSupports My SQL, OracleDB, MS SQL Server
and SQLite.
Scaffoldingwww.cityscaffoldings.inLeading Supplier of Best Quality Scaffoldings. Enquire for
Details.
Home Loaninstantloan.pnbhfl.com/home-loanGet Loan upto 80%*of Property Cost. Avail
Doorstep Services @ PNBHFL.
SELECT lastname, firstname, tag
FROM drivers, vehicles
WHERE drivers.location = vehicles.location
AND drivers.class = vehicles.class
The same query could be rewritten as:
SELECT lastname, firstname, tag
FROM drivers INNER JOIN vehicles ON drivers.location = vehicles.location
WHERE drivers.class = vehicles.class
That's it for this week! Be sure to check back next week for a new exciting article on
databases. If you'd like a reminder in your Inbox, subscribe to the About Databases newsletter.
Next page > > Page 1, 2, 3
Related Resources
SQL Fundamentals
Starting a Career in
Databases
Certification Resources
Let's begin by taking a look at two sample tables that comprise the
course database for a school. We might first have a list of courses and instructors, as shown
below. (Note that, for simplicity's sake, we are making the assumption that there is only one
section of each course and, therefore, that we can use it as the primary key.) In this case, the
instructor Adams has not yet been assigned to a course and the Computers course has no
instructor assigned yet.
Course Instructor
Math
Smith
Science Jones
NULL
Adams
Computers NULL
Now, let's assume that we have a table containing course registrations for students. Again, for
simplicity's sake, we'll assume that each student must take one and only one course. Every
student must take a class, so we will include a NULL record for any student whose course
registration information is unknown. In this case, we're not sure what course Alan is taking.
Student Course
Ryan Math
Betty Science
Alan NULL
If we perform an INNER JOIN, NULL values do not match each other. For example, if we
perform the following query:
SELECT *
FROM Instructors INNER JOIN Students
ON Instructors.Course = Students.Course
We'd get the following result:
Course Instructor Student
Math Smith
Ryan
Science Jones
Betty
The OUTER JOIN operations includes data from one or both tables that doesn't match data in the
Would yield:
Course Instructor Student
Math
Smith
Ryan
Science Jones
Betty
Computers NULL
NULL
NULL
NULL
Alan
NULL
Adams
NULL
And that's a look at how NULL values are treated by the JOIN operation!
Aggregate Functions in SQL
Part 1: Introducing SUM and AVG
OrderID
FirstName
LastName
Quantity
UnitPrice
Continent
122
John
Jacob
21
4.52
North America
923
Ralph
Wiggum
192
3.99
North America
238
Ryan
Johnson
87
4.49
Africa
829
Mary
Smith
842
2.99
North America
824
Elizabeth
Marks
48
3.48
Africa
753
James
Linea
7.85
North America
942
Alan
Jonas
638
3.29
Europe
Let's begin by taking a look at the SUM function. It is used within a SELECT statement and,
predictably, returns the summation of a series of values. If the widget project manager wanted to
know the total number of widgets sold to date, we could use the following query:
SELECT SUM(Quantity) AS Total
FROM WidgetOrders
Our results would appear as:
Total
----------1837
The AVG (average) function works in a similar manner to provide the mathematical average of a
series of values. Let's try a slightly more complicated task this time. We'd like to find out the
average dollar amount of all orders placed on the North American continent. Note that we'll have
to multiply the Quantity column by the UnitPrice column to compute the dollar amount of each
order. Here's what our query will look like:
SELECT AVG(UnitPrice * Quantity) As AveragePrice
FROM WidgetOrders
WHERE Continent = "North America"
And the results:
AveragePrice
--------------------862.3075
In the next section of this article, we'll explore methods used for counting the number of records
that meet given criteria. Read on!
Next page > Counting Records > Page 1, 2, 3
SQL provides the COUNT function to retrieve the number of records Part 1: Sum and
in a table that meet given criteria. We can use the COUNT(*) syntax Average
Part 3: Max and Min
alone to retrieve the number of rows in a table. Alternatively, a
WHERE clause can be included to restrict the counting to specific
Join the Discussion
records.
"Need some assistance or
advice? Join us in the
About Databases forum."
For example, suppose our Widgets product manager would like to
know how many orders our company processed that requested over Mike Chapple
100 widgets.
Here's the SQL query:
SELECT COUNT(*) AS 'Number of Large Orders'
FROM WidgetOrders
WHERE Quantity > 100
And the results:
Number of Large Orders
---------------------3
The COUNT function also allows for the use of the DISTINCT keyword and an expression to
count the number of times a unique value for the expression appears in the target data. Similarly,
the ALL keyword returns the total number of times the expression is satisfied, without worrying
about unique values. For example, our product manager would like a simple query that returned
the number of unique continents in our orders database.
First, let's take a look at the use of the ALL keyword:
SELECT COUNT(ALL Continent) As 'Number of Continents'
FROM WidgetOrders
And the result set:
Number of Continents
-------------------7
Obviously, this is not the desired results. If you recall the contents of the WidgetOrders table
from the previous page, all of our orders came from North America, Africa and Europe. Let's try
the DISTINCT keyword instead:
SELECT COUNT(DISTINCT Continent) As 'Number of Continents'
FROM WidgetOrders
And the output:
Number of Continents
-------------------3
That's more like it!
In the next section of this article, we'll look at the functions used to find the maximum and
minimum values of an expression. Read on!
Apart from using COALESCE(), there are 2 other ways to replace NULL values in SQL Server. Let's
understand this with an example.
I have a Table tblEmployee, as shown in the diagram below. Some of the Employees does not have
gender. All those employees who does not have Gender, must have a replacement value of 'No
Gender' in your query result. Let's explore all the 3 possible options we have.
Self join is not a different type of join. Self join means joining a table with itself. We can have an inner
self join or outer self join. Let us try to understand with an example.
To set up the data for the example, use the script below to create Employee Table and populate it with
some sample data. We will be using Employee Table to understand Self Join.
CREATE TABLE EMPLOYEE
(
[EMPLOYEEID] INT PRIMARY KEY,
[NAME] NVARCHAR(50),
[MANAGERID] INT
)
GO
INSERT INTO EMPLOYEE VALUES(101,'Mary',102)
INSERT INTO EMPLOYEE VALUES(102,'Ravi',NULL)
INSERT INTO EMPLOYEE VALUES(103,'Raj',102)
INSERT INTO EMPLOYEE VALUES(104,'Pete',103)
INSERT INTO EMPLOYEE VALUES(105,'Prasad',103)
INSERT INTO EMPLOYEE VALUES(106,'Ben',103)
GO
We use Self Join, if we have a table that references itself. For example, In the Employee Table below
MANAGERID column references EMPLOYEEID column. So the table is said to referencing itself. This is
the right scenario where we can use Self Join. Now I want to write a query that will give me the list of all
Employee Names and their respective Manager Names. In order to achieve this I can use Self Join. In the
Table below,Raj is the manager for Pete,Prasad and Ben. Ravi is the manager for Raj and Mary. Ravi
does not have a manager as he is the president of the Company.
The query below is an example of Self Join. Both E1 and E2 refer to the same Employee Table. In this
query we are joining the EmployeeTable with itself.
SELECT E1.[NAME],E2.[NAME] AS [MANAGER NAME]
FROM EMPLOYEE E1
INNER JOIN EMPLOYEE E2
ON E2.EMPLOYEEID =E1.MANAGERID
If we run the above query we only get 5 rows out of the 6 rows as shown below.
Inner Self Join
This is because Ravi does not have a Manager. MANAGERID column for Ravi is NULL. If we want to get
all the rows then we can use LEFT OUTER JOIN as shown below.
SELECT E1.[NAME],E2.[NAME] AS [MANAGER NAME]
FROM EMPLOYEE E1
LEFT OUTER JOIN EMPLOYEE E2
ON E2.EMPLOYEEID =E1.MANAGERID
If we execute the above query we get all the rows, including the row that has a null value in the
MANAGERID column. The results are shown below. The MANAGERNAME for 2nd record is NULL as
Ravi does not have a Manager.
Left Outer Self Join
Let us now slightly modify the above query using COALESCE as shown below. Read COALESCE
function in SQL Server to understandCOALESCE in a greater detail.
SELECT E1.[NAME],COALESCE(E2.[NAME],'No Manager') AS [MANAGER NAME]
FROM EMPLOYEE E1
LEFT JOIN EMPLOYEE E2
ON E2.EMPLOYEEID =E1.MANAGERID
If we execute the above query the output will be as shown in the image below. This is
how COALESCE can be used.
Left Outer Self Join with COALESCE
If you want to select all the rows from the LEFT Table ( In our example Candidate Table ) plus all the
rows from the RIGHT table ( In our example Company Table ) , then we use FULL OUTER JOIN. A
query involving a FULL OUTER JOIN for the Candidate and CompanyTable is shown below.
SELECT Cand.CandidateId, Cand.FullName, Cand.CompanyId, Comp.CompanyId,
Comp.CompanyName
FROM Candidate Cand
FULL OUTER JOIN Company Comp
ON Cand.CompanyId = Comp.CompanyId
If we run the above query the output will be as shown in below. If you look at the out put, we now got 8
rows. All the rows from the CandidateTable and all the rows from the Company Table.
(
CandidateId tinyint identity primary key,
FullName nvarchar(50) NULL,
CompanyId tinyint REFERENCES Company(CompanyId)
)
GO
INSERT Candidate VALUES('Ron',1)
INSERT Candidate VALUES('Pete',2)
INSERT Candidate VALUES('Steve',3)
INSERT Candidate VALUES('Steve',NULL)
INSERT Candidate VALUES('Ravi',1)
INSERT Candidate VALUES('Raj',3)
INSERT Candidate VALUES('Kiran',NULL)
GO
If you want to select all the rows from the LEFT Table ( In our example Candidate Table) that
have non null foreign key values plus all the rows from the RIGHT table ( In our
example Company Table) including the rows that are not referenced in the LEFT Table, then we
useRIGHT OUTER JOIN. A query involving a RIGHT OUTER JOIN for
the Candidate and Company Table is shown below.
SELECT Cand.CandidateId, Cand.FullName, Cand.CompanyId, Comp.CompanyId,
Comp.CompanyName
FROM Candidate Cand
RIGHT OUTER JOIN Company Comp
ON Cand.CompanyId = Comp.CompanyId
If we run the above query the output will be as shown in below. If you look at the out put, we now
got 6 rows. All the rows from the CandidateTable that has non null foreign key value plus all the
rows from the Company Table including the row that is not referenced in the CandidateTable.
If you can think of any other sql server interview questions please post them as comments,
so they will be useful to other users like you. This will be a great help from your side to
improve this site.
Email ThisBlogThis!Share to TwitterShare to FacebookShare to Pinterest
No comments:
Post a Comment
If you are aware of any other sql server questions asked in an interview, please post them
below. If you find anything missing or wrong, please feel free to correct by submitting the
form below.
If you want to select all the rows from the LEFT table ( In our example Candidate Table ) including the
rows that have a null foreign key value ( CompanyId in Candidate Table is the foreign key ) then we
use LEFT OUTER JOIN. A query involving a LEFT OUTER JOIN for theCandidate and Company Table
is shown below.
SELECT Cand.CandidateId, Cand.FullName, Cand.CompanyId, Comp.CompanyId,
Comp.CompanyName
FROM Candidate Cand
LEFT OUTER JOIN Company Comp
ON Cand.CompanyId = Comp.CompanyId
If we run the above query the output will be as shown in below. If you look at the out put, we now got all 7
rows ( All the rows from theCandidate Table ) including the row that has a null value for
the CompanyId column in the Candidate Table. So, LEFT OUTER JOIN would get all the rows from
the LEFT Table including the rows that has null foreign key value.
If you want to select all the rows from the LEFT table(In our example Candidate Table) that have a non
null foreign key value(CompanyId inCandidate Table is the foreign key) then we use INNER JOIN. A
query involving an INNER JOIN for the Candidate and Company Table is shown below.
SELECT Cand.CandidateId, Cand.FullName, Cand.CompanyId, Comp.CompanyId,
Comp.CompanyName
FROM Candidate Cand
INNER JOIN Company Comp
ON Cand.CompanyId = Comp.CompanyId
If we run the above query the output will be as shown in the image below. If you look at the out put, we
only got 5 rows. We did not get the 2 rows which has NULL value in the CompanyId column. So an
INNER JOIN would get all the rows from the LEFT Table that has non null foreign key value.
Once again, we'll use the WidgetOrders example table for this query
(see the first page of this article for the specification and contents). Suppose our product
manager wanted to find the order in our database that produced the most revenue for the
company. We could use the following query to find the order with the largest total dollar value:
SELECT MAX(Quantity * UnitPrice)As 'Largest Order'
FROM WidgetOrders
Our results would look like this:
Largest Order
--------------------2517.58
The MIN() function functions in the same manner, but returns the minimum value for the
expression. Let's try a slightly more complicated example utilizing the MIN() function. Our
sales department is currently analyzing data on small widget orders. They'd like us to retrieve
information on the smallest widget order placed on each continent. This requires the use of the
MIN() function on a computed value and a GROUP BY clause to summarize data by continent.
Here's the SQL:
SELECT Continent, MIN(Quantity * UnitPrice) AS 'Smallest Order'
FROM WidgetOrders
GROUP BY Continent
And our result set:
Continent Smallest Order
------------- --------------------Africa
167.04
Europe
2099.02
North America 70.65
That's it for this week. If you're not clear on the use of aggregate functions, be sure to stop by
our forum for some assistance. Check back each week for coverage of a new databases topic. If
you'd like a weekly reminder by e-mail, be sure to subscribe to our newsletter.
Explain about RANK,ROW_NUMBER and DENSE_RANK in Sql server ?
Found a very interesting explanation for the same in the url Click Here . PFB the content of the
same here.
Lets take 1 simple example to understand the difference between 3.
First lets create some sample data :
create table
CREATE TABLE Salaries
(
Names VARCHAR(1),
SalarY INT
)
GO
insert data
INSERT INTO Salaries SELECT
A,5000 UNION ALL SELECT
B,5000 UNION ALL SELECT
C,3000 UNION ALL SELECT
D,4000 UNION ALL SELECT
E,6000 UNION ALL SELECT
F,10000
GO
Test the data
SELECT Names, Salary
FROM Salaries
Now lets query the table to get the salaries of all employees with their salary in descending order.
For that Ill write a query like this :
SELECT names
, salary
,row_number () OVER (ORDER BY salary DESC) as ROW_NUMBER
,rank () OVER (ORDER BY salary DESC) as RANK
,dense_rank () OVER (ORDER BY salary DESC) as DENSE_RANK
FROM salaries
>>Output
NAMES
F
E
A
B
D
C
SALARY
10000
6000
5000
5000
4000
3000
ROW_NUMBER
1
2
3
4
5
6
RANK
1
2
3
3
5
6
DENSE_RANK
1
2
3
3
4
5
Interesting Names in the result are employee A, B and D. Row_number assign different number
to them. Rank and Dense_rank both assign same rank to A and B. But interesting thing is what
RANK and DENSE_RANK assign to next row? Rank assign 5 to the next row, while dense_rank
assign 4.
The numbers returned by the DENSE_RANK function do not have gaps and always have
consecutive ranks. The RANK function does not always return consecutive integers. The
ORDER BY clause determines the sequence in which the rows are assigned their unique
ROW_NUMBER within a specified partition.
So question is which one to use?
Its all depends on your requirement and business rule you are following.
1. Row_number to be used only when you just want to have serial number on result set. It is not
as intelligent as RANK and DENSE_RANK.
2. Choice between RANK and DENSE_RANK depends on business rule you are following.
Rank leaves the gaps between number when it sees common values in 2 or more rows.
DENSE_RANK dont leave any gaps between ranks.
So while assigning the next rank to the row RANK will consider the total count of rows before
that row and DESNE_RANK will just give next rank according to the value.
So If you are selecting employees rank according to their salaries you should be using
DENSE_RANK and if you are ranking students according to there marks you should be using
RANK(Though it is not mandatory, depends on your requirement.)
COMPAREDATE
unit
DateUtils
category
date/time
routines
declaration
type TValueRelationship = -1..1
function CompareDate(const ADate, BDate: TDateTime) : TValueRelationship
description
Compares two TDateTime values (returns "less", "equal" or "greater"). Ignores the Time
part if both values "fall" on the same day.
TValueRelationship represents the relationship between two values. Each of three
TValueRelationship values has a "liked" symbolic constant:
-1 [LessThanValue] The first value is less than the second value.
0 [EqualsValue] The two values are equal.
1 [GreaterThanValue] The first value is greater than the second value.
CompareDate results in:
LessThanValue if ADate occurs on a day prior to the Date part of the BDate.
EqualsValue if date parts of both ADate and BDate are the same, ignoring the Time part.
GreaterThanValue if ADate occurs on a day that follows the Date part of the BDate.
example
var ThisMoment, AnotherMoment : TDateTime;
ThisMoment := Now;
AnotherMoment := IncADay(ThisMoment, 5); //adds 5 days
COMPAREDATETIME
unit
DateUtils
category
date/time
routines
declaration
type TValueRelationship = -1..1
function CompareDateTime(const ADate, BDate: TDateTime) : TValueRelationship
description
Compares two TDateTime values (returns "less", "equal" or "greater").
TValueRelationship represents the relationship between two values. Each of three
TValueRelationship values has a "liked" symbolic constant:
-1 [LessThanValue] The first value is less than the second value.
0 [EqualsValue] The two values are equal.
1 [GreaterThanValue] The first value is greater than the second value.
CompareDate results in:
LessThanValue if ADate is earlier than BDate.
EqualsValue if date and time parts of both ADate and BDate are the same
GreaterThanValue if ADate is later than BDate.
example
var ThisMoment, FutureMoment : TDateTime;
ThisMoment := Now;
FutureMoment := IncDay(ThisMoment, 6); //adds 6 days
COMPARETIME
unit
DateUtils
category
date/time
routines
declaration
type TValueRelationship = -1..1
function CompareDate(const ADate, BDate: TDateTime) : TValueRelationship
description
Compares two TDateTime values (returns "less", "equal" or "greater"). Ignores the Time
part if both values occur at the same time.
TValueRelationship represents the relationship between two values. Each of three
TValueRelationship values has a "liked" symbolic constant:
-1 [LessThanValue] The first value is less than the second value.
0 [EqualsValue] The two values are equal.
1 [GreaterThanValue] The first value is greater than the second value.
CompareDate results in:
LessThanValue if ADate occurs earlier in the day specified by BDate.
EqualsValue if time parts of both ADate and BDate are the same, ignoring the Date part.
GreaterThanValue if ADate occurs later in the day specified by BDate.
example
var ThisMoment, AnotherMoment : TDateTime;
ThisMoment := Now;
AnotherMoment := IncHour(ThisMoment, 6); //adds 6 hours
DATE
unit
Sysutils
category
date/time
routines
declaration
type TDateTime = type Double;
function date: TDateTime;
description
Returns the current system date.
The integral part of a TDateTime value is the number of days that have passed since 12/30/1899.
The fractional part of a TDateTime value is fraction of a 24 hour day that has elapsed.
To find the fractional number of days between two dates, simply subtract the two values.
Likewise, to increment a date and time value by a certain fractional number of days, simply add
the fractional number to the date and time value.
example
DATETOSTR
declaration
function DateToStr(Value: TDateTime): string;
description
Converts a TDateTime value to a string.
unit
Sysutils
category
date/time
routines
The conversion uses the format specified by the ShortDateFormat global variable.
example
DATETIMETOFILEDATE
declaration
function DateTimeToFileDate(DateTime: TDateTime): Integer;
description
Converts a TDateTime value to a system timestamp value.
example
var aFile : string;
aFileDateTime : TDateTime;
aFileOSDate : integer;
begin
aFile : = Application.ExeName;
aFileOSDate := FileAge(aFile);
unit
Sysutils
category
date/time
routines
FileSetDate(aFile, DateTimeToFileDate(aFileDateTime));
DATETIMETOSTR
unit
Sysutils
category
date/time
routines
declaration
function DateTimeToStr(Value: TDateTime): string;
description
Converts a TDateTime value to a string.
The conversion uses the format specified by the ShortDateFormat global variable for a date part,
followed by the time using the format given by the LongTimeFormat global variable.
example
DAYOFWEEK
declaration
type TDateTime = type Double;
function DayOfWeek(Date: TDateTime): integer;
unit
Sysutils
category
date/time
routines
description
Returns the day of the week for a given date.
DayOfWeek returns an integer between 1 and 7, where Sunday is the first day of the week and
Saturday is the seventh.
DayOfTheWeek is not compliant with the ISO 8601 standard.
example
const Days: array[1..7] of string =
('Sunday', 'Monday', 'Tuesday',
'Wednesday', 'Thursday',
'Friday', 'Saturday')
//Today is Monday
DATETIMETOSTR
unit
Sysutils
category
date/time
routines
declaration
function DateTimeToStr(Value: TDateTime): string;
description
Converts a TDateTime value to a string.
The conversion uses the format specified by the ShortDateFormat global variable for a date part,
followed by the time using the format given by the LongTimeFormat global variable.
example
DAYOFTHEWEEK
unit
Sysutils
category
date/time
routines
declaration
type TDateTime = type Double;
function DayOfTheWeek(Date: TDateTime): word;
description
Returns the day of the week for a given TDateTime value.
DayOfTheWeek returns an integer between 1 and 7, where Monday is the first day of the week
and Sunday is the seventh.
DayOfTheWeek is compliant with the ISO 8601 standard.
example
const Days: array[1..7] of string =
('Monday', 'Tuesday',
'Wednesday', 'Thursday',
'Friday', 'Saturday', 'Sunday')
//Today is Friday
DAYOFTHEMONTH
unit
Date utils
category
date/time
routines
declaration
function DayOfTheMonth(const AValue: TDateTime): Word;
description
Returns the day of the month from a given TDateTime value (from 1 to 31)
example
var
ThisDate : TDateTime;
DaysPassed : Word;
begin
ThisDate := Now; (* 08/15/2003 *)
DaysPassed := DayOfTheMonth(ThisDate)
// DaysPassed == 15
end;
DATETIMETOFILEDATE
declaration
function DateTimeToFileDate(DateTime: TDateTime): Integer;
description
Converts a TDateTime value to a system timestamp value.
unit
Sysutils
category
date/time
routines
example
var aFile : string;
aFileDateTime : TDateTime;
aFileOSDate : integer;
begin
aFile : = Application.ExeName;
aFileOSDate := FileAge(aFile);
FileSetDate(aFile, DateTimeToFileDate(aFileDateTime));
DAYOFTHEYEAR
declaration
function DayOfTheYear(const AValue: TDateTime): Word;
description
unit
Date utils
category
date/time
routines
Returns the the ordinal position of a TDateTime value's day within its year.
example
var
ThisDate : TDateTime;
DaysPassed : Word;
begin
ThisDate := Now; (* 08/14/2003 *)
DaysPassed := DayOfTheYear(ThisDate)
// DaysPassed == 226
end;
DATETIMETOFILEDATE
declaration
function DateTimeToFileDate(DateTime: TDateTime): Integer;
description
Converts a TDateTime value to a system timestamp value.
example
var aFile : string;
aFileDateTime : TDateTime;
aFileOSDate : integer;
begin
unit
Sysutils
category
date/time
routines
aFile : = Application.ExeName;
aFileOSDate := FileAge(aFile);
FileSetDate(aFile, DateTimeToFileDate(aFileDateTime));
DAYSPAN
unit
DateUtils
category
date/time
routines
declaration
function DaySpan(const ANow, AThen: TDateTime): double;
description
Gives the number of days (including fractional days) between two specified dates.
Contrary to DaysBetween, DaySpan function does not count only whole days. What this means
is that it will NOT return 0 as the result for difference between 05/01/2003 23:59:59 and
05/01/2003 23:59:58 - where the actual difference is one *whole* day minus 1 second.
example
dtNow := Now;
dtBirth:=EncodeDate(1973, 1, 29);
fracDaysFromBirth := DaySpan(dtNow, dtBirth);
DAYSBETWEEN
unit
DateUtils
category
date/time
routines
declaration
function DaysBetween(const ANow, AThen: TDateTime): Integer;
description
Gives the number of whole days between two specified dates.
Function counts only whole days. What this means is that it will return 0 as the result for
difference between 05/01/2003 23:59:59 and 05/01/2003 23:59:58 - where the actual difference
is one *whole* day minus 1 second.
example
var dtNow, dtBirth : TDateTime;
DaysFromBirth : integer;
dtNow := Now;
dtBirth := EncodeDate(1973, 1, 29);
DaysFromBirth := DaysBetween(dtNow, dtBirth);
DATEOF
unit
DateUtils
category
date/time
routines
declaration
function DateOf(Date: TDateTime) : TDateTime
description
Returns only the Date portion of the TDateTime value, by setting Time part to 0.
DateOf sets the time portion to 0, which means midnight.
example
var ThisMoment, ThisDay : TDateTime;
DECODEDATE
unit
Sysutils
category
date/time
routines
declaration
procedure DecodeDate(Date: TDateTime; var Year, Month, Day: Word);;
description
Separates Year, Month, and Day values from a TDateTime value.
If the given TDateTime value is less than or equal to zero, the year, month, and day return
parameters are all set to zero.
example
var Y, M, D: Word;
DecodeDate(Date, Y, M, D);
if Y = 2000 then
ShowMessage('You''re in a "wrong" century!);
DECODETIME
unit
Sysutils
category
date/time
routines
declaration
procedure DecodeTime(Date: TDateTime; var Hour, Min, Sec, MSec: Word);;
description
Separates Hour, Minute, Second, and MilliSecond values from a TDateTime value.
If the given TDateTime value is less than or equal to zero, than hour, minute, second, and
millisecond return parameters are all set to zero.
example
var Hour, Min, Sec, MSec : Word;
showmessage(
'The time is Second ' + IntToStr(Sec) +
' of Minute ' + IntToStr(Min) +
' of Hour ' + IntToStr(Hour));
ENCODEDATE
unit
Sysutils
category
date/time
routines
declaration
function EncodeDate(Year, Month, Day: Word): TDateTime
description
Creates a TDateTime value from Year, Month, and Day values.
The Year must be between 1 and 9999. Valid Month values are 1 through 12. Valid Day values
are 1 through 28, 29, 30, or 31, depending on the Month value.
If the function fails, EncodeDate raises an EConvertError exception.
example
var Y, M, D: Word;
dt: TDateTime;
y:=2001;
M:=2;
D:=18;
dt:=EncodeDate(Y,M,D);
ShowMessage('Borna will be
one year old on ' + DateToStr(dt))
ENCODETIME
unit
Sysutils
category
date/time
routines
declaration
function EncodeTime(Hour, Min, Sec, MSec: Word): TDateTime
description
Creates a TDateTime value from Hour, Min, Sec, and MSec. values.
Valid Hour values are 0 through 23. Valid Min and Sec values are 0 through 59. Valid MSec
values are 0 through 999. If the specified values are not within range, an EConvertError
exception is raised.
The resulting value is a number between 0 (inclusive) and 1 (not inclusive) that indicates the
fractional part of a day given by the specified time.
The value 0 corresponds to midnight, 0.5 corresponds to noon, 0.75 corresponds to 6:00 pm, and
so on.
example
H:=8;
M:=58;
S:=18;
MS:=45;
dt:=EncodeTime(H,M,S,MS);
FORMATDATETIME
unit
Sysutils
category
date/time
routines
declaration
function FormatDateTime(const Fmt: string; Value: TDateTime): string;
description
Formats a TDateTime value to a string.
FormatDateTime uses the format specified by the Fmt parameter. For the supported format
specifiers go see Delphi Help files.
example
var s: string;
d: TDateTime;
...
d:=Now; // today + current time
s:=FormatDateTime('dddd',d);
// s:=Wednesday
s:=FormatDateTime('"Today is " dddd " minute " nn',d)
// s:=Today is Wednesday minute 24
HOUROF
unit
Dateutils
category
date/time
routines
declaration
function HourOf(ADateTime: TDateTime) : Boolean;
description
Returns the hour of the day represented by a TDateTime value.
HourOf returns a value between 0 and 23.
example
if HowOf(Now) > 17 then
ShowMessage ('Work time is over, go home');
in real code
see also
INCDAY
unit
Dateutils
category
date/time
routines
declaration
function IncDay(ADate: TDateTime; Days: Integer = 1) : TDateTime;
description
Adds or substracts a given number of days from a date value.
If the Days parameter is negative the date returned is < ADate. The Time part of day specified by
the Date parameter is copied to the result.
example
var Date: TDateTime;
INCMONTH
declaration
function IncMonth(Date: TDateTime; Months: Integer) : TDateTime;
description
Adds or substracts a given number of months from a date value.
The Time part of day specified by the Date parameter is copied to the result.
example
var Date: TDateTime;
unit
Sysutils
category
date/time
routines
ISLEAPYEAR
unit
Sysutils
category
date/time
routines
declaration
function IsLeapYear(Year: Word): boolean;
description
Returns True if a year specified is a leap year.
Use DecodeDate to obtain the value of Year for IsLeapYear from a TDateTime value.
example
var Y, M, D: Word;
DecodeDate(Date, Y, M, D);
if IsLeapYear(Y) then
ISPM
unit
Dateutils
category
date/time
routines
declaration
function IsPM(ADateTime: TDateTime) : Boolean;
description
Returns true if the time portion of a TDateTime value occurs on or after 12:00 (noon) and
before 24:00 (midnight)
IsPM indicates whether the time portion of a specified TDateTime value occurs after noon.
example
if IsPM(Now) then
ShowMessage ('It's between 12:00 and 24:00');
NOW
unit
Sysutils
category
date/time
routines
declaration
type TDateTime = type Double;
function Now: TDateTime;
description
Returns the current system date and time.
The integral part of a TDateTime value is the number of days that have passed since 12/30/1899.
The fractional part of a TDateTime value is fraction of a 24 hour day that has elapsed.
To find the fractional number of days between two dates, simply subtract the two values.
Likewise, to increment a date and time value by a certain fractional number of days, simply add
the fractional number to the date and time value.
example
TIME
unit
Sysutils
category
date/time
routines
declaration
function Time: TDateTime;
description
Returns the current system time.
example
TIMETOSTR
unit
Sysutils
category
date/time
routines
declaration
function TimeToStr(Time: TDateTime): string;
description
Converts a TDateTime (time part) value to a string.
The conversion uses the format specified by the LongTimeFormat global variable.
example
TIMEOF
unit
DateUtils
category
date/time
routines
declaration
function TimeOf(Date: TDateTime) : TDateTime
description
Returns only the Time portion of the TDateTime value, by setting Date part to 0.
TimeOf sets the time portion to 0, which means 12/30/1899.
example
var ThisMoment, ThisTime : TDateTime;
WITHINPASTDAYS
unit
DateUtils
category
date/time
routines
declaration
function WithinPastDays(const SomeDate, AnotherDate: TDateTime; const ADays:
Integer): boolean;
description
Returns true if two dates are within a specified number of days of each other.
dtNow := Now;
dtBirth := EncodeDate(1973, 1, 29);
WITHINPASTYEARS
unit
DateUtils
category
date/time
routines
declaration
function WithinPastYears(const SomeDate, AnotherDate: TDateTime; const AYears:
Integer): boolean;
description
Returns true if two dates are within a specified number of years of each other.
Function counts only whole years - using the YearsBetween function - if SomeDate and
AnotherDate are 2 and a half years apart, calling WithinPastYears returns True and sets AYears
to 2.
example
var dtNow, dtBirth : TDateTime;
DaysFromBirth : integer;
dtNow := Now;
dtBirth := EncodeDate(1973, 1, 29);
YEARSBETWEEN
unit
DateUtils
category
date/time
routines
declaration
function YearsBetween(const SomeDate, AnotherDate: TDateTime): Integer;
description
Gives the number of whole years between two specified dates.
YearsBetween returns an approximation based on an assumption of 365.25 days per year.
example
var dtSome, dtAnother : TDateTime;
DaysFromBirth : integer;
Now lets query the table to get the salaries of all employees with their salary in descending order.
For that Ill write a query like this :
SELECT names
, salary
,row_number () OVER (ORDER BY salary DESC) as ROW_NUMBER
,rank () OVER (ORDER BY salary DESC) as RANK
,dense_rank () OVER (ORDER BY salary DESC) as DENSE_RANK
FROM salaries
>>Output
NAMES
F
E
A
B
D
C
SALARY
10000
6000
5000
5000
4000
3000
ROW_NUMBER
1
2
3
4
5
6
RANK
1
2
3
3
5
6
DENSE_RANK
1
2
3
3
4
5
Interesting Names in the result are employee A, B and D. Row_number assign different number
to them. Rank and Dense_rank both assign same rank to A and B. But interesting thing is what
RANK and DENSE_RANK assign to next row? Rank assign 5 to the next row, while dense_rank
assign 4.
The numbers returned by the DENSE_RANK function do not have gaps and always have
consecutive ranks. The RANK function does not always return consecutive integers. The
ORDER BY clause determines the sequence in which the rows are assigned their unique
ROW_NUMBER within a specified partition.
So question is which one to use?
Its all depends on your requirement and business rule you are following.
1. Row_number to be used only when you just want to have serial number on result set. It is not
as intelligent as RANK and DENSE_RANK.
2. Choice between RANK and DENSE_RANK depends on business rule you are following.
Rank leaves the gaps between number when it sees common values in 2 or more rows.
DENSE_RANK dont leave any gaps between ranks.
So while assigning the next rank to the row RANK will consider the total count of rows before
that row and DESNE_RANK will just give next rank according to the value.
So If you are selecting employees rank according to their salaries you should be using
DENSE_RANK and if you are ranking students according to there marks you should be using
RANK(Though it is not mandatory, depends on your requirement.)