Writing SQL ยท Chapter 6
Working with columns
SELECT does more than pick columns: it can also compute new ones, rename them, add constants and remove duplicates. This chapter covers these operations.
Selecting every column
The star * selects every column of the table named in the FROM:
-- The star selects every column of the product table
SELECT *
FROM productQuestion 6.1
Display every column of the customer table.
Your answer
-- Question 6.1: write your query here
SELECT Show the solution
SELECT *
FROM customerColumn names with a space
When a column name contains a space or a special character, like VolKilo (COPA), it must be written in double quotes:
SELECT CustomerID, ProductID, "VolKilo (COPA)"
FROM perform21Putting spaces in column names is nonetheless bad practice. They force you to add quotes everywhere, which makes queries heavier and multiplies mistakes. And each DBMS has its own syntax for them, which makes code less portable:
-- SQL Server: square brackets
SELECT [Creation Date], [Customer Name] FROM Orders;
-- PostgreSQL, Oracle, DuckDB: double quotes
SELECT "Creation Date", "Customer Name" FROM Orders;
-- MySQL: backticks
SELECT `Creation Date`, `Customer Name` FROM Orders;Question 6.2
Display the CustomerID, ProductID, VolKilo (COPA), NOS (COPA) and COGS (COPA) columns of the perform21 table.
Your answer
-- Question 6.2: write your query here
SELECT Show the solution
SELECT CustomerID, ProductID, "VolKilo (COPA)", "NOS (COPA)", "COGS (COPA)"
FROM perform21The last three columns contain a space and brackets: they go in double quotes.
Computing a new column
SELECT can display the result of a calculation on existing columns, with the operators +, -, *, /.
Imagine the scale that weighs orders is badly calibrated and takes 5 kg off every weighing. To correct it, add 5 kg to each volume:
SELECT CustomerID, ProductID, "VolKilo (COPA)" + 5
FROM perform21The new column is named after its calculation, which is hard to read. The keyword AS gives it a name, called an alias:
SELECT CustomerID, ProductID, "VolKilo (COPA)" + 5 AS corrected_volume
FROM perform21Question 6.3
Display CustomerID, ProductID, NOS (COPA), COGS (COPA) and a new column margin that recomputes the gross margin from revenue and cost.
Reminder: NOS (COPA) is revenue (positive) and COGS (COPA) is the purchase cost, recorded as a negative number.
Your answer
-- Question 6.3: write your query here
SELECT Show the solution
SELECT CustomerID, ProductID, "NOS (COPA)", "COGS (COPA)",
"NOS (COPA)" + "COGS (COPA)" AS margin
FROM perform21Since the cost is already negative, you add it to revenue: 127,652 + (โ51,445) = 76,207. Writing "NOS (COPA)" - "COGS (COPA)" would add the cost instead of subtracting it. The result matches the GP (COPA) column, which lets you check your calculation. Always look at a column's sign before computing with it.
Question 6.4
Display CustomerID, ProductID, Date and the margin rate of each row of perform21, as a percentage rounded to one decimal place, in a column named margin_rate. The margin rate is the gross margin divided by revenue. To round, use ROUND(value, 1).
Your answer
-- Question 6.4: write your query here
SELECT Show the solution
SELECT CustomerID, ProductID, Date,
ROUND("GP (COPA)" / "NOS (COPA)" * 100, 1) AS margin_rate
FROM perform21Divide the margin by revenue, multiply by 100 to get a percentage, then round.
Watch out for division by zero: perform21 has no rows at 0, but later years do. Depending on the DBMS, dividing by zero raises an error (PostgreSQL, SQL Server) or returns infinity and NaN (DuckDB). Chapter 13 shows how to guard against it with NULLIF.
Adding a constant
A column can hold the same value on every row. Just write the value in the SELECT: in single quotes for text, without quotes for a number.
SELECT *, 'FR' AS country_code
FROM customerThis trick is useful to label data before stacking it with other data (we will see this in the chapter on UNION).
Question 6.5
Display CustomerID and CustomerName from the customer table, plus a type column equal to 'customer' on every row.
Your answer
-- Question 6.5: write your query here
SELECT Show the solution
SELECT CustomerID, CustomerName, 'customer' AS type
FROM customerConcatenating text
The || operator joins pieces of text end to end. Use it to build a label or a key:
SELECT CustomerName || ' (' || Channel || ')' AS label
FROM customerQuestion 6.6
A row of perform21 stands for one customer, one product and one month. Build a row identifier named row_id by joining CustomerID, ProductID and Date, separated by dashes (for example 1-1-2021-08-01). Display this identifier and the NOS (COPA) column.
Your answer
-- Question 6.6: write your query here
SELECT Show the solution
SELECT CustomerID || '-' || ProductID || '-' || Date AS row_id,
"NOS (COPA)"
FROM perform21DuckDB automatically converts numbers and dates to text to concatenate them. This kind of identifier, built from the columns that make a row unique, is called a composite key: we will come back to it in the chapter on data quality.
Removing duplicates with DISTINCT
DISTINCT, placed right after SELECT, removes duplicate rows from the result.
-- One row per sale: 21,736 rows
SELECT ProductID
FROM perform21-- One row per distinct product: 520 rows
SELECT DISTINCT ProductID
FROM perform21With several columns, DISTINCT compares whole rows: it keeps each distinct combination.
-- The distinct customer-product pairs: 2,845 rows
SELECT DISTINCT CustomerID, ProductID
FROM perform21Question 6.7
Display the list of distinct months in perform21 (the Date column).
Your answer
-- Question 6.7: write your query here
SELECT Show the solution
SELECT DISTINCT Date
FROM perform21There are 12, from January to December 2021: each month is represented by its first day.
Question 6.8
Display the list of distinct categories and sub-categories in the product table (each combination once).
Your answer
-- Question 6.8: write your query here
SELECT Show the solution
SELECT DISTINCT Category, SubCategory
FROM productDISTINCT applies to the combination of both columns: the Capsules category appears several times, once per sub-category.