Showing posts with label learning. Show all posts
Showing posts with label learning. Show all posts

Thursday, 1 February 2018

SQL Server Ranking Functions

There are four ranking functions included with SQL Server (starting with SQL Server 2005). Those functions; ROW_NUMBER, RANK, DENSE_RANK, and NTILE; can be used to rank the rows of your result set over a partition. This article will present those functions and examples of their use.

Ranking Functions


Ranking functions are a subset of the built in functions in SQL Server. They are used to provide a rank of one kind or another to a set of rows in a partition. The partition can be the full result set, if there is no partition. Otherwise, the partitioning of the result set is defined using the partition clause of the OVER clause. The order of the ranking within the partition is defined by the order clause of OVER. Order is required even though partition is optional. The OVER clause syntax can be found here.
In the following, each ranking function will be discussed and an example shown. The examples for this article use tables in the AdventureWorks2008R2 database.

ROW_NUMBER

The ROW_NUMBER ranking function is the simplest of the ranking functions. Its purpose in life is to provide consecutive numbering of the rows in the result set by the order selected in the OVER clause for each partition specified in the OVER clause.
If no partition is specified, ROW_NUMBER will provide a consecutive numbering of the rows based on the order clause. If a partition is provided, the numbering is consecutive within the partition and begins again at 1 when the partition changes.

Example
Here we have a query to find the top 10 products that sold in 2008. ROW_NUMBER is used here to designate the ordering from highest qty ordered to lowest. The order clause in the OVER clause tells it to rank the rows by the sum of all the order quantities for that product.

SELECT TOP(10) ProductID, SUM(OrderQty) AS ProductOrderCount, ROW_NUMBER() OVER (ORDER BY SUM(OrderQty) DESC) AS Row
FROM Sales.SalesOrderDetail sod
JOIN Sales.SalesOrderHeader soh
ON sod.SalesOrderID = soh.SalesOrderID
WHERE OrderDate BETWEEN '1/1/2008' AND '12/31/2008'
GROUP BY ProductID
ORDER BY Row

Results
ProductID ProductOrderCount Row
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
870 3519 1
712 2376 2
711 2133 3
708 2064 4
707 2053 5
873 2051 6
864 1834 7
921 1782 8
884 1654 9
877 1475 10
(10 row(s) affected)

To give you an example of what ROW_NUMBER would do if there was a partition involved; consider this example where TerritoryID was added to the result set. In this case, we have to retrieve the top 20 so you can see the row number start over when the partition changes. The partition is by ProductID and the order by clause of the select statement changed to order the result set by ProductID and then Row. The GROUP BY clause also changed to include Territory ID. So, we are getting a summation of the OrderQty for each product in each territory. That result set then has the ROW_NUMBER applied to each product in the order of most quantity ordered in each territory. After the ranking is applied, the result set is ordered by ProductID and Row and the top 20 rows are returned.

SELECT TOP(20) ProductID, soh.TerritoryID,
SUM(OrderQty) AS ProductOrderCount,
ROW_NUMBER() OVER ( PARTITION BY sod.ProductID ORDER BY SUM(OrderQty) DESC) AS Row
FROM Sales.SalesOrderDetail sod
JOIN Sales.SalesOrderHeader soh
ON sod.SalesOrderID = soh.SalesOrderID
JOIN Sales.SalesTerritory st
ON soh.TerritoryID = st.TerritoryID
WHERE OrderDate BETWEEN '1/1/2008' AND '12/31/2008'
GROUP BY ProductID, soh.TerritoryID
ORDER BY ProductID, Row

Results

ProductID TerritoryID ProductOrderCount Row
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
707 4 355 1
707 6 324 2
707 9 283 3
707 10 249 4
707 1 243 5
707 7 217 6
707 8 211 7
707 3 66 8
707 5 59 9
707 2 46 10
708 4 374 1
708 6 332 2
708 9 288 3
708 1 236 4
708 10 223 5
708 8 208 6
708 7 182 7
708 2 92 8
708 3 65 9
708 5 64 10
(20 row(s) affected)

RANK

The function RANK provides consecutive numbering except in the case of a tie. This function is used when you want all tied rows to have the same ranking, but the next row after the tied rows to have the rank it would have been assigned if there had been no tie. In other words, the numbers assigned by RANK are not necessarily consecutive.

