Back to articles list Articles Cookbook
4 minutes read

The Most Useless SQL Queries (and What you Should do Instead)

They run. They return data. But they’re pointless. Here’s what not to write in SQL and what to do instead.

Some SQL queries run just fine – but that doesn’t mean they’re doing anything useful.

In this article, we’ll walk through real examples of SQL queries that are valid, harmless-looking, and completely pointless. They waste resources, hide insights, or just add noise. For each one, you’ll see what’s wrong, and how to write a smarter alternative instead.

Want to practice writing better queries right away? Try the SQL Practice track on LearnSQL.com – it’s built to help you turn theory into skill, with 12 courses and over 1000 interactive exercises.

Let’s clean up the junk and write queries that actually get the job done.

1. Selecting Everything Without a Purpose

  • The query:


    SELECT * 
    FROM orders;
    
  • Why it’s useless: pulls unnecessary data, slows down queries, and burdens the database.
  • What to do instead: specify only the required columns to improve performance.
  • Better query:

    SELECT order_id, customer_id, total_amount
    FROM orders;
    

2. Counting Everything Without Filtering

  • The query:

    SELECT COUNT(*) 
    FROM orders;
    
  • Why it’s useless: often returns misleading insights if not filtered.
  • What to do instead: use WHERE conditions or GROUP BY for better accuracy.
  • Better query:

    SELECT COUNT(*) 
    FROM orders 
    WHERE status = 'completed';
    

3. Order By Default When Order Doesn’t Matter

  • The query:

    SELECT total_amount 
    FROM orders 
    ORDER BY customer_id;
    
  • Why it’s useless: adds processing time without benefiting analysis.
  • What to do instead: use ORDER BY intentionally, e.g., for reporting or visualization.
  • Better query: do not use ORDER BY unless necessary;

    SELECT total_amount 
    	FROM orders;
    
  • 4. Sorting Without a Limit

    This one is similar to the previous one.

  • The query:

    SELECT order_id, customer_id, total_amount 
    FROM orders 
    ORDER BY created_at DESC;
    
  • Why it’s useless: sorting large datasets without constraints is inefficient.
  • What to do instead: if possible, use LIMIT or TOP.
  • Better query:

    SELECT order_id, customer_id, total_amount 
    	FROM orders 
    	ORDER BY created_at 
    	DESC LIMIT 10;
    
  • 5. Grouping Without Meaningful Labels

  • The query:

    SELECT customer_id, COUNT(*) 
    FROM orders 
    GROUP BY customer_id;
    
  • Why it’s useless: IDs alone don’t provide context – the results are hard to interpret and not actionable.
  • What to do instead: make sure to include a meaningful label like name or email.
  • Better query:

    SELECT o.customer_id, c.email, COUNT(*) AS total_orders 
    FROM orders o 
    JOIN customers c 
    ON o.customer_id = c.id 
    GROUP BY o.customer_id, c.email;
    
  • 6. Using HAVING Instead of WHERE for Filtering Rows

  • The query:

    SELECT order_id, customer_id, total_amount 
    FROM orders 
    HAVING total_amount > 100;
    
  • Why it’s useless: HAVING is meant for aggregate filtering, not row filtering. While it technically works, it will distract the reader of the query from understanding your intention.
  • What to do instead: use WHERE before aggregation.
  • Better query:

    SELECT order_id, customer_id, total_amount 
    	FROM orders 
    	WHERE total_amount > 100;
    
  • 7. Filtering on Computed Columns Without Indexing

  • The query:

    	SELECT order_id, customer_id, total_amount 
    FROM orders 
    WHERE YEAR(created_at) = 2023;
    
  • Why it’s useless: prevents index usage, causing full table scans.
  • What to do instead: use range-based filtering to leverage indexes.
  • Better query:

    	SELECT order_id, customer_id, total_amount 
    	FROM orders 
    	WHERE created_at >= '2023-01-01' AND created_at < '2024-01-01';
    
  • 8. Using Subqueries Instead of Joins

  • The query:

    SELECT order_id, customer_id, total_amount  
    FROM orders  
    WHERE customer_id IN (SELECT customer_id FROM blacklisted_customers);
    
  • Why it’s useless: can lead to slow performance compared to JOINs.
  • What to do instead: use an INNER JOIN or LEFT JOIN.
  • Better query:

    	SELECT o.order_id, o.customer_id, o.total_amount  
    	FROM orders o  
    	JOIN blacklisted_customers b ON o.customer_id = b.customer_id;
    
  • 9. Self-Joining Instead of Using Window Functions

  • The query:

    SELECT
      o1.customer_id,
      o1.order_id,
    COUNT(*) AS row_num  
    FROM orders o1
    JOIN orders o2
      ON o1.customer_id = o2.customer_id
      AND o1.order_date >= o2.order_date
    GROUP BY o1.customer_id, o1.order_id;
    
  • Why it’s useless: causes unnecessary complexity and duplication.
  • What to do instead: use window functions like ROW_NUMBER(), RANK(), or LAG().
  • Better query:

    SELECT 
      customer_id, 
      order_id,  
      ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date) AS row_num  
    FROM orders;
    
  • Write Smarter SQL, not Just Valid SQL

    Just because a query runs doesn’t mean it’s helping. Avoiding these common traps will make your SQL faster, cleaner, and way more useful.

    If you want to keep practicing the right way to write queries, check out the SQL Practice track on LearnSQL.com. It’s packed with hands-on exercises that help you sharpen your skills by doing – not just reading.