Friday, October 21, 2016

Tricky Query Interview Questions

Create following tables:

CREATE TABLE PRODUCTS
(
PRODUCT_ID INTEGER,
PRODUCT_NAME VARCHAR2(30)
);

CREATE TABLE SALES
(
SALE_ID INTEGER,
PRODUCT_ID INTEGER,
YEAR INTEGER,
Quantity INTEGER,
PRICE INTEGER
);

INSERT INTO PRODUCTS VALUES ( 100, 'Nokia');
INSERT INTO PRODUCTS VALUES ( 200, 'IPhone');
INSERT INTO PRODUCTS VALUES ( 300, 'Samsung');
INSERT INTO PRODUCTS VALUES ( 400, 'LG');

INSERT INTO SALES VALUES ( 1, 100, 2010, 25, 5000);
INSERT INTO SALES VALUES ( 2, 100, 2011, 16, 5000);
INSERT INTO SALES VALUES ( 3, 100, 2012, 8, 5000);
INSERT INTO SALES VALUES ( 4, 200, 2010, 10, 9000);
INSERT INTO SALES VALUES ( 5, 200, 2011, 15, 9000);
INSERT INTO SALES VALUES ( 6, 200, 2012, 20, 9000);
INSERT INTO SALES VALUES ( 7, 300, 2010, 20, 7000);
INSERT INTO SALES VALUES ( 8, 300, 2011, 18, 7000);
INSERT INTO SALES VALUES ( 9, 300, 2012, 20, 7000);
COMMIT;


SELECT * FROM PRODUCTS;

PRODUCT_ID PRODUCT_NAME
-----------------------
100 Nokia
200 IPhone
300 Samsung


SELECT * FROM SALES;

SALE_ID PRODUCT_ID YEAR QUANTITY PRICE
--------------------------------------
1 100 2010 25 5000
2 100 2011 16 5000
3 100 2012 8 5000
4 200 2010 10 9000
5 200 2011 15 9000
6 200 2012 20 9000
7 300 2010 20 7000
8 300 2011 18 7000
9 300 2012 20 7000





1. Write a SQL query to find the products which have continuous increase in sales every year?

SELECT PRODUCT_NAME
FROM
(
SELECT P.PRODUCT_NAME,
S.QUANTITY -
LEAD(S.QUANTITY,1,0) OVER (
PARTITION BY P.PRODUCT_ID
ORDER BY S.YEAR DESC
) QUAN_DIFF
FROM PRODUCTS P,
SALES S
WHERE P.PRODUCT_ID = S.PRODUCT_ID
)A
GROUP BY PRODUCT_NAME
HAVING MIN(QUAN_DIFF) >= 0;

2. Write a SQL query to find the products whose sales decreased in 2012 compared to 2011?

SELECT P.PRODUCT_NAME
FROM PRODUCTS P,
SALES S_2012,
SALES S_2011
WHERE P.PRODUCT_ID = S_2012.PRODUCT_ID
AND S_2012.YEAR = 2012
AND S_2011.YEAR = 2011
AND S_2012.PRODUCT_ID = S_2011.PRODUCT_ID
AND S_2012.QUANTITY < S_2011.QUANTITY;

3. Write a query to select the top product sold in each year?

SELECT PRODUCT_NAME,
YEAR
FROM
(
SELECT P.PRODUCT_NAME,
S.YEAR,
RANK() OVER (
PARTITION BY S.YEAR
ORDER BY S.QUANTITY DESC
) RNK
FROM PRODUCTS P,
SALES S
WHERE P.PRODUCT_ID = S.PRODUCT_ID
) A
WHERE RNK = 1;

4. Write a query to find the products whose quantity sold in a year should be greater than the average quantity of the product sold across all the years?

SELECT P.PRODUCT_NAME,
S.YEAR,
S.QUANTITY
FROM PRODUCTS P,
SALES S
WHERE P.PRODUCT_ID = S.PRODUCT_ID
AND S.QUANTITY >
(SELECT AVG(QUANTITY)
FROM SALES S1
WHERE S1.PRODUCT_ID = S.PRODUCT_ID
);

5. Write a query to compare the products sales of "IPhone" and "Samsung" in each year? The output should look like as

