Subquery Kinds

Column, Row, and Table Subqueries

A column subquery returns one column and feeds IN, ANY and ALL (IN, ANY, ALL, and EXISTS). A row subquery returns one row, compared with a row constructor: (customer_id, status) = (SELECT customer_id, status FROM orders WHERE id = 1) finds Ana's shipped orders 1 and 4. A table subquery returns rows and columns, and a tuple IN tests whole rows:

Each product's best review with a tuple IN, and a refused LIMITSQL
SELECT id, product_id, rating FROM reviews
WHERE product_id IN (1, 2) AND (product_id, rating) IN
      (SELECT product_id, MAX(rating) FROM reviews GROUP BY product_id);
SELECT sku FROM products
WHERE id IN (SELECT product_id FROM order_items ORDER BY quantity DESC LIMIT 2);
Output
+----+------------+--------+
| id | product_id | rating |
+----+------------+--------+
|  1 |          1 |      5 |
|  2 |          2 |      4 |
+----+------------+--------+
2 rows in set (0.001 sec)
ERROR 1235 (42000): This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME
  subquery'

This greatest-per-group query drops Elif's 4 for product 1 (review 6) and would keep ties. Rows compare left to right, and (1, 2) = (1, NULL) is unknown. For the refused LIMIT, wrap the query in a derived table, IN (SELECT product_id FROM (SELECT ... LIMIT 2) AS t), which returns the mug and the sticker pack. Since 8.0.19, IN (TABLE wishlist) also works.