A SQL-based exploratory data analysis project focused on analyzing the global impact of COVID-19 through cases, deaths, population, and vaccination data.
The project uses Microsoft SQL Server to transform raw COVID-19 datasets into meaningful insights through data exploration, aggregation, joins, window functions, CTEs, temporary tables, and SQL views.
The COVID-19 pandemic generated large volumes of data across countries and continents.
This project explores that data to answer important analytical questions around:
- COVID-19 cases and deaths
- Death rates
- Infection rates
- Population impact
- Country and continent comparisons
- Global COVID-19 trends
- Vaccination progress
- Percentage of population vaccinated
The analysis demonstrates practical SQL skills for data cleaning, exploratory analysis, aggregation, relational joins, window functions, and analytical reporting.
The main objectives of this project are to:
- Explore global COVID-19 case and death data.
- Calculate COVID-19 death percentages.
- Analyze the likelihood of death after contracting COVID-19.
- Identify countries with the highest infection rates.
- Compare COVID-19 death counts across countries.
- Analyze COVID-19 deaths by continent.
- Calculate global daily cases and deaths.
- Examine population size against vaccination progress.
- Calculate cumulative vaccinations over time.
- Determine the percentage of population vaccinated.
- Create reusable SQL views for visualization and reporting.
The project uses two primary datasets:
Contains information relating to:
- Location
- Continent
- Date
- Population
- Total cases
- New cases
- Total deaths
- New deaths
Contains vaccination-related information, including:
- Location
- Date
- New vaccinations
The datasets are joined using:
ON dea.location = vac.location
AND dea.date = vac.dateMicrosoft SQL Server
| SQL Technique | Application |
|---|---|
SELECT |
Data extraction |
WHERE |
Filtering records |
GROUP BY |
Aggregating data |
ORDER BY |
Sorting results |
MAX() |
Identifying highest values |
SUM() |
Calculating totals |
CAST() / CONVERT() |
Data type conversion |
ISNULL() |
Handling missing values |
JOIN |
Combining COVID datasets |
| Window Functions | Cumulative vaccination calculations |
| CTE | Structuring complex queries |
| Temporary Tables | Intermediate analysis |
| SQL Views | Reusable analytical datasets |
ROUND() |
Formatting calculated percentages |
The project begins by examining the COVID deaths dataset and ordering records by location and date.
SELECT *
FROM CovidAnalysis..CovidDeaths
ORDER BY 3, 4;A more focused view of the data includes:
SELECT
Location,
Date,
total_cases,
new_cases,
total_deaths,
population
FROM CovidAnalysis..CovidDeaths
ORDER BY 1, 2;This provides an initial understanding of the available variables and their structure.
The analysis calculates the percentage of reported cases that resulted in death.
SELECT
Location,
Date,
total_cases,
total_deaths,
(total_deaths / total_cases) * 100 AS DeathPercentage
FROM CovidAnalysis..CovidDeaths
ORDER BY 1, 2;Death Percentage
Total Deaths / Total Cases ร 100
This helps assess the relationship between reported infections and reported deaths over time.
The project also examines the death percentage specifically for the United States.
SELECT
Location,
Date,
Population,
total_cases,
total_deaths,
(total_deaths / total_cases) * 100 AS DeathPercentage
FROM CovidAnalysis..CovidDeaths
WHERE location LIKE '%states%'
ORDER BY 1, 2;This provides a time-based view of the reported likelihood of death among confirmed cases.
The project identifies countries with the highest recorded infection levels relative to their populations.
SELECT
Location,
Population,
MAX(total_cases) AS HighestInfectionCount,
MAX(total_cases / population) * 100 AS PercentPopulationInfected
FROM CovidAnalysis..CovidDeaths
GROUP BY Location, Population
ORDER BY PercentPopulationInfected DESC;- Highest infection count
- Percentage of population infected
This allows countries to be compared based on the relative population impact of COVID-19.
The analysis identifies countries with the highest recorded total deaths.
SELECT
Location,
MAX(CAST(total_deaths AS INT)) AS TotalDeathCount
FROM CovidAnalysis..CovidDeaths
WHERE continent IS NOT NULL
GROUP BY Location
ORDER BY TotalDeathCount DESC;This focuses on countries with valid continent classifications to avoid non-country aggregate records.
The project also aggregates the maximum recorded death count by continent.
SELECT
Continent,
MAX(CAST(total_deaths AS INT)) AS TotalDeathCount
FROM CovidAnalysis..CovidDeaths
WHERE continent IS NOT NULL
GROUP BY Continent
ORDER BY TotalDeathCount DESC;This provides a high-level comparison of COVID-19 mortality across continents.
Global daily cases and deaths are calculated by aggregating new cases and new deaths.
SELECT
Date,
SUM(new_cases) AS TotalCases,
SUM(CAST(new_deaths AS INT)) AS Total_Deaths,
SUM(CAST(new_deaths AS INT))
/ SUM(new_cases) * 100 AS DeathPercentage
FROM CovidAnalysis..CovidDeaths
WHERE continent IS NOT NULL
GROUP BY Date
ORDER BY 1, 2;This creates a global time series showing how COVID-19 cases and deaths evolved.
The project combines the COVID deaths and vaccination datasets to analyze vaccination progress.
SELECT
dea.continent,
dea.location,
dea.date,
dea.population,
vac.new_vaccinations
FROM CovidAnalysis..CovidDeaths dea
JOIN CovidAnalysis..CovidVaccination$ vac
ON dea.location = vac.location
AND dea.date = vac.date
WHERE dea.continent IS NOT NULL
ORDER BY 1, 2, 3;This demonstrates the use of a relational JOIN to combine datasets using both location and date.
A SQL window function is used to calculate cumulative vaccinations for each country.
SUM(
CONVERT(BIGINT, ISNULL(vac.new_vaccinations, 0))
) OVER (
PARTITION BY dea.location
ORDER BY dea.date
ROWS UNBOUNDED PRECEDING
) AS RollingPeopleVaccinatedThis produces a running total of vaccinations over time.
The cumulative vaccination figure is compared against population size to calculate vaccination coverage.
ROUND(
100.0 * RollingPeopleVaccinated / Population,
2
) AS PercentVaccinatedThe resulting metric provides an estimate of the cumulative vaccination percentage by country and date.
A Common Table Expression (CTE) is used to organize the rolling vaccination calculation.
WITH PopvsVac AS
(
SELECT
dea.continent,
dea.location,
dea.date,
dea.population,
vac.new_vaccinations,
SUM(
CONVERT(BIGINT, ISNULL(vac.new_vaccinations, 0))
) OVER (
PARTITION BY dea.location
ORDER BY dea.date
ROWS UNBOUNDED PRECEDING
) AS RollingPeopleVaccinated
FROM CovidAnalysis..CovidDeaths dea
JOIN CovidAnalysis..CovidVaccination$ vac
ON dea.location = vac.location
AND dea.date = vac.date
WHERE dea.continent IS NOT NULL
)
SELECT
*,
ROUND(
100.0 * RollingPeopleVaccinated / Population,
2
) AS PercentVaccinated
FROM PopvsVac
ORDER BY Location, Date;The CTE makes the query easier to structure and allows the rolling calculation to be reused in the final query.
The project also demonstrates the use of a SQL Server temporary table:
DROP TABLE IF EXISTS #PercentPopulationVaccinated;
CREATE TABLE #PercentPopulationVaccinated
(
Continent NVARCHAR(255),
Location NVARCHAR(255),
Date DATETIME,
Population NUMERIC,
RollingPeopleVaccinated BIGINT
);The calculated vaccination data is inserted into the temporary table and subsequently queried.
This demonstrates how intermediate analytical results can be stored and processed within a SQL session.
A reusable SQL view is created to store the vaccination analysis.
CREATE VIEW PercentPopulationVaccinated AS
SELECT
dea.continent,
dea.location,
dea.date,
dea.population,
SUM(
CONVERT(BIGINT, ISNULL(vac.new_vaccinations, 0))
) OVER (
PARTITION BY dea.location
ORDER BY dea.date
ROWS UNBOUNDED PRECEDING
) AS RollingPeopleVaccinated
FROM CovidAnalysis..CovidDeaths dea
JOIN CovidAnalysis..CovidVaccination$ vac
ON dea.location = vac.location
AND dea.date = vac.date
WHERE dea.continent IS NOT NULL;The view can then be queried directly:
SELECT
*,
ROUND(
100.0 * RollingPeopleVaccinated / Population,
2
) AS PercentPopulationVaccinated
FROM PercentPopulationVaccinated
ORDER BY Location, Date;This creates a reusable analytical dataset that can be connected to visualization or reporting tools.
The project focuses on several major areas:
| Analysis | Key Metric |
|---|---|
| Case Fatality | Death Percentage |
| Infection Impact | % Population Infected |
| Country Mortality | Total Death Count |
| Continental Mortality | Death Count by Continent |
| Global Trends | Daily Cases & Deaths |
| Vaccination | New Vaccinations |
| Cumulative Vaccination | Rolling Vaccinations |
| Vaccination Coverage | % Population Vaccinated |
This analysis can be used to investigate questions such as:
- What percentage of reported COVID-19 cases resulted in death?
- Which countries experienced the highest infection rates relative to population?
- Which countries recorded the highest death counts?
- Which continents experienced the highest mortality?
- How did global COVID-19 cases change over time?
- How did vaccination programs progress across countries?
- What percentage of a country's population had received vaccinations over time?
- How can SQL window functions be used to calculate cumulative metrics?
- How can SQL views support downstream visualization and reporting?
This project demonstrates practical SQL Server skills including:
SELECT
WHERE
ORDER BYSUM()
MAX()
GROUP BYCAST()
CONVERT()
ISNULL()
ROUND()JOINWITH ... AS
OVER()
PARTITION BY
ROWS UNBOUNDED PRECEDINGCREATE TABLE
CREATE VIEW
DROP TABLE
DROP VIEWThe calculated metrics should be interpreted carefully.
The analysis is based on reported COVID-19 data. Differences in testing, reporting practices, definitions, and data completeness can affect comparisons between countries.
The calculated:
Deaths / Cases ร 100
is a reported case-fatality-style measure and should not automatically be interpreted as the true probability that an infected individual will die.
The cumulative vaccination calculation is based on the available new_vaccinations field. Depending on the source data, vaccination counts may represent doses rather than unique individuals.
COVID-19-SQL-Analysis/
โ
โโโ README.md
โ
โโโ sql/
โ โโโ covid_analysis.sql
โ
โโโ data/
โ โโโ CovidDeaths.csv
โ โโโ CovidVaccinations.csv
โ
โโโ outputs/
โโโ visualization_data.csv
Use Microsoft SQL Server and a SQL client such as SQL Server Management Studio (SSMS).
Create a database named:
CovidAnalysis
Import the COVID deaths and vaccination datasets into the database.
The queries expect tables similar to:
CovidAnalysis..CovidDeaths
CovidAnalysis..CovidVaccination$
Open the project SQL file in SQL Server Management Studio.
Execute the queries sequentially to:
- Explore the data.
- Analyze cases and deaths.
- Calculate infection rates.
- Compare countries and continents.
- Analyze global trends.
- Join vaccination data.
- Calculate rolling vaccinations.
- Calculate vaccination percentages.
- Create temporary analytical tables.
- Create the final visualization view.
Potential extensions include:
- Connect the SQL view to Power BI or Tableau.
- Build a COVID-19 interactive dashboard.
- Add vaccination trend visualizations.
- Analyze vaccination rates by continent.
- Compare infection and vaccination rates.
- Add population-adjusted death rates.
- Analyze new cases using rolling averages.
- Add monthly and yearly trend analysis.
- Improve handling of missing and inconsistent data.
- Add stored procedures for reusable analysis.
- Create automated ETL pipelines for updated COVID-19 data.
This project demonstrates how SQL Server can be used to transform raw COVID-19 datasets into meaningful analytical insights.
Through a combination of data exploration, aggregation, joins, window functions, CTEs, temporary tables, and SQL views, the project analyzes the global impact of COVID-19 and vaccination progress.
The project also provides a strong foundation for connecting SQL-based analysis to tools such as Power BI or Tableau for interactive data visualization and business intelligence.
Kingsley Agbo
Tools: SQL Server ยท SSMS ยท SQL ยท CTEs ยท Window Functions ยท Temporary Tables ยท Views ยท Data Analysis