YEAR | IPHONE_QUANT | SAM_QUANT  | IPHONE_PRICE | SAM_PRICE
-----------------------------------------------------------------------------------------------
2010     10                             20                      9000                         7000
2011     15                             18                      9000                         7000
2012     20                            20                       9000                         7000


Using self join:

SELECT S_I.YEAR,
S_I.QUANTITY IPHONE_QUANT,
S_S.QUANTITY SAM_QUANT,
S_I.PRICE IPHONE_PRICE,
S_S.PRICE SAM_PRICE
FROM PRODUCTS P_I,
SALES S_I,
PRODUCTS P_S,
SALES S_S
WHERE P_I.PRODUCT_ID = S_I.PRODUCT_ID
AND P_S.PRODUCT_ID = S_S.PRODUCT_ID
AND P_I.PRODUCT_NAME = 'IPhone'
AND P_S.PRODUCT_NAME = 'Samsung'
AND S_I.YEAR = S_S.YEAR

Using DECODE:

select year,max(decode(product_name,'IPhone',quantity)) Iphone_QUAN,
max(decode(product_name,'Samsung',quantity)) SAM_QUAN,
max(decode(product_name,'IPhone',price)) Iphone_PRICE,
max(decode(product_name,'Samsung',price)) SAM_PRICE
from sales s, products p where s.product_id=p.product_id
group by year


Using PIVOT (from oracle 11g onwards):

select * from (
select year,quantity,price,product_name
from sales s, products p where s.product_id=p.product_id
)
pivot (max(quantity) AS QUAN,max(price) AS PRICE FOR product_name in ('IPhone','Samsung'))


6. Write a query to transpose the quantity for each product and display it in columns? The output should look like as

PRODUCT_NAME  | QUAN_2010  |  QUAN_2011  |  QUAN_2012
---------------------------------------------------------------------------------
IPhone                       10                      15                      20
Samsung                   20                      18                      20
Nokia                         25                      16                       8

Using DECODE:

SELECT P.PRODUCT_NAME,
MAX(DECODE(S.YEAR,2010, S.QUANTITY)) QUAN_2010,
MAX(DECODE(S.YEAR,2011, S.QUANTITY)) QUAN_2011,
MAX(DECODE(S.YEAR,2012, S.QUANTITY)) QUAN_2012
FROM PRODUCTS P,
SALES S
WHERE (P.PRODUCT_ID = S.PRODUCT_ID)
GROUP BY P.PRODUCT_NAME;


Using PIVOT (from oracle 11g onwards):

SELECT * FROM
(
SELECT P.PRODUCT_NAME,
S.QUANTITY,
S.YEAR
FROM PRODUCTS P,
SALES S
WHERE (P.PRODUCT_ID = S.PRODUCT_ID)
)A
PIVOT ( MAX(QUANTITY) AS QUAN FOR (YEAR) IN (2010,2011,2012));


7. Write a query to generate sequence numbers from 1 to the specified number N?

SELECT LEVEL FROM DUAL CONNECT BY LEVEL<=&N;

8. Write a query to display only friday dates from Jan, 2000 to till now?

select d_date,to_char(d_date,'DY') as Day from (
select to_date('01-JAN-2000','DD-MON-YYYY')+Level-1 as d_date from dual
connect by level < = (SYSDATE - to_date('01-JAN-2000','DD-MON-YYYY')+1)
) where to_char(d_date,'DY') = 'FRI'

9. 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

SELECT PRODUCTS,
REPEAT
FROM T,
( SELECT LEVEL L FROM DUAL
CONNECT BY LEVEL <= (SELECT MAX(REPEAT) FROM T)
) A
WHERE T.REPEAT >= A.L
ORDER BY T.PRODUCTS;

10. Write a query to display each letter of the word "IPHONE" in a separate row?

I
P
H
O
N
E


SELECT SUBSTR('IPHONE',LEVEL,1) A
FROM DUAL
CONNECT BY LEVEL <=LENGTH('IPHONE');


11. Convert the string "IPHONE" to Ascii values? The output should look like as 73,80,72,79,78,69. Where 73 is the ascii value of I and so on.

Using WM_CONCAT() which is not official & documented:

