SQL Interview Questions
SQL Interview Questions
SQL Interview Questions
1. Write a query to find the highest salary earned by an employee in each department and also the
number of employees who earn the highest salary?
SELECT DEPARTMENT_ID,
MAX(SALARY) HIGHEST_SALARY,
FROM EMPLOYEES
GROUP BY DEPARTMENT_ID;
2. Write a query to get the top 2 employees who are earning the highest salary in each department?
SELECT DEPARTMENT_ID,
EMPLOYEE_ID,
SALARY
FROM
SELECT DEPARTMENT_ID,
EMPLOYEE_ID,
SALARY,
FROM EMPLOYEES
) A
WHERE R <= 2;
3. Write a query to delete the duplicate records from employees table?
4. Write a query to find the employees who are earning more than the average salary in their
department?
SELECT EMPLOYEE_ID,
SALARY
It is a form of sub query, where the sub query uses the values from the outer query in its WHERE
clause. The sub query runs for each row processed in the outer query. Question 4 is an example for
a correlated sub query.
PL/SQL Interview Questions:
1. What is a cursor?
A cursor is a reference to the system memory when an SQL statement is executed. A cursor
contains the information about the select statement and the rows accessed by it.
Implicit Cursors: Implicit cursors are created by default when DML statements like INSERT,
UPDATE and DELETE are executed in PL/SQL objects.
Explicit Cursors: Explicit cursors must be created by you when executing the select statements.
%FOUND : Returns true if a DML or SELECT statement affects at least one row.
%NOTFOUND: Returns true if a DML or SELECT statement does not affect at least one row.
%ROWCOUNT: Returns the number of rows affected by the DML or SELECT statement.
%ISOPEN: Returns true if a cursor is in open state.
%BULK_ROWCOUNT: Similar to %ROWCOUNT, except it is used in bulk operations.
Public procedure: In a package, the signature of the procedure is specified in the package
specification. This procedure can be called outside of the package.
Private procedure: For private procedure, there won’t be any signature in the package specification.
So, these procedures can be called only inside the package and cannot be called outside of the
package.
INSERT INTO
employees_changes (employee_id,
change_date
VALUES (:OLD.photo_tag_id,
SYSDATE
);
END;
Normalization is the process of organizing the columns, tables of a database to minimize the
redundancy of data. Normalization involves in dividing large tables into smaller tables and defining
relationships between them. Normalization is used in OLTP systems.
First Normal Form: Duplicate columns from the same table needs to be eliminated. We have to
create separate tables for each group of related data and identify each row with a unique column or
set of columns (Primary Key)
Second Normal Form: First it should meet the requirement of first normal form. Removes the
subsets of data that apply to multiple rows of a table and place them in separate tables.
Relationships must be created between the new tables and their predecessors through the use of
foreign keys.
Third Normal Form: First it should meet the requirements of second normal form. Remove columns
that are not depending upon the primary key.
Fourth Normal Form: There should not be any multi-valued dependencies.
3. What is De-normalization?
A transaction is a logical unit of work performed against a database in which all steps must be
performed or none.
Atomic: Transactions must be atomic. Transactions must fail or succeed as a single unit.
Consistent: The database must always be in consistent state. There should not be any partial
transactions
Isolation: The changes made by a user should be visible only to that user until the transaction is
committed.
Durability: Once a transaction is committed, it should be permanent and cannot be undone.
MOLAP: The data is stored in multi-dimensional cube. The storage is not in the relational database,
but in proprietary formats.
ROLAP: ROLAP relies on manipulating the data stored in the RDBMS for slicing and dicing
functionality.
HOLAP: HOLAP combines the advantages of both MOLAP and ROLAP. For summary type
information, HOLAP leverages on cube technology for faster performance. For detail information,
HOLAP can drill through the cube.
One to one relationship is a simple reference between two tables. Consider Customer and Address
tables as an example. A customer can have only one address and an address references only one
customer.
One-to-many relationships can be implemented by splitting the data into two tables with a primary
key and foreign key relationship. Here the row in one table is referenced by one or more rows in the
other table. An example is the Employees and Departments table, where the row in the Departments
table is referenced by one or more rows in the Employees table.
Many-to-Many relationship is created between two tables by creating a junction table with the key
from both the tables forming the composite primary key of the junction table.
An example is Students, Subjects and Stud_Sub_junc tables. A student can opt for one or more
subjects in a year. Similarly a subject can be opted by one or more students. So a junction table is
created to implement the many-to-many relationship.
SELECT Columns | *
FROM Table_Name
[WHERE Search_Condition]
[GROUP BY Group_By_Expression]
[HAVING Search_Condition]
PRODUCT_ID INTEGER,
PRODUCT_NAME VARCHAR2(30)
);
COMMIT;
-----------------------
100 Nokia
200 IPhone
300 Samsung
400 LG
500 BlackBerry
600 Motorola
Solution:
First we will create a target table. The target table will have an additional column INSERT_DATE to
know when a product is loaded into the target table. The target
table structure is
PRODUCT_ID INTEGER,
PRODUCT_NAME VARCHAR2(30),
INSERT_DATE DATE
);
The next step is to pick 5 products randomly and then load into target table. While selecting check
whether the products are there in the
INSERT INTO TGT_PRODUCTS
SELECT PRODUCT_ID,
PRODUCT_NAME,
SYSDATE INSERT_DATE
FROM
SELECT PRODUCT_ID,
PRODUCT_NAME
FROM PRODUCTS S
SELECT 1
FROM TGT_PRODUCTS T
)A
The last step is to delete the products from the table which are loaded 30 days back.
CONTENT_ID INTEGER,
CONTENT_TYPE VARCHAR2(30)
);
COMMIT;
CONTENT_ID CONTENT_TYPE
-----------------------
1 MOVIE
2 MOVIE
3 AUDIO
4 AUDIO
5 MAGAZINE
6 MAGAZINE
Solution:
First we will create a lookup table where we mention the priorities for the content types. The lookup
table “Create Statement” and data is shown below.
CONTENT_TYPE VARCHAR2(30),
PRIORITY INTEGER,
LOAD_FLAG INTEGER
);
COMMIT;
---------------------------------
MOVIE 1 1
AUDIO 2 0
MAGAZINE 3 0
Here if LOAD_FLAG is 1, then it indicates which content type needs to be loaded into the target
table. Only one content type will have LOAD_FLAG as 1. The other content types will have
LOAD_FLAG as 0. The target table structure is same as the source table structure.
The second step is to truncate the target table before loading the data
The third step is to choose the appropriate content type from the lookup table to load the source data
into the target table.
SELECT CONTENT_ID,
CONTENT_TYPE
FROM CONTENTS
UPDATE CONTENTS_LKP
SET LOAD_FLAG = 0
WHERE LOAD_FLAG = 1;
UPDATE CONTENTS_LKP
SET LOAD_FLAG = 1
WHERE PRIORITY = (
FROM CONTENTS_LKP
Before starting with the interview questions, we will see the difference between the aggregate
functions and analytic functions with an example. I have used SALES TABLE as an example to
solve the interview questions. Please create the below sales table in your oracle database.
SALE_ID INTEGER,
PRODUCT_ID INTEGER,
YEAR INTEGER,
Quantity INTEGER,
PRICE INTEGER
);
COMMIT;
--------------------------------------
SELECT Year,
COUNT(1) CNT
FROM SALES
GROUP BY YEAR;
YEAR CNT
---------
2009 3
2010 3
2011 3
2008 3
2012 3
SELECT SALE_ID,
PRODUCT_ID,
Year,
QUANTITY,
PRICE,
FROM SALES;
------------------------------------------
The PARTITION BY clause is similar to GROUP By clause, it specifies the window of rows that the
analytic funciton should operate on.
I hope you got some basic idea about aggregate and analytic functions. Now lets start with solving
the Interview Questions on Oracle Analytic Functions.
1. Write a SQL query using the analytic function to find the total sales(QUANTITY) of each product?
Solution:
SUM analytic function can be used to find the total sales. The SQL query is
SELECT PRODUCT_ID,
QUANTITY,
FROM SALES;
-----------------------------
100 12 71
100 10 71
100 25 71
100 16 71
100 8 71
200 15 72
200 10 72
200 20 72
200 14 72
200 13 72
300 20 94
300 18 94
300 17 94
300 20 94
300 19 94
2. Write a SQL query to find the cumulative sum of sales(QUANTITY) of each product? Here first
sort the QUANTITY in ascendaing order for each product and then accumulate the QUANTITY.
Cumulative sum of QUANTITY for a product = QUANTITY of current row + sum of QUANTITIES all
previous rows in that product.
Solution:
We have to use the option "ROWS UNBOUNDED PRECEDING" in the SUM analytic function to get
the cumulative sum. The SQL query to get the ouput is
SELECT PRODUCT_ID,
QUANTITY,
FROM SALES;
-----------------------------
100 8 8
100 10 18
100 12 30
100 16 46
100 25 71
200 10 10
200 13 23
200 14 37
200 15 52
200 20 72
300 17 17
300 18 35
300 19 54
300 20 74
300 20 94
The ORDER BY clause is used to sort the data. Here the ROWS UNBOUNDED PRECEDING option
specifies that the SUM analytic function should operate on the current row and the pervious rows
processed.
3. Write a SQL query to find the sum of sales of current row and previous 2 rows in a product group?
Sort the data on sales and then find the sum.
Solution:
SELECT PRODUCT_ID,
QUANTITY,
SUM(QUANTITY) OVER(
PARTITION BY PRODUCT_ID
------------------------------
100 25 25
100 16 41
100 12 53
100 10 38
100 8 30
200 20 20
200 15 35
200 14 49
200 13 42
200 10 37
300 20 20
300 20 40
300 19 59
300 18 57
300 17 54
The ROWS BETWEEN clause specifies the range of rows to consider for calculating the SUM.
Solution:
QUANTITY,
FROM SALES;
--------------------------
100 8 12
100 10 12
100 12 12
100 16 12
100 25 12
200 10 14
200 13 14
200 14 14
200 15 14
200 20 14
300 17 19
300 18 19
300 19 19
300 20 19
300 20 19
5. Write a SQL query to find the minimum sales of a product without using the group by clause.
Solution:
SELECT PRODUCT_ID,
YEAR,
QUANTITY
FROM
SELECT PRODUCT_ID,
YEAR,
QUANTITY,
FROM SALES
) WHERE MIN_SALE_RANK = 1;
------------------------
100 2012 8
200 2010 10
300 2008 17
1. Write a query to find the products whose quantity sold in a year should be greater than the
average quantity sold across all the years?
Solution:
This can be solved with the help of correlated query. The SQL query for this is
SELECT P.PRODUCT_NAME,
S.YEAR,
S.QUANTITY
FROM PRODUCTS P,
SALES S
(SELECT AVG(QUANTITY)
FROM SALES S1
);
--------------------------
Nokia 2010 25
IPhone 2012 20
Samsung 2012 20
Samsung 2010 20
2. Write a query to compare the products sales of "IPhone" and "Samsung" in each year? The output
should look like as
---------------------------------------------------
2010 10 20 9000 7000
Solution:
By using self-join SQL query we can get the required result. The required SQL query is
SELECT S_I.YEAR,
S_I.QUANTITY IPHONE_QUANT,
S_S.QUANTITY SAM_QUANT,
S_I.PRICE IPHONE_PRICE,
S_S.PRICE SAM_PRICE
SALES S_I,
PRODUCTS P_S,
SALES S_S
Solution:
The ratio of a product is calculated as the total sales price in a particular year divide by the total
sales price across all years. Oracle provides RATIO_TO_REPORT analytical function for finding the
ratios. The SQL query is
SELECT P.PRODUCT_NAME,
S.YEAR,
RATIO_TO_REPORT(S.QUANTITY*S.PRICE)
FROM PRODUCTS P,
SALES S
-----------------------------
4. In the SALES table quantity of each product is stored in rows for every year. Now write a query to
transpose the quantity for each product and display it in columns? The output should look like as
------------------------------------------
IPhone 10 15 20
Samsung 20 18 20
Nokia 25 16 8
Solution:
Oracle 11g provides a pivot function to transpose the row data into column data. The SQL query for
this is
SELECT * FROM
SELECT P.PRODUCT_NAME,
S.QUANTITY,
S.YEAR
FROM PRODUCTS P,
SALES S
)A
If you are not running oracle 11g database, then use the below query for transposing the row data
into column data.
SELECT P.PRODUCT_NAME,
FROM PRODUCTS P,
SALES S
WHERE (P.PRODUCT_ID = S.PRODUCT_ID)
GROUP BY P.PRODUCT_NAME;
Solution:
To get this result we have to group by on year and the find the count. The SQL query for this
question is
SELECT YEAR,
COUNT(1) NUM_PRODUCTS
FROM SALES
GROUP BY YEAR;
YEAR NUM_PRODUCTS
------------------
2010 3
2011 3
2012 3
To solve these interview questions on SQL queries you have to create the products, sales tables in
your oracle database. The "Create Table", "Insert" statements are provided below.
PRODUCT_ID INTEGER,
PRODUCT_NAME VARCHAR2(30)
);
CREATE TABLE SALES
SALE_ID INTEGER,
PRODUCT_ID INTEGER,
YEAR INTEGER,
Quantity INTEGER,
PRICE INTEGER
);
COMMIT;
The products table contains the below data.
PRODUCT_ID PRODUCT_NAME
-----------------------
100 Nokia
200 IPhone
300 Samsung
--------------------------------------
I hope you have created the tables in your oracle database. Now try to solve the below SQL queries.
1. Write a SQL query to find the products which have continuous increase in sales every year?
Solution:
Here “Iphone” is the only product whose sales are increasing every year.
STEP1: First we will get the previous year sales for each product. The SQL query to do this is
SELECT P.PRODUCT_NAME,
S.YEAR,
S.QUANTITY,
LEAD(S.QUANTITY,1,0) OVER (
PARTITION BY P.PRODUCT_ID
) QUAN_PREV_YEAR
FROM PRODUCTS P,
SALES S
-----------------------------------------
Nokia 2012 8 16
Nokia 2011 16 25
Nokia 2010 25 0
IPhone 2012 20 15
IPhone 2011 15 10
IPhone 2010 10 0
Samsung 2012 20 18
Samsung 2011 18 20
Samsung 2010 20 0
Here the lead analytic function will get the quantity of a product in its previous year.
STEP2: We will find the difference between the quantities of a product with its previous year’s
quantity. If this difference is greater than or equal to zero for all the rows, then the product is a
constantly increasing in sales. The final query to get the required result is
SELECT PRODUCT_NAME
FROM
SELECT P.PRODUCT_NAME,
S.QUANTITY -
LEAD(S.QUANTITY,1,0) OVER (
PARTITION BY P.PRODUCT_ID
) QUAN_DIFF
FROM PRODUCTS P,
SALES S
)A
GROUP BY PRODUCT_NAME
------------
IPhone
2. Write a SQL query to find the products which does not have sales at all?
Solution:
“LG” is the only product which does not have sales at all. This can be achieved in three ways.
SELECT P.PRODUCT_NAME
FROM PRODUCTS P
SALES S
ON (P.PRODUCT_ID = S.PRODUCT_ID);
PRODUCT_NAME
------------
LG
SELECT P.PRODUCT_NAME
FROM PRODUCTS P
------------
LG
SELECT P.PRODUCT_NAME
FROM PRODUCTS P
PRODUCT_NAME
------------
LG
3. Write a SQL query to find the products whose sales decreased in 2012 compared to 2011?
Solution:
Here Nokia is the only product whose sales decreased in year 2012 when compared with the sales
in the year 2011. The SQL query to get the required output is
SELECT P.PRODUCT_NAME
FROM PRODUCTS P,
SALES S_2012,
SALES S_2011
PRODUCT_NAME
------------
Nokia
Solution:
Nokia is the top product sold in the year 2010. Similarly, Samsung in 2011 and IPhone, Samsung in
2012. The query for this is
SELECT PRODUCT_NAME,
YEAR
FROM
SELECT P.PRODUCT_NAME,
S.YEAR,
RANK() OVER (
PARTITION BY S.YEAR
) RNK
FROM PRODUCTS P,
SALES S
WHERE RNK = 1;
PRODUCT_NAME YEAR
--------------------
Nokia 2010
Samsung 2011
IPhone 2012
Samsung 2012
Solution:
This is a simple query. You just need to group by the data on PRODUCT_NAME and then find the
sum of sales.
SELECT P.PRODUCT_NAME,
FROM PRODUCTS P
SALES S
ON (P.PRODUCT_ID = S.PRODUCT_ID)
GROUP BY P.PRODUCT_NAME;
PRODUCT_NAME TOTAL_SALES
---------------------------
LG 0
IPhone 405000
Samsung 406000
Nokia 245000
3 M,N
Here the data in value column is a delimited by comma. Now write a query to split the delimited data
in the value column into multiple rows. The output should look like as
id value
1 A
1 B
1 C
2 P
2 Q
2 R
2 S
2 T
3 M
3 N
Solution:
SELECT t.id,
CASE WHEN a.l = 1
THEN substr(value, 1, instr(value,',',1,a.l)-1)
ELSE substr(value, instr(value,',',1,a.l-1)+1,
CASE WHEN instr(value,',',1,a.l)-instr(value,',',1,a.l-1)-1 > 0
THEN instr(value,',',1,a.l)-instr(value,',',1,a.l-1)-1
ELSE length(value)
END
)
END final_value
FROM t,
( SELECT level l FROM DUAL
CONNECT BY LEVEL <= (SELECT Max(length(value) - length(replace(value,',',''))+1) FROM
t)
)a
WHERE length(value) - length(replace(value,',',''))+1 >= a.l
order by t.id, a.l;
Now let see how to calculate the median in oracle with the employees table as example.
select empid,
dept_id,
salary,
percentile_disc(0.5) within group (order by salary desc)
over () median
from employees;
The output of the above query is
select empid,
dept_id,
salary,
percentile_disc(0.5) within group (order by salary desc)
over (partition by department_id) median
from employees;
The ouput of the above query is
Here in this table, column C1 is parent of column C2, column C2 is parent of column C3, column C3
is parent of column C4.
Q1. Write a query to load the target table with the below data. Here you need to generate sequence
numbers for each element and then you have to get the parent id. As the element "A" is at root, it
does not have any parent and its parent_id is NULL.
WITH t1 AS
(
SELECT VALUE PARENT,
LEV,
LEAD(value,1) OVER (PARTITION BY r ORDER BY lev) CHILD
FROM (SELECT c1,
c2,
c3,
c4,
ROWNUM r
FROM table_name
)
UNPIVOT (value FOR lev IN (c1 as 0,c2 as 1,c3 as 2,c4 as 3))
),
t2 AS
(
SELECT PARENT,
LEV,
ROWNUM SEQ
FROM
(SELECT DISTINCT PARENT,
LEV
FROM T1
ORDER BY LEV
)
),
T3 AS
(
SELECT DISTINCT PARENT,
CHILD
FROM T1
WHERE CHILD IS NOT NULL
UNION ALL
SELECT DISTINCT NULL,
PARENT
FROM T1
WHERE LEV=0
)
SELECT C.SEQ Id,
T3.CHILD ELEMENT,
C.LEV,
P.SEQ PARENT_ID
FROM T3
INNER JOIN
T2 C
ON (T3.CHILD = C.PARENT)
LEFT OUTER JOIN
T2 P
ON (T3.PARENT = P.PARENT)
ORDER BY C.SEQ;
1. Consider the following friends table as the source
Name, Friend_Name
-----------------
sam, ram
sam, vamsi
vamsi, ram
vamsi, jhon
ram, vijay
ram, anand
Here ram and vamsi are friends of sam; ram and jhon are friends of vamsi and so on. Now write a
query to find friends of friends of sam. For sam; ram,jhon,vijay and anand are friends of friends. The
output should look as
Name, Friend_of_Firend
----------------------
sam, ram
sam, jhon
sam, vijay
sam, anand
Solution:
SELECT f1.name,
f2.friend_name as friend_of_friend
friends f2
2. This is an extension to the problem 1. In the output, you can see ram is displayed as friends of
friends. This is because, ram is mutual friend of sam and vamsi. Now extend the above query to
exclude mutual friends. The outuput should look as
Name, Friend_of_Friend
----------------------
sam, jhon
sam, vijay
sam, anand
Solution:
SELECT f1.name,
f2.friend_name as friend_of_friend
friends f2
3. Write a query to get the top 5 products based on the quantity sold without using the row_number
analytical function? The source data looks as
-----------------------------
A, 200, 2009
B, 155, 2009
C, 455, 2009
D, 620, 2009
E, 135, 2009
F, 390, 2009
G, 999, 2010
H, 810, 2010
I, 910, 2010
J, 109, 2010
L, 260, 2010
M, 580, 2010
Solution:
SELECT products,
quantity_sold,
year
FROM
SELECT products,
quantity_sold,
year,
rownum r
from t
)A
WHERE r <= 5;
4. This is an extension to the problem 3. Write a query to produce the same output using
row_number analytical function?
Solution:
SELECT products,
quantity_sold,
year
FROM
SELECT products,
quantity_sold,
year,
row_number() OVER(
from t
)A
WHERE r <= 5;
5. This is an extension to the problem 3. write a query to get the top 5 products in each year based
on the quantity sold?
Solution:
SELECT products,
quantity_sold,
year
FROM
SELECT products,
quantity_sold,
year,
row_number() OVER(
PARTITION BY year
from t
)A
WHERE r <= 5;
Solution:
2. Write a query to display only friday dates from Jan, 2000 to till now?
Solution:
SELECT C_DATE,
TO_CHAR(C_DATE,'DY')
FROM
FROM DUAL
3. Write a query to duplicate each row based on the value in the repeat column? The input table data
looks like as below
Products, Repeat
----------------
A, 3
B, 5
C, 2
Now in the output data, the product A should be repeated 3 times, B should be repeated 5 times and
C should be repeated 2 times. The output will look like as below
Products, Repeat
----------------
A, 3
A, 3
A, 3
B, 5
B, 5
B, 5
B, 5
B, 5
C, 2
C, 2
Solution:
SELECT PRODUCTS,
REPEAT
FROM T,
) A
ORDER BY T.PRODUCTS;
4. Write a query to display each letter of the word "SMILE" in a separate row?
Solution:
SELECT SUBSTR('SMILE',LEVEL,1) A
FROM DUAL
5. Convert the string "SMILE" to Ascii values? The output should look like as 83,77,73,76,69. Where
83 is the ascii value of S and so on.
The ASCII function will give ascii value for only one character. If you pass a string to the ascii
function, it will give the ascii value of first letter in the string. Here i am providing two solutions to get
the ascii values of string.
Solution1:
SELECT SUBSTR(DUMP('SMILE'),15)
FROM DUAL;
Solution2:
SELECT WM_CONCAT(A)
FROM
SELECT ASCII(SUBSTR('SMILE',LEVEL,1)) A
FROM DUAL
);