Cleaning Data in PostgreSQL Databases
Cleaning Data in PostgreSQL Databases
--------------------------------+-------+-----------------------------------------+--------------+-----
name | grade | inspection_type | census_tract | ...
... | ... | ... | ... | ...
--------------------------------+-------+-----------------------------------------+--------------+-----
EMPANADAS MONUMENTAL | B | Cycle Inspection / Re-inspection | 26900 | ...
... | ... | ... | ... | ...
ALPHONSO'S PIZZERIA & TRATTORIA | A | Cycle Inspection / Initial Inspection | 202 | ...
EMPANADAS MONUMENTAL | B | Cycle Inspection / Re-inspection | 26900 | ...
THE SPARROW TAVERN | A | Cycle Inspection / Initial Inspection | 12500 | ...
ALPHONSO'S PIZZERIA & TRATTORIA | A | Cycle Inspection / Initial Inspection | 202 | ...
BURGER KING | A | Cycle Inspection / Re-inspection | 86400 | ...
THE SPARROW TAVERN | A | Cycle Inspection / Initial Inspection | 12500 | ...
ASTORIA PIZZA | B | Cycle Inspection / Re-inspection | 6300 | ...
BURGER KING | A | Cycle Inspection / Re-inspection | 86400 | ...
... | ... | ... | ... | ...
ASTORIA PIZZA | B | Cycle Inspection / Re-inspection | 6300 | ...
... | ... | ... | ... | ...
name
inspection_type
census_tract
name | grade | inspection_type | census_tract | ... INITCAP(input_string)
--------------------------------+-------+-----------------------------------------+--------------+-----
... | ... | ... | ... | ...
EMPANADAS MONUMENTAL | B | Cycle Inspection / Re-inspection | 26900 | ... SELECT INITCAP('HELLO FRIEND!');
ALPHONSO'S PIZZERIA & TRATTORIA | A | Cycle Inspection / Initial Inspection | 202 | ...
THE SPARROW TAVERN | A | Cycle Inspection / Initial Inspection | 12500 | ...
BURGER KING | A | Cycle Inspection / Re-inspection | 86400 | ...
ASTORIA PIZZA | B | Cycle Inspection / Re-inspection | 6300 | ... Hello Friend!
... | ... | ... | ... | ...
SELECT
*
SELECT
FROM
*
restaurant_inspection
FROM
WHERE nta LIKE 'QN%'
restaurant_inspection
AND nta NOT LIKE 'QN__';
WHERE nta LIKE 'QN%';
LIKE
SELECT
camis, name, inspection_date, score, nta
FROM
restaurant_inspection
WHERE nta SIMILAR TO 'QN%' AND nta NOT SIMILAR TO 'QN__';
SELECT
camis, name, inspection_date, score, nta
FROM
restaurant_inspection
\d \d\d\d
WHERE nta SIMILAR TO 'QN%' AND nta NOT SIMILAR TO 'QN__';
? x\d?
SELECT
camis, name, inspection_date, score, nta
+ \d+
FROM
restaurant_inspection
* \d* WHERE
nta NOT SIMILAR TO '[A-Z][A-Z]\d\d';
[] [a-z]
camis | name | inspection_date | score | nta
---------+--------------------+-----------------+-------+------
41659848 | LA BRISA DEL CIBAO | 01/30/2018 | 20 | Q26
41104041 | THE SPARROW TAVERN | 09/17/2019 | 13 | QN723
121 Fontainebleau Drive
SOUNDEX(input_string)
sd_pair | sd_pear
--------+---------
SELECT P600 | P600
SOUNDEX('Fountainbleau') as sd1,
SOUNDEX('Fontainebleau') as sd2,
SELECT DIFFERENCE('pair', 'pear') AS diff;
SOUNDEX('Fontaineblue') as sd3;
diff
sd1 | sd2 | sd3
----
-----+------+------
4
F535 | F535 | F535
B300 | B230 HOT POT UNDER DE' TREE | Manhattan | 2839 | FREDERICK DOUGLAS BOULEVARD
LIDO | Manhattan | 2168 | FREDERICK DOUGLAS BOULEVARD
MESS HALL | Manhattan | 2194 | FRDRCK DGLS BLVD
VINATERIA | Manhattan | 2211 | FREDERICK DOUGLAS BOULEVARD
SELECT DIFFERENCE('bout', 'bought') AS diff
diff
----
2
name | boro | building | street | sd_street UPDATE
-----------------------+-----------+----------+------------------------------+----------- table_name
ATOMIC WINGS | Manhattan | 2090 | FREDERICK DOUGLASS BOULEVARD | F636 SET
BARAKA BUFFET | Manhattan | 2546 | FREDERICK DOUGLASS BOULEVARD | F636 column_name = value
CHOCOLAT | Manhattan | 2217 | FREDERICK DOUGLASS BOULEVARD | F636
WHERE
ESO | Manhattan | 2906 | FREDERICK DOUGLASS BOULEVARD | F636
condition
HOP HOUSE HARLEM | Manhattan | 2224 | FREDERICK DOUGLASS BOULEVARD | F636
HOT POT UNDER DE' TREE | Manhattan | 2839 | FREDERICK DOUGLAS BOULEVARD | F636
LIDO | Manhattan | 2168 | FREDERICK DOUGLAS BOULEVARD | F636 UPDATE
MESS HALL | Manhattan | 2194 | FRDRCK DGLS BLVD | F636 restaurant_inspection
VINATERIA | Manhattan | 2211 | FREDERICK DOUGLAS BOULEVARD | F636 SET
street = 'Frederick Douglass Boulevard'
SELECT WHERE
name, boro, building, street DIFFERENCE(street, 'Frederick Douglass Boulevard') = 4;
FROM
restaurant_inspections
UPDATE 10
WHERE
DIFFERENCE(street, 'Frederick Douglass Boulevard') = 4;
... | name | score | inspection_type | ...
----+------------------+-------+----------------------------------------------+-----
... | ... | ... | ... | ...
... | SCHNIPPERS | 27 | Cycle Inspection / Initial Inspection | ...
... | ATOMIC WINGS | | Administrative Miscellaneous / Re-inspection | ...
... | WING LING | 44 | Cycle Inspection / Initial Inspection | ...
... | JUAN VALDEZ CAFE | 24 | Cycle Inspection / Initial Inspection | ...
... | FULTON GRAND | 22 | Cycle Inspection / Initial Inspection | ...
... | ... | ... | ... | ...
NULL
''
... | name | score | inspection_type | ...
----+------------------+-------+----------------------------------------------+-----
... | ... | ... | ... | ...
... | SCHNIPPERS | 27 | Cycle Inspection / Initial Inspection | ...
... | ATOMIC WINGS | | Administrative Miscellaneous / Re-inspection | ...
... | WING LING | 44 | Cycle Inspection / Initial Inspection | ...
... | JUAN VALDEZ CAFE | 24 | Cycle Inspection / Initial Inspection | ...
... | FULTON GRAND | 22 | Cycle Inspection / Initial Inspection | ...
... | ... | ... | ... | ...
SELECT
*
FROM
restaurant_inspection
WHERE
score IS NULL;
SELECT
COUNT(*)
FROM
restaurant_inspection
WHERE
score IS NULL;
SELECT inspection_type | count
inspection_type, --------------------------------------------------+-------
COUNT(*) as count Administrative Miscellaneous / Initial Inspection | 104
FROM Smoke-Free Air Act / Initial Inspection | 29
restaurant_inspection Calorie Posting / Initial Inspection | 22
WHERE Administrative Miscellaneous / Re-inspection | 22
score IS NULL Trans Fat / Initial Inspection | 18
GROUP BY Smoke-Free Air Act / Re-inspection | 7
inspection_type Trans Fat / Re-inspection | 3
ORDER BY
count DESC;
0
ROW_NUMBER() OVER() SELECT
camis,
name,
ROW_NUMBER() OVER(
boro,
PARTITION BY
inspection_date,
col1, col2, ...
ORDER BY violation_code,
colA, colB, ... ROW_NUMBER() OVER(
) PARTITION BY
camis,
name,
camis | name | boro | inspection_date | violation_code | row_number | ...
boro,
---------+--------------------------+-----------+-----------------+----------------+------------+----
inspection_date,
... | ... | ... | ... | ... | ... | ...
violation_code
41659848 | LA BRISA DEL CIBAO | Queens | 01/30/2018 | 04L | 1 | ...
41659848 | LA BRISA DEL CIBAO | Queens | 01/30/2018 | 04L | 2 | ... ) - 1 AS duplicate
40961447 | MESON SEVILLA RESTAURANT | Manhattan | 03/19/2019 | 10F | 1 | ... FROM
41630358 | FAY DA BAKERY | Queens | 03/07/2019 | 06E | 1 | ... restaurant_inspection;
... | ... | ... | ... | ... | ... |...
SELECT
camis, name, boro, inspection_date, violation_code,
ROW_NUMBER() OVER(
PARTITION BY camis, name, boro, inspection_date, violation_code camis | name | inspection_date | violation_code | score | ...
) - 1 AS duplicate --------+-----------------+-----------------+----------------+-------+-----
FROM
... | ... | ... | ... | ... | ...
restaurant_inspection;
50038736 | DON NICO'S | 03/29/2018 | 09B | 26 | ...
50038736 | DON NICO'S | 03/29/2018 | 09B | 18 | ...
camis | name | boro | inspection_date | violation_code | duplicate | ...
---------+--------------------------+-----------+-----------------+----------------+------------+----
50033304 | ASTORIA PIZZA | 12/18/2019 | 02B | 16 | ...
... | ... | ... | ... | ... | ... | ... 50081658 | IRVING FARMS | 12/13/2018 | 06F | 9 | ...
40961447 | MESON SEVILLA RESTAURANT | Manhattan | 03/19/2019 | 10F | 0 | ... 50033733 | ICHIBANTEI | 02/12/2019 | 10B | 12 | ...
41630358 | FAY DA BAKERY | Queens | 03/07/2019 | 06E | 0 | ...
... | ... | ... | ... | ... | ...
41630358 | FAY DA BAKERY | Queens | 03/07/2019 | 06E | 1 | ...
41630358 | FAY DA BAKERY | Queens | 03/07/2019 | 06E | 2 | ...
41659848 | LA BRISA DEL CIBAO | Queens | 01/30/2018 | 04L | 0 | ...
41659848 | LA BRISA DEL CIBAO | Queens | 01/30/2018 | 04L | 1 | ...
... | ... | ... | ... | ... | ... | ...
AVERAGE() MIN() MAX()
camis | name | inspection_date | violation_code | score | ...
---------+-----------------+-----------------+----------------+-------+-----
SELECT
camis, ... | ... | ... | ... | ... | ...
name,
50038736 | DON NICO'S | 03/29/2018 | 09B | 22.0 | ...
inspection_date,
violation_code, ... | ... | ... | ... | ... | ...
AVG(score) AS score
FROM
restaurant_inspection
GROUP BY
camis,
name,
inspection_date,
violation_code
HAVING
COUNT(*) > 1;
camis | name | inspection_date | score | inspection_type | ...
---------+---------------------------------+-----------------+-------+---------------------------------------+----- SELECT
... | ... | ... | ... | ... | ...
camis,
41659848 | LA BRISA DEL CIBAO | 01/30/2018 | 20 | Cycle Inspection / Initial Inspection | ...
40961447 | MESON SEVILLA RESTAURANT | 03/19/2019 | 50 | Cycle Inspection / Initial Inspection | ... name,
50063071 | WA BAR | 05/23/2018 | 15 | Cycle Inspection / Initial Inspection | ...
50034992 | EMPANADAS MONUMENTAL | 06/21/2019 | 17 | Cycle Inspection / Re-inspection | ... inspection_date,
50095871 | ALPHONSO'S PIZZERIA & TRATTORIA | 01/16/2020 | 10 | Cycle Inspection / Initial Inspection | ...
... | ... | ... | ... | ... | ...
score
FROM
camis | name | inspection_date | score | inspection_type | ...
restaurant_inspection
---------+------------------------------+-----------------+-------+-------------------------------------------------+-----
... | ... | ... | ... | ... | ... WHERE
41104041 | THE SPARROW TAVERN | 09/17/2019 | 13 | Cycle Inspection / Initial Inspection | ...
50016937 | BURGER KING | 09/14/2018 | 12 | Cycle Inspection / Re-inspection | ... score NOT SIMILAR TO '\d+';
50066469 | DARBAR'S CHICKEN & RIBS | 08/07/2017 | 11 | Pre-permit (Operational) / Reopening Inspection | ...
41195691 | F & J PINE RESTAURANT | 05/02/2019 | 26 | Cycle Inspection / Initial Inspection | ...
50015706 | EL RINCONCITO DE LOS SABORES | 12/18/2019 | A | Cycle Inspection / Initial Inspection | ...
... | ... | ... | ... | ... | ...
? x\d? SELECT
camis,
+ \d+
name,
* \d* inspection_date,
score
[] [a-z]
FROM
restaurant_inspection
WHERE
score < 0;
SELECT SELECT
camis, camis,
name, name,
inspection_date, inspection_date,
score score
FROM FROM
restaurant_inspection restaurant_inspection
WHERE WHERE
score <= -1; score < 0 OR
score > 100;
SELECT
ALTER TABLE restaurant_inspection
camis, name, inspection_date, score
ALTER COLUMN score TYPE SMALLINT USING score::smallint; FROM
restaurant_inspection
WHERE
SELECT
score NOT BETWEEN 0 AND 100;
camis,
name,
camis | name | inspection_date | score
inspection_date, ---------+-------------------------+-----------------+-------
score ... | ... | ... | ...
41702543 | TROPICAL GRILL | 05/14/2018 | 109
FROM
50074058 | PAD THAI | 08/01/2018 | 101
restaurant_inspection 50085349 | DON CHILE MEXICAN GRILL | 12/04/2018 | 124
WHERE 50092932 | ENERGY JUICE BAR | 06/24/2019 | 102
41702543 | TROPICAL GRILL | 05/14/2018 | 109
score < 0 OR
50034653 | KAI FAN ASIAN CUISINE | 12/06/2019 | -1
score >= 101; ... | ... | ... | ...
SELECT
camis,
score
grade,
camis | name | score | ... A grade_date,
---------+---------------------------------+--------+-----
... | ... | ... | ... score,
41659848 | LA BRISA DEL CIBAO | 20 | ...
40961447 | MESON SEVILLA RESTAURANT | 50 | ... inspection_type
50063071 | WA BAR | 15 | ...
... | ... | ... | ...
FROM
restaurant_inspection
A B C WHERE
grade = 'A' AND
score NOT BETWEEN 0 AND 13;
A
A B C 0
B SELECT
camis, grade, grade_date, score, inspection_type FROM
SELECT restaurant_inspection
camis, WHERE
grade, (grade = 'A' OR grade = 'B' OR grade = 'C') AND
grade_date, inspection_type LIKE '%Reopening%';
score,
inspection_type
camis | grade | grade_date | score | inspection_type | ...
FROM
---------+-------+------------+-------+-------------------------------------------------+-----
restaurant_inspection
... | ... | ... | ... | ... | ...
WHERE
50005784 | C | 05/29/2019 | 14 | Cycle Inspection / Reopening Inspection | ...
grade = 'B' AND
50091190 | C | 07/12/2019 | 7 | Pre-permit (Operational) / Reopening Inspection | ...
score NOT BETWEEN 14 AND 27;
40395023 | C | 09/13/2019 | 8 | Cycle Inspection / Reopening Inspection | ...
50037770 | C | 10/26/2018 | 11 | Cycle Inspection / Reopening Inspection | ...
camis | grade | grade_date | score | inspection_type 50036406 | C | 07/10/2018 | 20 | Cycle Inspection / Reopening Inspection | ...
---------+-------+------------+-------+---------------------------------- ... | ... | ... | ... | ... | ...
50034653 | B | 12/06/2019 | -1 | Cycle Inspection / Re-inspection
camis | name | score | inspection_type | ...
---------+---------------------------------+-------+---------------------------------------+-----
... | ... | ... | ... | ...
41659848 | LA BRISA DEL CIBAO | 20 | Cycle Inspection / Initial Inspection | ...
40961447 | MESON SEVILLA RESTAURANT | 50 | Cycle Inspection / Initial Inspection | ...
50063071 | WA BAR | 15 | Cycle Inspection / Initial Inspection | ...
50095871 | ALPHONSO'S PIZZERIA & TRATTORIA | 10 | Cycle Inspection / Initial Inspection | ...
41104041 | THE SPARROW TAVERN | 13 | Cycle Inspection / Initial Inspection | ...
... | ... | ... | ... | ...
SELECT column_name | data_type SELECT
column_name, -----------------+----------- column_name,
data_type camis | bigint data_type
FROM name | text FROM
value::type
SELECT
camis,
MAX(score::int) - MIN(score::int) AS diff
FROM
restaurant_inspection
WHERE
score IS NOT NULL
GROUP BY
camis
ORDER BY
diff DESC
camis | name | inspection_date | grade_date | ... DATE TEXT
---------+----------------------+-----------------+------------+----
... | ... | ... | ... | ...
50034992 | EMPANADAS MONUMENTAL | 06/21/2019 | 06/21/2019 | ...
50095871 | ALPHONSO'S PIZZERIA | 01/16/2020 | 01/16/2020 | ...
41104041 | THE SPARROW TAVERN | 09/17/2019 | 09/17/2019 | ...
50016937 | BURGER KING | 09/14/2018 | 09/14/2018 | ...
50033304 | ASTORIA PIZZA | 12/18/2019 | 12/18/2019 | ...
... | ... | ... | ... | ...
DATE(string_date)
string_date DATE
DATE('2019-12-01') DATE
--------+----------------------------------+-----------------+------------+----- camis,
name,
... | ... | ... | ... | ...
TO_CHAR(
41659848 | LA BRISA DEL CIBAO | 2018-01-30 | - | ...
TO_CHAR('2012-04-03', YYYY-DD-MM) inspection_date::date,
40961447 | MESON SEVILLA RESTAURANT | 2019-03-19 | - | ...
'MM/DD/YY'
50063071 | WA BAR | 2018-05-23 | - | ... ) AS inspection_date
TO_CHAR(date_value, format_string)
50034992 | EMPANADAS MONUMENTAL | 2019-06-21 | 2019-06-21 | ... FROM
50095871 | ALPHONSO'S PIZZERIA & TRATTORIA | 2020-01-16 | 2020-01-16 | ... restaurant_inspection;
TO_CHAR(date_value, format)
TO_DATE('2012', 'YYYY') TO_DATE('09/2012', 'MM/YYYY')
DATE DATE
DD Day
DATE DATE
YYYY MM
2012 09/2012
DD Day
inspection_datetime TIMESTAMP
TIMESTAMP TO_TIMESTAMP(ts_string, format)
name | boro | building | street | zip_code | ... CONCAT('data', 'cleaning', 'is', 'fun') datacleaningisfun
-----------------------------+--------+----------+------------------+----------+-----
... | ... | ... | ... | ... | ... CONCAT('data', ' ', 'cleaning', ' ', 'is', ' ', 'fun') data cleaning is fun
DARBAR'S CHICKEN & RIBS | Queens | 12609 | LIBERTY AVE | 11419 | ...
F & J PINE RESTAURANT | Bronx | 1913 | BRONXDALE AVENUE | 10462 | ...
EL RINCONCITO DE LOS SABORES | Queens | 13933 | 89TH AVE | 11435 | ...
DON NICO'S | Queens | 9014 | 161ST ST | 11432 | ...
ASTORIA PIZZA | Queens | 3204B | 30TH AVE | 11102 | ...
... | ... | ... | ... | ... | ...
Restaurant Name
Street Address
Boro, NY Zipcode
name | mailing_address
-----------------+-----------------------
SCHNIPPERS | SCHNIPPERS +
| 570 LEXINGTON AVENUE +
| Manhattan, NY 10022
ATOMIC WINGS |
WING LING | WING LING +
| 159B EAST 170 STREET+
| Bronx, NY 10452
JUAN VALDEZ CAFE | JUAN VALDEZ CAFE +
| 140 EAST 57 STREET +
| Manhattan, NY 10022
FULTON GRAND | FULTON GRAND +
| 1011 FULTON STREET +
| Brooklyn, NY 11238
camis | inspection_date | violation | ...
---------+-----------------+-------------------------------------------------+-----
... | ... | ... | ...
50038736 | 03/29/2018 | 09B Thawing procedures | ...
50033304 | 12/18/2019 | 02B Hot food item not held at or above 140º ... | ...
50081658 | 12/13/2018 | 06F Wiping cloths soiled or not stored in sa... | ...
50033733 | 02/12/2019 | 10B Plumbing not properly installed or maint... | ...
40559634 | 08/22/2017 | 04N Filth flies or food/refuse/sewage-associ... | ...
... | ... | ... | ...
STRPOS(source_string, search_string)
SELECT
STRPOS('09B Thawing procedures', ' '); SELECT
STRPOS('09B Thawing procedures', '?');
4
0
SUBSTRING(source_string FROM start_pos FOR num_chars)
SELECT
STRPOS('09B Thawing procedures', ' ');
SELECT
SUBSTRING(
'09B Thawing procedures'
FROM 1
FOR STRPOS('09B Thawing procedures', ' ') - 1
); SELECT
STRPOS('09B Thawing procedures', ' ') + 1;
09B
5
LENGTH('09B Thawing procedures') 22
LENGTH('Thawing procedures') 18
LENGTH(string) INTEGER
SELECT LENGTH('hello')
SELECT SELECT
LENGTH('09B Thawing procedures') - SUBSTRING(
Thawing procedures
SELECT
camis | inspection_date | violation | ...
camis,
inspection_date,
---------+-----------------+-------------------------------------------------+-----
... | ... | ... | ...
SUBSTRING( 50038736 | 03/29/2018 | 09B Thawing procedures | ...
violation
50033304 | 12/18/2019 | 02B Hot food item not held at or above 140º ... | ...
FROM 1
FOR STRPOS(violation, ' ') - 1 50081658 | 12/13/2018 | 06F Wiping cloths soiled or not stored in sa... | ...
) AS violation_code, 50033733 | 02/12/2019 | 10B Plumbing not properly installed or maint... | ...
40559634 | 08/22/2017 | 04N Filth flies or food/refuse/sewage-associ... | ...
SUBSTRING(
violation ... | ... | ... | ...
FROM STRPOS(violation, ' ') + 1
FOR LENGTH(violation) - STRPOS(violation, ' ')
) AS violation_description
FROM
restaurant_inspection;
' / '
sub_inspection_type | count
-----------------------------+-------
Reopening Inspection | 56
Re-inspection | 1333
Initial Inspection | 3488
Second Compliance Inspection | 2
Compliance Inspection | 27
50048685 | KENNEDY FRIED CHICKEN | Cycle Inspection | Re-inspection | ... 41628459 | KFC | Chicken | ...
50043003 | BANGIA | Korean | ...
50058910 | HUNGER PANG | Pre-permit (Operational) | Re-inspection | ...
41418978 | BAGEL EXPRESS III | Bagels | ...
50047834 | SUBWAY | Smoke-Free Air Act | Re-inspection | ... 41418978 | BAGEL EXPRESS III | Pretzels | ...
... | ... | ... | ... | ... ... | ... | ... | ...
SELECT
summary_column,
AGG(agg_column) FILTER (WHERE agg_column = PIVOT_VALUE_1) AS "pivot_column_1",
AGG(agg_column) FILTER (WHERE agg_column = PIVOT_VALUE_2) AS "pivot_column_2",
...
AGG(agg_column) FILTER (WHERE agg_column = PIVOT_VALUE_N) AS "pivot_column_N"
FROM
source_table
GROUP BY
summary_column;
SELECT inspection_type | A | B | C | N | P | Z
inspection_type, --------------------------------------------------+------+-----+----+----+----+----
COUNT(grade) FILTER (WHERE grade = 'A') AS "A",
Cycle Inspection / Re-inspection | 723 | 270 | 93 | 0 | 0 | 29
COUNT(grade) FILTER (WHERE grade = 'B') AS "B",
Cycle Inspection / Initial Inspection | 1063 | 0 | 0 | 0 | 0 | 0
COUNT(grade) FILTER (WHERE grade = 'C') AS "C",
COUNT(grade) FILTER (WHERE grade = 'N') AS "N", Pre-permit (Operational) / Reopening Inspection | 0 | 0 | 3 | 0 | 3 | 1
COUNT(grade) FILTER (WHERE grade = 'P') AS "P", Cycle Inspection / Reopening Inspection | 0 | 0 | 8 | 0 | 26 | 3
COUNT(grade) FILTER (WHERE grade = 'Z') AS "Z" Pre-permit (Non-operational) / Initial Inspection | 0 | 0 | 0 | 4 | 0 | 0
FROM Pre-permit (Operational) / Initial Inspection | 119 | 0 | 0 | 17 | 0 | 0
restaurant_inspections
Pre-permit (Operational) / Re-inspection | 79 | 49 | 13 | 0 | 0 | 9
WHERE
grade IS NOT NULL
GROUP BY
inspection_type;