select wm_concat(A) from(
SELECT ascii(SUBSTR('IPHONE',LEVEL,1)) A
FROM DUAL
CONNECT BY LEVEL <=LENGTH('IPHONE'))

Using DUMP:

SELECT SUBSTR(DUMP('IPHONE'),15)
FROM DUAL;

Using LISTAGG():

select LISTAGG(A,',') within group (order by B) from(
SELECT ascii(SUBSTR('IPHONE',LEVEL,1)) A ,LEVEL B
FROM DUAL
CONNECT BY LEVEL <=LENGTH('IPHONE'))


12. I have a table which has only one column and one row. The numeric column contains a 6 digit number. My requirements is to find out the product of the 3 consecutive digits and display them in separate rows.

Sample input data output are shown below:
Source Table Name: Digits

Value
-----------
123456

Output:

product
------------
6
24
60
120

select (substr(Value,level,1)*substr(Value,level+1,1)*substr(Value,level+2,1)) as product from Digits
connect by level <= length(Value)-2

13. Write a query to print star triangle.

select rpad( '* ', level*2, '* ' ) from dual connect by level <= 3


14. How to create test data in bulk ?
Refer following queries :

Insert into test(id, name) select level, dbms_random.string('ss',4) from dual connect by level<=1000

SELECT LEVEL empl_id,
MOD (ROWNUM, 50000) dept_id,
TRUNC (DBMS_RANDOM.VALUE (1000, 500000), 2) salary,
DECODE (ROUND (DBMS_RANDOM.VALUE (1, 2)), 1, 'M', 2, 'F') gender,
TO_DATE ( ROUND (DBMS_RANDOM.VALUE (1, 28))
|| '-'
|| ROUND (DBMS_RANDOM.VALUE (1, 12))
|| '-'
|| ROUND (DBMS_RANDOM.VALUE (1900, 2010)),
'DD-MM-YYYY'
) dob,
DBMS_RANDOM.STRING ('x', DBMS_RANDOM.VALUE (20, 50)) address
FROM DUAL
CONNECT BY LEVEL < 10000;


15. One of the columns in the table is of varchar data type. It contains both strings, numbers and mix of char and numeric values. My problem is to print only the values that contains only numeric digits.

Sample data in the columne is shown below:
--------------
Ora123
786
database
92db

The output should contain the following values:
786

select * from test where regexp_like(a,'^[0-9]+$')

select * from test where regexp_like(a,'^[0-9]*$')

select * from test where regexp_like(a,'^[[:digit:]]+$')

select * from test where upper(a)=lower(a) --will fail for special characters

select * from test where LTRIM (a, '0123456789') IS NULL


select * from test where translate(a,'0123456789',' ') IS NULL

Friday, October 7, 2016

Important Queries -- Interview Questions

Write a query to fetch system date from oracle db.
select sysdate from dual

Query to view installed Oracle version information.
select banner from v$version;

How to view NLS parameters ?
select * from nls_database_parameters

Query to find open cursors.

1. SELECT user_Name, COUNT(SQL_Text), SQL_Text FROM v$open_cursor GROUP BY SQL_Text,user_Name ORDER BY user_Name ASC , COUNT(SQL_Text) DESC, SQL_Text;

2. SELECT COUNT(USER_NAME), USER_NAME FROM v$open_cursor GROUP BY USER_NAME;


How to view all indexes on any table ?

SELECT X.TABLE_NAME, X.COLUMN_NAME, X.DATA_TYPE, X.INDEX_TYPE, X.INDEX_NAME, Y.COLUMN_EXPRESSION
FROM
(SELECT A.TABLE_NAME, A.COLUMN_NAME, C.DATA_TYPE, B.INDEX_TYPE, A.INDEX_NAME
FROM User_Ind_Columns A, User_Indexes B, USER_TAB_COLUMNS C
WHERE A.Index_Name = B.Index_Name
AND A.TABLE_NAME = C.TABLE_NAME(+)
AND A.COLUMN_NAME = C.COLUMN_NAME(+)
AND A.TABLE_NAME LIKE 'TABLE_Name') X, USER_IND_EXPRESSIONS Y
WHERE X.INDEX_NAME = Y.INDEX_NAME(+)


What value one gets for "Select * from dual" ?