Example
Let's take the first example from above (products ordered in 2008) and apply RANK instead of ROW_NUMBER. To get a result worth looking at, however, we have to limit the products to those having a ProductOrderCount between 400 and 500. You can see in the results that two of the rows had ProductOrderCount equal to 488. Therefore, with RANK, they both received the same ranking, in this case 2, and the next number is skipped. In this example the 2nd and 3rd items have a ranking of 2 and the fourth item has a ranking of 4.
- Advertisement -
SELECT ProductID, SUM(OrderQty) AS ProductOrderCount,
RANK() OVER (ORDER BY SUM(OrderQty) DESC) AS Ranking
FROM Sales.SalesOrderDetail sod
JOIN Sales.SalesOrderHeader soh
ON sod.SalesOrderID = soh.SalesOrderID
WHERE OrderDate BETWEEN '1/1/2008' AND '12/31/2008'
GROUP BY ProductID
HAVING SUM(OrderQty) BETWEEN 400 AND 500
ORDER BY Ranking

Results
ProductID ProductOrderCount Ranking
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
928 499 1
954 488 2
966 488 2
974 471 4
972 464 5
933 463 6
801 453 7
977 447 8
797 442 9
860 409 10
(10 row(s) affected)

DENSE_RANK

As with RANK, DENSE_RANK will divvy out the same rank to tying rows. In contrast, however, DENSE_RANK will not skip any numbers. So if the first two rows tie, they will both receive 1 for the rank. The third row will receive 2 for its rank, unlike with RANK where it would have been assigned 3.

Example
To display the difference, here is the same example query as above. Changing RANK to DENSE_RANK renders the same results with one distinction. Rows 2 and 3 are still tied and therefore receive the same rank of 2; however the fourth row now receives the rank of 3 instead of 4.

SELECT ProductID, SUM(OrderQty) AS ProductOrderCount,
DENSE_RANK() OVER (ORDER BY SUM(OrderQty) DESC) AS Ranking
FROM Sales.SalesOrderDetail sod
JOIN Sales.SalesOrderHeader soh
ON sod.SalesOrderID = soh.SalesOrderID
WHERE OrderDate BETWEEN '1/1/2008' AND '12/31/2008'
GROUP BY ProductID
HAVING SUM(OrderQty) BETWEEN 400 AND 500
ORDER BY Ranking

Results
ProductID ProductOrderCount Ranking
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
928 499 1
954 488 2
966 488 2
974 471 3
972 464 4
933 463 5
801 453 6
977 447 7
797 442 8
860 409 9
(10 row(s) affected)

NTILE

When you want to group rows equally across a partition, the NTILE function is the one you want. For this ranking function you need to provide it the number of groups into which you want the rows equally divided. Should the row count not be equally divisible by the number of groups, there will be a group or groups with one more row than the rest. Those groups with the extra row will come first in the ranking.
For instance, if you had 26 rows and desired 5 groups, the first group would contain 6 rows and the remaining 4 groups would contain 5 rows each.

Example
Again using the same query to identify products with a total quantity ordered in 2008 between 400 and 500, this time we are grouping them into 4 groups using NTILE and supplying the group count in the function call. Since this query returns 10 rows and 10 is not equally divided into 4 groups, you can see in the results that the first two groups contain 3 rows each and the last two groups contain just two rows each.

SELECT ProductID, SUM(OrderQty) AS ProductOrderCount,
NTILE(4) OVER (ORDER BY SUM(OrderQty) DESC) AS Ranking
FROM Sales.SalesOrderDetail sod
JOIN Sales.SalesOrderHeader soh
ON sod.SalesOrderID = soh.SalesOrderID
WHERE OrderDate BETWEEN '1/1/2008' AND '12/31/2008'
GROUP BY ProductID
HAVING SUM(OrderQty) BETWEEN 400 AND 500
ORDER BY Ranking

Results
ProductID ProductOrderCount Ranking
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
928 499 1
954 488 1
966 488 1
974 471 2
972 464 2
933 463 2
801 453 3
977 447 3
797 442 4
860 409 4
(10 row(s) affected)

Conclusion

SQL Server includes a subset of built-in functions called ranking functions. These ranking functions provide various means of ranking and grouping result sets by utilizing the OVER clause to identify the partitioning of the result set and the order for the ranking.



Friday, 25 November 2016

Replace String in all files in Eclipse

Hello everyone,

One of the simple things we often come across while developing projects how to replace the string across all files in the Eclipse project.


Below are the basic steps to Follow:

  • "Search"->"File"
  • Enter text, file pattern and projects
  • "Replace"
  • Enter new text
















This is how we should to do while replacing string across all files in Eclipse.

Thanks.

Wednesday, 24 August 2016

Understanding JOINs in MySQL and Other Relational Databases

