@@ -167,7 +167,9 @@ VALUES (501, 3, '2023-12-15', 4.5, 1, 'Excellent performance in sales targets. G
167167INSERT INTO PERFORMANCE_REVIEW(reviewId, empId, reviewDate, rating, reviewerEmpId, comments)
168168VALUES (502, 6, '2023-12-16', 4.2, 1, 'Consistently meets targets. Could improve on documentation.');
169169
170-
170+ -- ========================================
171+ -- SELECT QUERIES
172+ -- ========================================
171173-- Sample queries
172174-- Find all employees in Sales department
173175SELECT * FROM EMPLOYEE WHERE dept = 'Sales';
@@ -191,3 +193,365 @@ FROM EMPLOYEE e
191193LEFT JOIN ATTENDANCE a ON e.empId = a.empId
192194WHERE MONTH(a.workDate) = MONTH(GETDATE()) AND YEAR(a.workDate) = YEAR(GETDATE())
193195GROUP BY e.name;
196+ -- ========================================
197+ -- ALTER TABLE / UPDATE COLUMN TYPE QUERIES
198+ -- ========================================
199+
200+ -- Increase the size of varchar columns
201+ ALTER TABLE DEPARTMENT ALTER COLUMN deptName VARCHAR(50);
202+ ALTER TABLE DEPARTMENT ALTER COLUMN location VARCHAR(100);
203+
204+ -- Change email column to accommodate longer email addresses
205+ ALTER TABLE EMPLOYEE ALTER COLUMN email VARCHAR(100);
206+
207+ -- Expand project name and status fields
208+ ALTER TABLE PROJECT ALTER COLUMN projectName VARCHAR(100);
209+ ALTER TABLE PROJECT ALTER COLUMN status VARCHAR(25);
210+
211+ -- Increase performance review comments field
212+ ALTER TABLE PERFORMANCE_REVIEW ALTER COLUMN comments VARCHAR(1000);
213+
214+ -- Add new columns to existing tables
215+ ALTER TABLE EMPLOYEE ADD isActive BIT DEFAULT 1;
216+ ALTER TABLE EMPLOYEE ADD terminationDate DATE NULL;
217+
218+ ALTER TABLE PROJECT ADD projectManager INT NULL;
219+ ALTER TABLE PROJECT ADD FOREIGN KEY (projectManager) REFERENCES EMPLOYEE(empId);
220+
221+ ALTER TABLE DEPARTMENT ADD budget DECIMAL(15,2) NULL;
222+
223+ -- For SQL Server, to change data type of a column with data:
224+ -- First, create a new column with the desired type
225+ ALTER TABLE PROJECT_ASSIGNMENT ADD hoursAllocatedNew DECIMAL(7,2);
226+ -- Copy data from old column to new column
227+ UPDATE PROJECT_ASSIGNMENT SET hoursAllocatedNew = hoursAllocated;
228+ -- Drop the old column
229+ ALTER TABLE PROJECT_ASSIGNMENT DROP COLUMN hoursAllocated;
230+ -- Rename the new column to the original name
231+ EXEC sp_rename 'PROJECT_ASSIGNMENT.hoursAllocatedNew', 'hoursAllocated', 'COLUMN';
232+
233+
234+ -- ========================================
235+ -- COMPLEX SELECT QUERIES WITH CTEs
236+ -- ========================================
237+
238+ -- 1. Employee Hierarchy with Recursive CTE
239+ WITH EmployeeHierarchy AS (
240+ -- Anchor member: Top-level managers
241+ SELECT empId, name, managerId, jobTitle, 0 as Level
242+ FROM EMPLOYEE
243+ WHERE managerId IS NULL
244+
245+ UNION ALL
246+
247+ -- Recursive member: Employees under managers
248+ SELECT e.empId, e.name, e.managerId, e.jobTitle, eh.Level + 1
249+ FROM EMPLOYEE e
250+ INNER JOIN EmployeeHierarchy eh ON e.managerId = eh.empId
251+ )
252+ SELECT empId, name, jobTitle, Level,
253+ REPLICATE(' ', Level) + name AS HierarchicalName
254+ FROM EmployeeHierarchy
255+ ORDER BY Level, name;
256+
257+
258+ -- 2. Department Performance Analysis with Multiple CTEs
259+ WITH DeptSalary AS (
260+ SELECT d.deptId, d.deptName,
261+ AVG(s.amount) as avgSalary,
262+ MIN(s.amount) as minSalary,
263+ MAX(s.amount) as maxSalary,
264+ COUNT(e.empId) as empCount
265+ FROM DEPARTMENT d
266+ JOIN EMPLOYEE e ON d.deptId = e.deptId
267+ JOIN SALARY s ON e.empId = s.empId
268+ GROUP BY d.deptId, d.deptName
269+ ),
270+ DeptProjects AS (
271+ SELECT d.deptId,
272+ COUNT(DISTINCT p.projectId) as projectCount,
273+ SUM(p.budget) as totalBudget,
274+ AVG(p.budget) as avgProjectBudget
275+ FROM DEPARTMENT d
276+ LEFT JOIN PROJECT p ON d.deptId = p.deptId
277+ GROUP BY d.deptId
278+ )
279+ SELECT ds.deptName,
280+ ds.empCount,
281+ ds.avgSalary,
282+ ds.minSalary,
283+ ds.maxSalary,
284+ COALESCE(dp.projectCount, 0) as projectCount,
285+ COALESCE(dp.totalBudget, 0) as totalProjectBudget,
286+ COALESCE(dp.avgProjectBudget, 0) as avgProjectBudget
287+ FROM DeptSalary ds
288+ LEFT JOIN DeptProjects dp ON ds.deptId = dp.deptId
289+ ORDER BY ds.avgSalary DESC;
290+
291+
292+ -- 3. Employee Workload Analysis
293+ WITH EmployeeProjects AS (
294+ SELECT e.empId, e.name, e.deptId,
295+ COUNT(pa.projectId) as projectCount,
296+ SUM(pa.hoursAllocated) as totalHours
297+ FROM EMPLOYEE e
298+ LEFT JOIN PROJECT_ASSIGNMENT pa ON e.empId = pa.empId
299+ GROUP BY e.empId, e.name, e.deptId
300+ ),
301+ ProjectDetails AS (
302+ SELECT pa.empId,
303+ STRING_AGG(p.projectName, ', ') as projectList
304+ FROM PROJECT_ASSIGNMENT pa
305+ JOIN PROJECT p ON pa.projectId = p.projectId
306+ GROUP BY pa.empId
307+ )
308+ SELECT ep.name,
309+ d.deptName,
310+ ep.projectCount,
311+ ep.totalHours,
312+ pd.projectList,
313+ CASE
314+ WHEN ep.totalHours > 40 THEN 'Overallocated'
315+ WHEN ep.totalHours BETWEEN 30 AND 40 THEN 'Fully Allocated'
316+ WHEN ep.totalHours BETWEEN 15 AND 29 THEN 'Partially Allocated'
317+ ELSE 'Underallocated'
318+ END as AllocationStatus
319+ FROM EmployeeProjects ep
320+ JOIN DEPARTMENT d ON ep.deptId = d.deptId
321+ LEFT JOIN ProjectDetails pd ON ep.empId = pd.empId
322+ ORDER BY ep.totalHours DESC;
323+
324+
325+ -- 4. Salary Ranking within Departments
326+ WITH SalaryRanking AS (
327+ SELECT e.empId, e.name, d.deptName, s.amount,
328+ RANK() OVER (PARTITION BY d.deptId ORDER BY s.amount DESC) as salaryRank,
329+ DENSE_RANK() OVER (PARTITION BY d.deptId ORDER BY s.amount DESC) as denseRank,
330+ ROW_NUMBER() OVER (PARTITION BY d.deptId ORDER BY s.amount DESC) as rowNum,
331+ PERCENT_RANK() OVER (PARTITION BY d.deptId ORDER BY s.amount DESC) as percentRank
332+ FROM EMPLOYEE e
333+ JOIN DEPARTMENT d ON e.deptId = d.deptId
334+ JOIN SALARY s ON e.empId = s.empId
335+ )
336+ SELECT name, deptName, amount,
337+ salaryRank,
338+ CASE
339+ WHEN percentRank <= 0.25 THEN 'Top 25%'
340+ WHEN percentRank <= 0.50 THEN 'Top 50%'
341+ WHEN percentRank <= 0.75 THEN 'Top 75%'
342+ ELSE 'Bottom 25%'
343+ END as SalaryPercentile
344+ FROM SalaryRanking
345+ ORDER BY deptName, salaryRank;
346+
347+
348+ -- 5. Project Timeline Analysis
349+ WITH ProjectStatus AS (
350+ SELECT projectId, projectName,
351+ startDate, endDate, budget, status,
352+ DATEDIFF(day, startDate, endDate) as durationDays,
353+ DATEDIFF(day, startDate, GETDATE()) as daysElapsed,
354+ CASE
355+ WHEN endDate < GETDATE() AND status != 'Completed' THEN 'Overdue'
356+ WHEN endDate >= GETDATE() AND status = 'In Progress' THEN 'On Track'
357+ WHEN status = 'Completed' THEN 'Completed'
358+ ELSE 'Not Started'
359+ END as ProjectHealth
360+ FROM PROJECT
361+ ),
362+ ProjectTeam AS (
363+ SELECT p.projectId,
364+ COUNT(DISTINCT pa.empId) as teamSize,
365+ SUM(pa.hoursAllocated) as totalAllocatedHours
366+ FROM PROJECT p
367+ LEFT JOIN PROJECT_ASSIGNMENT pa ON p.projectId = pa.projectId
368+ GROUP BY p.projectId
369+ )
370+ SELECT ps.projectName,
371+ ps.status,
372+ ps.ProjectHealth,
373+ ps.durationDays,
374+ ps.daysElapsed,
375+ CAST(ps.daysElapsed * 100.0 / NULLIF(ps.durationDays, 0) AS DECIMAL(5,2)) as PercentComplete,
376+ ps.budget,
377+ pt.teamSize,
378+ pt.totalAllocatedHours
379+ FROM ProjectStatus ps
380+ LEFT JOIN ProjectTeam pt ON ps.projectId = pt.projectId
381+ ORDER BY ps.ProjectHealth DESC, ps.endDate;
382+
383+
384+ -- 6. Employee Tenure and Salary Growth Analysis
385+ WITH EmployeeTenure AS (
386+ SELECT empId, name, hireDate,
387+ DATEDIFF(year, hireDate, GETDATE()) as yearsOfService,
388+ DATEDIFF(month, hireDate, GETDATE()) as monthsOfService
389+ FROM EMPLOYEE
390+ ),
391+ SalaryHistory AS (
392+ SELECT et.empId, et.name, et.yearsOfService,
393+ s.amount as currentSalary,
394+ s.amount / NULLIF(et.yearsOfService, 0) as avgYearlyIncrease
395+ FROM EmployeeTenure et
396+ JOIN SALARY s ON et.empId = s.empId
397+ )
398+ SELECT name, yearsOfService, currentSalary,
399+ COALESCE(avgYearlyIncrease, currentSalary) as avgYearlyIncrease,
400+ CASE
401+ WHEN yearsOfService < 2 THEN 'New Employee'
402+ WHEN yearsOfService BETWEEN 2 AND 5 THEN 'Mid-Level'
403+ ELSE 'Senior Employee'
404+ END as TenureCategory
405+ FROM SalaryHistory
406+ ORDER BY yearsOfService DESC;
407+
408+
409+ -- 7. Department Cross-Analysis
410+ WITH DepartmentMetrics AS (
411+ SELECT d.deptId, d.deptName,
412+ COUNT(DISTINCT e.empId) as employeeCount,
413+ COUNT(DISTINCT p.projectId) as projectCount,
414+ COALESCE(SUM(p.budget), 0) as totalProjectBudget,
415+ AVG(s.amount) as avgSalary
416+ FROM DEPARTMENT d
417+ LEFT JOIN EMPLOYEE e ON d.deptId = e.deptId
418+ LEFT JOIN PROJECT p ON d.deptId = p.deptId
419+ LEFT JOIN SALARY s ON e.empId = s.empId
420+ GROUP BY d.deptId, d.deptName
421+ ),
422+ DepartmentEfficiency AS (
423+ SELECT deptId,
424+ CASE
425+ WHEN employeeCount > 0 THEN totalProjectBudget / employeeCount
426+ ELSE 0
427+ END as budgetPerEmployee,
428+ CASE
429+ WHEN projectCount > 0 THEN employeeCount * 1.0 / projectCount
430+ ELSE 0
431+ END as employeesPerProject
432+ FROM DepartmentMetrics
433+ )
434+ SELECT dm.deptName,
435+ dm.employeeCount,
436+ dm.projectCount,
437+ dm.totalProjectBudget,
438+ dm.avgSalary,
439+ de.budgetPerEmployee,
440+ de.employeesPerProject
441+ FROM DepartmentMetrics dm
442+ JOIN DepartmentEfficiency de ON dm.deptId = de.deptId
443+ ORDER BY dm.totalProjectBudget DESC;
444+
445+
446+ -- 8. Performance Review Insights
447+ WITH ReviewStats AS (
448+ SELECT e.empId, e.name, e.deptId,
449+ COUNT(pr.reviewId) as reviewCount,
450+ AVG(pr.rating) as avgRating,
451+ MIN(pr.rating) as minRating,
452+ MAX(pr.rating) as maxRating
453+ FROM EMPLOYEE e
454+ LEFT JOIN PERFORMANCE_REVIEW pr ON e.empId = pr.empId
455+ GROUP BY e.empId, e.name, e.deptId
456+ ),
457+ DeptAvgRating AS (
458+ SELECT deptId,
459+ AVG(avgRating) as deptAvgRating
460+ FROM ReviewStats
461+ WHERE avgRating IS NOT NULL
462+ GROUP BY deptId
463+ )
464+ SELECT rs.name,
465+ d.deptName,
466+ rs.reviewCount,
467+ rs.avgRating,
468+ dar.deptAvgRating,
469+ CASE
470+ WHEN rs.avgRating > dar.deptAvgRating THEN 'Above Department Average'
471+ WHEN rs.avgRating = dar.deptAvgRating THEN 'At Department Average'
472+ WHEN rs.avgRating < dar.deptAvgRating THEN 'Below Department Average'
473+ ELSE 'No Reviews'
474+ END as PerformanceLevel
475+ FROM ReviewStats rs
476+ JOIN DEPARTMENT d ON rs.deptId = d.deptId
477+ LEFT JOIN DeptAvgRating dar ON rs.deptId = dar.deptId
478+ ORDER BY CASE WHEN rs.avgRating IS NULL THEN 1 ELSE 0 END, rs.avgRating DESC;
479+
480+
481+ -- 9. Attendance Pattern Analysis
482+ WITH AttendanceStats AS (
483+ SELECT empId,
484+ COUNT(*) as daysPresent,
485+ AVG(DATEDIFF(hour, timeIn, timeOut)) as avgHoursWorked,
486+ MIN(timeIn) as earliestArrival,
487+ MAX(timeOut) as latestDeparture
488+ FROM ATTENDANCE
489+ WHERE workDate >= DATEADD(month, -1, GETDATE())
490+ GROUP BY empId
491+ ),
492+ EmployeeAttendance AS (
493+ SELECT e.empId, e.name, d.deptName,
494+ COALESCE(a.daysPresent, 0) as daysPresent,
495+ COALESCE(a.avgHoursWorked, 0) as avgHoursWorked,
496+ a.earliestArrival,
497+ a.latestDeparture
498+ FROM EMPLOYEE e
499+ JOIN DEPARTMENT d ON e.deptId = d.deptId
500+ LEFT JOIN AttendanceStats a ON e.empId = a.empId
501+ )
502+ SELECT name, deptName, daysPresent, avgHoursWorked,
503+ FORMAT(earliestArrival, 'HH:mm') as earliestArrival,
504+ FORMAT(latestDeparture, 'HH:mm') as latestDeparture,
505+ CASE
506+ WHEN avgHoursWorked >= 9 THEN 'Overtime Worker'
507+ WHEN avgHoursWorked BETWEEN 7.5 AND 9 THEN 'Regular Hours'
508+ WHEN avgHoursWorked > 0 THEN 'Part Time'
509+ ELSE 'No Recent Attendance'
510+ END as WorkPattern
511+ FROM EmployeeAttendance
512+ ORDER BY avgHoursWorked DESC;
513+
514+
515+ -- 10. Comprehensive Employee Dashboard
516+ WITH EmployeeSummary AS (
517+ SELECT e.empId, e.name, e.jobTitle, d.deptName,
518+ s.amount as salary,
519+ DATEDIFF(year, e.hireDate, GETDATE()) as yearsOfService
520+ FROM EMPLOYEE e
521+ JOIN DEPARTMENT d ON e.deptId = d.deptId
522+ LEFT JOIN SALARY s ON e.empId = s.empId
523+ ),
524+ ProjectSummary AS (
525+ SELECT pa.empId,
526+ COUNT(DISTINCT pa.projectId) as activeProjects,
527+ SUM(pa.hoursAllocated) as totalHours
528+ FROM PROJECT_ASSIGNMENT pa
529+ JOIN PROJECT p ON pa.projectId = p.projectId
530+ WHERE p.status = 'In Progress'
531+ GROUP BY pa.empId
532+ ),
533+ ReviewSummary AS (
534+ SELECT empId,
535+ AVG(rating) as avgRating,
536+ MAX(reviewDate) as lastReviewDate
537+ FROM PERFORMANCE_REVIEW
538+ GROUP BY empId
539+ )
540+ SELECT es.name,
541+ es.jobTitle,
542+ es.deptName,
543+ es.salary,
544+ es.yearsOfService,
545+ COALESCE(ps.activeProjects, 0) as activeProjects,
546+ COALESCE(ps.totalHours, 0) as projectHours,
547+ rs.avgRating,
548+ rs.lastReviewDate,
549+ CASE
550+ WHEN rs.lastReviewDate < DATEADD(year, -1, GETDATE()) OR rs.lastReviewDate IS NULL
551+ THEN 'Review Overdue'
552+ ELSE 'Review Current'
553+ END as reviewStatus
554+ FROM EmployeeSummary es
555+ LEFT JOIN ProjectSummary ps ON es.empId = ps.empId
556+ LEFT JOIN ReviewSummary rs ON es.empId = rs.empId
557+ ORDER BY es.name;
0 commit comments