DUMMY
------
X

How can you take an Input from a User of the Database?

You can take it using the Input Operator. This is as follow:
SELECT * FROM table WHERE column = &input;

How will you copy the structure of a table without copying the data ?

CREATE TABLE DestTable AS SELECT * FROM SourceTable WHERE 1=2;

What is the difference between these 2 queries :
  • Select count(*) from table
  • Select count(1) from table

Nothing, they are the same, incur the same amount of work -- do the same thing, take the same amount of resources.


How do I eliminate the duplicate rows ?

delete from table_name where rowid not in (select max(rowid) from table group by
duplicate_values_field_name);

Write a query to display "Not Applicable" or "NA" instead of blank space if commission is null for a employee.

SQL> select nvl(to_char(comm),'NA') from emp;
Output :
NVL(TO_CHAR(COMM),'NA')
-----------------------
NA
300
500
NA
1400
NA
NA

Find out nth highest salary from emp table.

SELECT DISTINCT (a.sal) FROM EMP A WHERE &N = (SELECT COUNT (DISTINCT (b.sal)) FROM EMP B
WHERE a.sal<=b.sal);


Display the number value in Words.

SQL> select sal, (to_char(to_date(sal,'j'), 'jsp'))
from emp;

SAL (TO_CHAR(TO_DATE(SAL,'J'),'JSP'))
--------- -----------------------------------------------------
800 eight hundred
1600 one thousand six hundred
1250 one thousand two hundred fifty


Display Odd number of records.

select * from emp where (rowid,1) in (select rowid, mod(rownum,2) from emp);

Display Even number of records.

select * from emp where (rowid,0) in (select rowid, mod(rownum,2) from emp)

Monday, September 19, 2016

EXCEPTIONS and PRAGMA Interview Questions

What is an Exception ? What are types of Exception ?
A warning or error condition in a PL/SQL program is called an exception. Types of exception are :
  • Internally defined : Oracle Database Error Messages that does not have a name. The runtime system raises them implicitly.
  • Predefined : internally defined exceptions that have predefined names, which PL/SQL declares globally in the package STANDARD. The runtime system raises them implicitly. E.g.: Zero_Divide, No_Data_Found, DUP_VAL_ON_INDEX, TOO_MANY_ROWS etc.
  • User-Defined : declare your own exceptions in the declarative part of any PL/SQL anonymous block, subprogram, or package.
Syntax is : exception_name EXCEPTION;
E.g.: DECLARE
out_of_stock EXCEPTION;
number_on_hand NUMBER(4);
BEGIN
...
IF number_on_hand < 1 THEN
RAISE out_of_stock;
END IF;
EXCEPTION
WHEN out_of_stock THEN
-- handle the error
END;

What is RAISE_APPLICATION_ERROR ?
The procedure RAISE_APPLICATION_ERROR lets you issue user-defined ORA- error messages from stored subprograms. That way, you can report errors to your application and avoid returning unhandled exceptions.

To call RAISE_APPLICATION_ERROR, use the syntax :

raise_application_error(error_number, message[, {TRUE | FALSE}]);

where error_number is a negative integer in the range -20000 .. -20999 and message is a character string up to 2048 bytes long. If the optional third parameter is TRUE, the error is placed on the stack of previous errors. If the parameter is FALSE (the default), the error replaces all previous errors. RAISE_APPLICATION_ERROR is part of package DBMS_STANDARD, and as with package STANDARD, you do not need to qualify references to it.

In the following example, you call raise_application_error if an employee's salary is missing:

CREATE PROCEDURE raise_salary (emp_id NUMBER, amount NUMBER) AS
curr_sal NUMBER;
BEGIN
SELECT sal INTO curr_sal FROM emp WHERE empno = emp_id;
IF curr_sal IS NULL THEN
/* Issue user-defined error message. */
raise_application_error(-20101, 'Salary is missing');
ELSE
UPDATE emp SET sal = curr_sal + amount WHERE empno = emp_id;
END IF;
END raise_salary;

What is the range of the Error Codes for User-Defined Exceptions ?
The range of error code is between -20000 and -20999.

What is the starting oracle error number ?
ORA-00000 normal, successful completion