“JOIN” is an SQL keyword used to query data from two or more related tables. Unfortunately, the concept is regularly explained using abstract terms or differs between database systems. It often confuses me. Developers cope with enough confusion, so this is my attempt to explain JOINs briefly and succinctly to myself and anyone who’s interested.

Related Tables

MySQL, PostgreSQL, Firebird, SQLite, SQL Server and Oracle are relational database systems. A well-designed database will provide a number of tables containing related data. A very simple example would be users (students) and course enrollments:

‘user’ table:

MySQL table creation code:
CREATE TABLE `user` (
                `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
                `name` varchar(30) NOT NULL,
                `course` smallint(5) unsigned DEFAULT NULL,
                PRIMARY KEY (`id`)
) ENGINE=InnoDB;

 

id
name
course
1
Alice
1
2
Bob
1
3
Caroline
2
4
David
5
5
Emma
(NULL)

The course number relates to a subject being taken in a course table…

‘course’ table:

MySQL table creation code:

CREATE TABLE `course` (
                `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
                `name` varchar(50) NOT NULL,
                PRIMARY KEY (`id`)
) ENGINE=InnoDB;
id
name
1
HTML5
2
CSS3
3
JavaScript
4
PHP
5
MySQL
Since we’re using InnoDB tables and know that user.course and course.id are related, we can specify a foreign key relationship:
ALTER TABLE `user`
ADD CONSTRAINT `FK_course`
FOREIGN KEY (`course`) REFERENCES `course` (`id`)
ON UPDATE CASCADE;
In essence, MySQL will automatically:
·         re-number the associated entries in the user.course column if the course.id changes
·         reject any attempt to delete a course where users are enrolled.
Important: This is terrible database design!
This database is not efficient. It’s fine for this example, but a student can only be enrolled on zero or one course. A real system would need to overcome this restriction — probably using an intermediate ‘enrollment’ table which mapped any number of students to any number of courses.
JOINs allow us to query this data in a number of ways.

INNER JOIN (or just JOIN)

The most frequently used clause is INNER JOIN. This produces a set of records which match in both the user and course tables, i.e. all users who are enrolled on a course:
SELECT user.name, course.name
FROM `user`
INNER JOIN `course` on user.course = course.id;
Result:
user.name
course.name
Alice
HTML5
Bob
HTML5
Carline
CSS3
David
MySQL

LEFT JOIN

What if we require a list of all students and their courses even if they’re not enrolled on one? A LEFT JOIN produces a set of records which matches every entry in the left table (user) regardless of any matching entry in the right table (course):
SELECT user.name, course.name
FROM `user`
LEFT JOIN `course` on user.course = course.id;
Result:
user.name
course.name
Alice
HTML5
Bob
HTML5
Carline
CSS3
David
MySQL
Emma
(NULL)

 

RIGHT JOIN

Perhaps we require a list all courses and students even if no one has been enrolled? A RIGHT JOIN produces a set of records which matches every entry in the right table (course) regardless of any matching entry in the left table (user):
SELECT user.name, course.name
FROM `user`
RIGHT JOIN `course` on user.course = course.id;

Result:
user.name
course.name
Alice
HTML5
Bob
HTML5
Carline
CSS3
(NULL)
JavaScript
(NULL)
PHP
David
MySQL
RIGHT JOINs are rarely used since you can express the same result using a LEFT JOIN. This can be more efficient and quicker for the database to parse:
SELECT user.name, course.name
FROM `course`
LEFT JOIN `user` on user.course = course.id;
We could, for example, count the number of students enrolled on each course:
SELECT course.name, COUNT(user.name)
FROM `course`
LEFT JOIN `user` ON user.course = course.id
GROUP BY course.id;
Result:
course.name
count()
HTML5
2
CSS3
1
JavaScript
0
PHP
0
MySQL
1

OUTER JOIN (or FULL OUTER JOIN)

Our last option is the OUTER JOIN which returns all records in both tables regardless of any match. Where no match exists, the missing side will contain NULL.
OUTER JOIN is less useful than INNER, LEFT or RIGHT and it’s not implemented in MySQL. However, you can work around this restriction using the UNION of a LEFT and RIGHT JOIN, e.g.
SELECT user.name, course.name
FROM `user`
LEFT JOIN `course` on user.course = course.id
UNION
SELECT user.name, course.name
FROM `user`
RIGHT JOIN `course` on user.course = course.id;


Result:
user.name
course.name
Alice
HTML5
Bob
HTML5
Carline
CSS3
David
MySQL
Emma
(NULL)
(NULL)
JavaScript
(NULL)
PHP
I hope that gives you a better understanding of JOINs and helps you write more efficient SQL queries.