SQL Server Interview and Practice Questions
SQL Server Interview and Practice Questions
returns all columns of all rows from the Employees table 1 2 . The SELECT * syntax
means “select all columns” 1 , whereas listing specific columns (e.g. SELECT Name, Salary )
returns only those fields 2 .
returns only employees in department 3. The WHERE clause follows FROM and allows you to
fetch rows that match specified conditions 3 . In this example, only rows satisfying
DepartmentID = 3 are returned 3 .
sorts employees by salary in descending order. By default, ORDER BY sorts in ascending order;
adding DESC makes it descending. The ORDER BY clause “is used to sort the result set in
ascending or descending order” 4 .
1
returns each DepartmentID once, even if it appears in multiple rows. This removes duplicate
values from the output. (While many tutorials note DISTINCT , one example is: SELECT
DISTINCT column FROM table; 1 .)
returns those in either dept 3 or 4. The AND / OR keywords let you filter on multiple criteria 5 .
(If none match, an empty set is returned 6 .)
adds up all salaries. Aggregate functions must often go with GROUP BY if you group results.
For instance, to count per department:
groups rows by DepartmentID and counts each group. In SQL, “the aggregate function SUM()
can be used with the GROUP BY clause to calculate sums for groups of rows” 7 , and similarly
for COUNT().
2
groups of rows based on one or more columns” 7 . Likewise, you can group by any column(s)
to, say, get average or count per group.
returns only departments whose average salary exceeds 60,000. In SQL, the HAVING clause
filters results based on aggregate conditions (e.g., SUM or AVG) after grouping 8 .
This selects each employee’s name along with their department name for those with matching
department IDs. An inner join “produces rows only when a match is found in both tables” (as is
standard SQL behavior). The INNER JOIN clause specifies how the tables relate by the ON
condition.
3
SELECT e.Name, d.DepartmentName
FROM Employees e
RIGHT JOIN Departments d
ON e.DepartmentID = d.DepartmentID;
This returns all departments, and any matching employee names. In practice, RIGHT JOIN is
the mirror of LEFT JOIN .
returns all employees and all departments, pairing where possible and using NULL where there
is no match. This covers situations where an employee has no department and where a
department has no employees. (A FULL JOIN is essentially all rows from both tables, joined
where keys match.)
SELECT FirstName
FROM Employees
WHERE Salary = (
SELECT MAX(Salary)
FROM Employees
);
This returns the employee(s) with the highest salary. Here the inner query (SELECT
MAX(Salary) FROM Employees) finds the maximum salary, and the outer query selects those
with that salary. In SQL, “a SELECT statement may contain another SQL statement, known as a
subquery or nested query” 10 .
4
SELECT AVG(e2.Salary)
FROM Employees e2
WHERE e2.DepartmentID = e.DepartmentID
);
Here the inner query uses e.DepartmentID from the outer query, making it correlated.
turns any NULL ManagerID into 0. According to documentation, “the ISNULL() function
returns a specified value if the expression is NULL” 11 . Similarly, COALESCE(expr1, expr2,
…) returns the first non- NULL expression. For example:
returns the extension if not NULL , else 'n/a' . The COALESCE function “returns the first non-
null value in a list” 12 .
17. How do you get the current date and time in SQL Server?
Use the GETDATE() function. For example:
returns the current system date and time. In SQL Server, “the GETDATE() function returns the
current database system date and time” in YYYY-MM-DD hh:mm:ss format 13 .
5
results of a SELECT . You create a view with CREATE VIEW . For example:
This defines a view of Brazilian customers 14 . After creation, you can query the view like a table:
SELECT * FROM [Brazil_Customers]; 15 . As documented, “the CREATE VIEW command
creates a view. A view is a virtual table based on the result set of an SQL statement” 16 .
You can then run it with EXEC SelectAllEmployees; . A stored procedure can also accept
parameters, e.g.:
This returns employees for a given department. In SQL Server, the syntax is
CREATE PROCEDURE name AS ... 17 .
This trigger inserts a log row whenever a new employee is added. Triggers use special virtual
tables ( INSERTED , DELETED ). As documentation shows, a trigger is created with CREATE
6
TRIGGER … ON table … FOR INSERT/UPDATE/DELETE and can, for example, insert into a log
table using INSERTED 18 . The above example is adapted from that pattern.
BEGIN TRANSACTION;
UPDATE Accounts SET Balance = Balance - 100 WHERE AccountID = 1;
UPDATE Accounts SET Balance = Balance + 100 WHERE AccountID = 2;
IF @@ERROR = 0
COMMIT;
ELSE
ROLLBACK;
This transfers 100 between accounts. The concept is that “explicit transactions start with the
BEGIN TRANSACTION statement and end with the COMMIT or ROLLBACK statement” 19 . If
any error occurs, the ROLLBACK undoes all updates, ensuring data integrity.
BEGIN TRY
-- code that might fail
INSERT INTO Employees(Name) VALUES(NULL); -- suppose Name is NOT NULL
END TRY
BEGIN CATCH
PRINT 'Error: ' + ERROR_MESSAGE();
END CATCH;
In SQL Server, “a TRY...CATCH construct catches execution errors” and transfers control to the
CATCH block if an error occurs 20 . Inside CATCH , you can retrieve error info with functions
like ERROR_MESSAGE() .
7
at 1 for the first row in each partition” 21 . If you include PARTITION BY DeptID in OVER ,
numbering restarts for each department.
creates a nonclustered index on LastName . This speeds lookups by last name without
reordering the table. The pointer (row locator) tells SQL where to find the full row. According to
Microsoft: “Nonclustered indexes have a structure separate from the data rows. A nonclustered
index contains the nonclustered index key values and each key value entry has a pointer to the
data row” 23 .
This creates an index on EmployeeID . Indexes allow faster data retrieval by organizing data (B-
tree) for quick searches 24 25 . With an index on EmployeeID , queries like WHERE
EmployeeID = ... or joins on that column will use the index to find rows quickly rather than
scanning the whole table. W3Schools notes “indexes are used to retrieve data from the database
very fast” 25 .
8
needed. Avoid SELECT * if many columns. Understanding the query execution plan helps
identify bottlenecks. (Using indexes as above is one key strategy.) According to MS
documentation and best practices, indexing relevant columns usually improves performance 25
24 .
returns unique names from both departments. If you want all names including duplicates, use
UNION ALL . The important thing is both queries must have the same number of columns and
compatible types.
returns only departments with more than 5 employees. Here, HAVING COUNT(*) > 5 applies
to the grouped result. Recall that WHERE cannot filter aggregates, so HAVING is needed for
conditions on counts, sums, etc.
9
This retrieves each employee’s name, department, and location. It demonstrates joining multiple
tables by chaining INNER JOIN . Each join clause specifies matching keys.
This returns all employees and all departments. If an employee has no department,
DepartmentName will be NULL . If a department has no employees, Name will be NULL .
This covers all cases from both tables.
The inner query uses e.DepartmentID from the outer query, making it correlated. This finds
employees whose salary is above the average salary in their own department. The subquery runs
once per outer row.
10
BEGIN
SELECT * FROM Employees WHERE DepartmentID = @DeptID;
END;
GO
This procedure takes @DeptID as input and returns employees in that department. You
execute it with:
This trigger fires in place of the usual INSERT on the view, allowing custom logic. In contrast, an
AFTER trigger fires after the insert has succeeded on a table.
BEGIN TRY
BEGIN TRANSACTION;
-- Perform updates
INSERT INTO Orders(...) VALUES(...);
UPDATE Inventory SET Qty = Qty - 1 WHERE ItemID = ...;
COMMIT;
END TRY
BEGIN CATCH
ROLLBACK;
PRINT 'Error occurred: ' + ERROR_MESSAGE();
END CATCH;
This ensures that on error, the transaction is rolled back. Microsoft states that TRY...CATCH
“catches execution errors” and transfers control to the CATCH block 20 .
11
pointer or clustered key) 23 . So clustered indexes speed up range queries on the key, while
nonclustered indexes speed lookups on other columns without changing row order.
This resets the row number for each DepartmentID . The PARTITION BY clause divides the
result set into groups; within each group the numbering starts at 1. The MS docs note that
ROW_NUMBER() “returns the sequential number of a row within a partition” 21 .
If two employees tie for highest salary, both get 1 for Rnk and DenseRnk , but the next Rnk
would be 3 while the next DenseRnk would be 2.
12
SELECT Name FROM Employees WHERE DepartmentID = 1
UNION
SELECT Name FROM Employees WHERE DepartmentID = 2;
returns each name once. Use UNION ALL if you want to include duplicates (and improve
performance if deduplication isn’t needed).
◦ 1NF (First Normal Form): Eliminate repeating groups; each column holds atomic values.
◦ 2NF: Ensure 1NF and remove partial dependencies; non-key columns depend on the
whole primary key (applies when composite keys exist).
◦ 3NF: Ensure 2NF and remove transitive dependencies; non-key columns depend only on
the primary key, not on other non-key columns.
This design reduces update anomalies and saves space.
19. How do you find and kill a long-running query in SQL Server?
Use system views or Activity Monitor. For example:
to find running queries. Or query sys.sysprocesses . Once you identify the session (SPID),
you can stop it:
KILL <session_id>;
13
21. What is an execution plan and how do you use it?
The execution plan shows how SQL Server executes a query. It indicates join types, index usage,
estimated costs, etc. In SSMS, you can display the Actual Execution Plan. Reading it helps identify
slow operations (e.g., table scans vs index seeks). The Query Optimizer chooses a plan; by
reviewing it, you can add indexes or rewrite queries to improve performance.
22. Explain the difference between a primary key and a unique constraint.
Both enforce uniqueness on columns. A table can have only one primary key, which implicitly
creates a unique, clustered index (unless a clustered index already exists, then a nonclustered
index). A unique constraint can be on multiple columns and creates a unique index. Unlike
primary key, unique constraint allows one row to have a NULL (depending on DBMS). In SQL
Server, defining a primary key creates a unique index 27 .
UPDATE e
SET e.Salary = e.Salary * 1.1
FROM Employees e
INNER JOIN Departments d ON e.DepartmentID = d.DepartmentID
WHERE d.Name = 'Sales';
This increases salaries by 10% for employees in Sales. The UPDATE ... FROM JOIN syntax lets
you match rows across tables before updating.
This index is on FirstName, LastName , but also stores HireDate in leaf nodes to cover
queries that select it, improving performance. Included columns are not part of the key but avoid
lookups.
WITH RecentSales AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY SaleDate DESC) AS rn
FROM Sales
)
SELECT * FROM RecentSales WHERE rn <= 5;
14
This returns the 5 most recent sales. CTEs are useful for readable complex queries or recursion
(recursive CTEs).
Here Employees appears twice with different aliases. It lets you relate rows within the same
table.
Sources: Concepts and examples are based on SQL Server documentation and tutorials 1 2 3 4
7 8 12 11 13 16 18 19 20 21 25 24 10 .
15
4 SQL ORDER BY Clause (With Examples)
https://www.programiz.com/sql/order-by
9 25 SQL INDEX
https://www.w3schools.com/sql/sql_ref_index.asp
16