Explain about SQLERRM and SQLCODE and their importance.
SQLERRM returns the error message for the last error that came across. SQLERRM is useful for WHEN OTHERS Exception. They can be used for Reporting purpose in Error Handling. They can also store the Error in the Code and store it in the Error Log Table. SQLCODE Returns the Value of the Error Number for the previous error.

What is the Difference between Runtime errors and Syntax errors ?
A Runtime Error is handled with the help of Exception Handling Mechanism in a PL/SQL Block whereas a Syntax Error such as a spelling mistake is efficiently detected by the SQL Compiler.

How can you assign a Name to an Un-Named PL/SQL Exception Block ?
You can assign a name to an Un-Named Exception using Pragma, also known as Exception_init.

Explain about Pragma Exception_Init.
To handle error conditions (typically ORA- messages) that have no predefined name, you must use the OTHERS handler or the pragma EXCEPTION_INIT. In PL/SQL, the pragma EXCEPTION_INIT tells the compiler to associate an exception name with an Oracle error number.

Syntax : PRAGMA EXCEPTION_INIT(exception_name, -Oracle_error_number);

where exception_name is the name of a previously declared exception and the number is a negative value corresponding to an ORA- error number. The pragma must appear somewhere after the exception declaration in the same declarative section, as shown in the following example:

DECLARE
deadlock_detected EXCEPTION;
PRAGMA EXCEPTION_INIT(deadlock_detected, -60);
BEGIN
... -- Some operation that causes an ORA-00060 error
EXCEPTION
WHEN deadlock_detected THEN
-- handle the error
END;


What is PRAGMA ? What are the different types of PRAGMA ?
PRAGMA refers to a compiler directive or "hint" it is used to provide an instruction to the compiler. Pragma tells Oracle to use specific rules other than the default rules for a particular object. They are processed at compile time, not at run time.

Differnt types of PRAGMA are:

RESTRICTED_REFERENCES : To check for violations of the rules at compile time, you can use the compiler directive PRAGMA RESTRICT_REFERENCES. This pragma asserts that a function does not read and/or write database tables and/or package variables. Functions that do any of these read or write operations are difficult to optimize, because any call might produce different results or encounter errors.

EXCEPTION_INIT : This pragma is used to associates an exception name with an Oracle error number.

Declare MyExcep exception;
PRAGMA EXCEPTION_INIT(MyExcep,10001);
begin
..…

exception
when I then
dbms_output.put_line( 'Duplicate value');
end;

AUTONOMOUS_TRANSACTION : this pragma changes the way a subprogram works within a transaction. A subprogram marked with this pragma can do SQL operations and commit or roll back those operations, without committing or rolling back the data in the main transaction.

Eg : When you declare a trigger as AUTONOMOUS_TRANSACTION, then you can commit inside the trigger, irrespective of the calling procedure.

CREATE OR REPLACE TRIGGER audit_sal
AFTER UPDATE OF salary ON employees FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
-- bind variables are used here for values
INSERT INTO emp_audit VALUES( :old.employee_id, SYSDATE,
:new.salary, :old.salary );
COMMIT;
END;

SERIALLY_REUSABLE : indicates that the package state is needed only for the duration of one call to the server. This pragma is appropriate for packages that declare large temporary work areas that are used once and not needed during subsequent database calls in the same session. You can mark a bodiless package as serially reusable. If a package has a spec and body, you must mark both.

INLINE : (introduced in 11g) specifys that a subprogram call is, or is not, to be inlined. Inlining replaces a subprogram call (to a subprogram in the same program unit) with a copy of the called subprogram.

E.g.: PROCEDURE p1 (x PLS_INTEGER) IS ...
...
PRAGMA INLINE (p1, 'YES');
x:= p1(1) + p1(2) + 17; -- These 2 calls to p1 will be inlined
...
x:= p1(3) + p1(4) + 17; -- These 2 calls to p1 will not be inlined




Thursday, September 8, 2016

Collections & Record Interview Questions

What is a collection in pl/sql ?
A collection is an ordered group of elements, all of the same type. It is a general concept that encompasses lists, arrays, and other datatypes used in classic programming algorithms. Each element is addressed by a unique subscript.

PL/SQL has three collection types:

An associative array (also called an index-by table) is a set of key-value pairs. Each key is unique, and is used to locate the corresponding value. The key can be either an integer or a string. Using a key-value pair for the first time adds that pair to the associative array. Using the same key with a different value changes the value.

Example : Declaring and Using an Associative Array

SQL> DECLARE
2 -- Associative array indexed by string:
3
4 TYPE population IS TABLE OF NUMBER -- Associative array type
5 INDEX BY VARCHAR2(64);
6
7 city_population population; -- Associative array variable
8 i VARCHAR2(64);
9
10 BEGIN
11 -- Add new elements to associative array:
12
13 city_population('Agra') := 2000;
14 city_population('Noida') := 750000;
15 city_population('Delhi') := 1000000;
16
17 -- Change value associated with key 'Agra':
18
19 city_population('Agra') := 2001;
20
21 -- Print associative array:
22
23 i := city_population.FIRST;
24
25 WHILE i IS NOT NULL LOOP
26 DBMS_Output.PUT_LINE
27 ('Population of ' || i || ' is ' || TO_CHAR(city_population(i)));
28 i := city_population.NEXT(i);
29 END LOOP;
30 END;
31 /
Population of Delhi is 1000000
Population of Noida is 750000
Population of Agra is 2001
PL/SQL procedure successfully completed.
SQL>

An associative array is intended for temporary data storage. To make an associative array persistent for the life of a database session, declare the associative array (the type and the variable of that type) in a package, and assign values to its elements in the package body.


A nested table is like a one-dimensional array with an arbitrary number of elements. Within the database, a nested table is a column type that holds a set of values.

Example : Declaring and Using a nested table:

SQL> DECLARE
2 TYPE names_table IS TABLE OF VARCHAR2(10);
3 TYPE grades IS TABLE OF INTEGER;
4
5 names names_table;
6 marks grades;
7 total integer;
8 BEGIN
9 names := names_table('Jitendra', 'Chinmay', 'Ankit', 'Abhinav', 'Vivek');
10 marks:= grades(98, 97, 78, 87, 92);
11 total := names.count;
12 dbms_output.put_line('Total '|| total || ' Students');
13 FOR i IN 1 .. total LOOP
14 dbms_output.put_line('Student:'||names(i)||', Marks:' || marks(i));
15 end loop;
16 END;
17 /
Total 5 Students
Student:Jitendra, Marks:98
Student:Chinmay, Marks:99
Student:Ankit, Marks:78
Student:Abhinav, Marks:87
Student:Vivek, Marks:92

PL/SQL procedure successfully completed.

SQL>

Elements of a nested table could also be a %ROWTYPE of any database table or %TYPE of any database table field.

Example:
TYPE DocIndex_TYPE IS TABLE OF ISDoc.DocIndex%TYPE;
doc_type DocIndex_TYPE;
doc_size DocIndex_TYPE;

A varray is a variable-size array of a datatype which has a maximum size, which you specify in its type definition. A varray can contain a varying number of elements, from zero (when empty) to the maximum size. To access an element of a varray, you use standard subscripting syntax.

Example :
      DECLARE
         TYPE Calendar IS VARRAY(366) OF DATE;


What is the difference between varray and nested table ?
  • A varray has a declared number of elements, but a nested table does not. The size of a nested table can increase dynamically.
  • An varray is always dense (that is, it always has consecutive subcripts). A nested table is dense initially, but it can become sparse, because you can delete elements from it.


What is a Record in pl/sql ?
A record is a group of related data items stored in fields, each with its own name and datatype. You can think of a record as a variable that can hold a table row, or some columns from a table row.

DECLARE
-- Declare a record type with 3 fields.
TYPE rec1_t IS RECORD (field1 VARCHAR2(16), field2 NUMBER, field3 DATE);


What is difference between % ROWTYPE and TYPE RECORD ?
% ROWTYPE is to be used whenever query returns a entire row of a table or view.

TYPE rec RECORD is to be used whenever query returns columns of different table or views and variables.

E.g. TYPE r_emp is RECORD (eno emp.empno% type,ename emp ename %type);
         e_rec emp% ROWTYPE
         cursor c1 is select empno,deptno from emp;
         e_rec c1 %ROWTYPE.