[
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nquery = \"SELECT * FROM users WHERE name = '\" + name + \"'\"\ncursor.execute(query)\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: String concatenation in query**\n\n**Fix:**\n```sql\n# Use parameterized queries\ncursor.execute(\"SELECT * FROM users WHERE name = ?\", (name,))\n# Or with named parameters:\ncursor.execute(\"SELECT * FROM users WHERE name = :name\", {\"name\": name})\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "string_concatenation_in_query"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\ncursor.execute(f\"SELECT * FROM orders WHERE user_id = {user_id}\")\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: f-string in SQL query**\n\n**Fix:**\n```sql\ncursor.execute(\"SELECT * FROM orders WHERE user_id = ?\", (user_id,))\n# Never interpolate values into SQL strings\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "f-string_in_sql_query"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\ncursor.execute(\"SELECT * FROM users WHERE email = '{}'\".format(email))\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: format() in SQL query**\n\n**Fix:**\n```sql\ncursor.execute(\"SELECT * FROM users WHERE email = ?\", (email,))\n# .format() is just as vulnerable as f-strings\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "format()_in_sql_query"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\ncolumn = request.args.get('sort')\ncursor.execute(f\"SELECT * FROM products ORDER BY {column}\")\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Dynamic ORDER BY injection**\n\n**Fix:**\n```sql\nALLOWED_COLUMNS = {'name', 'price', 'created_at'}\ncolumn = request.args.get('sort', 'name')\nif column not in ALLOWED_COLUMNS:\n    column = 'name'\ncursor.execute(f\"SELECT * FROM products ORDER BY {column}\")\n# Allowlist column names for dynamic SQL parts\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "dynamic_order_by_injection"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\ntable = request.args.get('table')\ncursor.execute(f\"SELECT * FROM {table}\")\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Dynamic table name injection**\n\n**Fix:**\n```sql\nALLOWED_TABLES = {'users', 'products', 'orders'}\ntable = request.args.get('table', 'users')\nif table not in ALLOWED_TABLES:\n    raise ValueError('Invalid table')\ncursor.execute(f\"SELECT * FROM {table}\")\n# Allowlist identifiers that can't be parameterized\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "dynamic_table_name_injection"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nINSERT INTO users (username, password) VALUES ('alice', 'password123')\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Storing passwords in plain text**\n\n**Fix:**\n```sql\nimport bcrypt\nhash = bcrypt.hashpw(b'password123', bcrypt.gensalt())\ncursor.execute(\"INSERT INTO users (username, password_hash) VALUES (?, ?)\", ('alice', hash.decode()))\n# Always hash passwords before storing\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "storing_passwords_in_plain_text"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nterm = request.args.get('q')\ncursor.execute(f\"SELECT name FROM products WHERE name LIKE '%{term}%'\")\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: UNION injection via search**\n\n**Fix:**\n```sql\nterm = request.args.get('q', '')\ncursor.execute(\"SELECT name FROM products WHERE name LIKE ?\", ('%' + term + '%',))\n# Parameterized LIKE queries prevent UNION injection\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "union_injection_via_search"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n# User profile stored in DB, then used later\ncursor.execute(f\"INSERT INTO settings (value) VALUES ('{user_input}')\")\n# Later...\ncursor.execute(f\"UPDATE config SET val = (SELECT value FROM settings WHERE id=1)\")\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Second-order injection**\n\n**Fix:**\n```sql\ncursor.execute(\"INSERT INTO settings (value) VALUES (?)\", (user_input,))\n# Second-order: stored data used in SQL later\n# Defense: parameterize ALL queries, even with stored data\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "second-order_injection"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n# App connection\nDB_USER = app\nDB_PASS = supersecret\n# Connected as root/superuser\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Excessive database privileges**\n\n**Fix:**\n```sql\n# Principle of least privilege\nCREATE USER app_user WITH PASSWORD 'strong_password';\nGRANT SELECT, INSERT, UPDATE ON TABLE users TO app_user;\nGRANT SELECT ON TABLE orders TO app_user;\n-- Never connect as superuser from application code\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "excessive_database_privileges"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nquery = f\"SELECT * FROM users WHERE ssn = '{ssn}'\"\nlogger.info(f\"Running query: {query}\")\ncursor.execute(query)\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Sensitive data in logs**\n\n**Fix:**\n```sql\ncursor.execute(\"SELECT * FROM users WHERE ssn = ?\", (ssn,))\nlogger.info(\"User lookup completed\")  # No sensitive data in logs\n# Never log query strings with parameters\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "sensitive_data_in_logs"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\ntry:\n    cursor.execute(query)\nexcept psycopg2.Error as e:\n    return f\"Database error: {e}\", 500\n# Exposes query structure and schema\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: SQL dump in error messages**\n\n**Fix:**\n```sql\ntry:\n    cursor.execute(query)\nexcept psycopg2.Error as e:\n    logger.error(\"DB error: %s\", e, exc_info=True)\n    return \"Internal server error\", 500\n# Log details server-side, show generic message to user\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "sql_dump_in_error_messages"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n# Multi-tenant app - no tenant isolation\nSELECT * FROM orders WHERE status = 'pending'\n# Returns ALL tenants' orders\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Missing row-level security**\n\n**Fix:**\n```sql\nSELECT * FROM orders WHERE tenant_id = current_setting('app.tenant_id')::int AND status = 'pending'\n# Or use PostgreSQL Row Level Security:\nALTER TABLE orders ENABLE ROW LEVEL SECURITY;\nCREATE POLICY tenant_isolation ON orders USING (tenant_id = current_setting('app.tenant_id')::int);\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "missing_row-level_security"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nrows = [(name, email) for name, email in users]\nqueries = [f\"INSERT INTO users (name, email) VALUES ('{n}', '{e}')\" for n, e in rows]\nfor q in queries:\n    cursor.execute(q)\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Batch insert without parameterization**\n\n**Fix:**\n```sql\ncursor.executemany(\"INSERT INTO users (name, email) VALUES (?, ?)\", users)\n# executemany is safe and efficient\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "batch_insert_without_parameterization"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nDELETE FROM sessions\n# Missing WHERE - deletes all sessions\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: DROP/DELETE without WHERE**\n\n**Fix:**\n```sql\nDELETE FROM sessions WHERE expires_at < NOW()\n# Always include WHERE on destructive operations\n# In migrations: wrap in transaction so you can rollback\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "drop/delete_without_where"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n# Client sends raw SQL for custom reports\ndef run_report(sql):\n    cursor.execute(sql)\n    return cursor.fetchall()\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Trusting client-side SQL**\n\n**Fix:**\n```sql\n# Never execute client-provided SQL\n# Instead: build queries from validated parameters\ndef run_report(filters):\n    query = \"SELECT * FROM reports\"\n    conditions = []\n    if filters.get('date_from'):\n        conditions.append(\"created_at >= ?\")\n    params = [f for f in filters.values() if f]\n    if conditions:\n        query += \" WHERE \" + \" AND \".join(conditions)\n    cursor.execute(query, params)\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "trusting_client-side_sql"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM users WHERE status = 'active'\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: SELECT * instead of specific columns**\n\n**Fix:**\n```sql\nSELECT id, username, email FROM users WHERE status = 'active'\n# Only fetch what you need:\n# - Less data transfer\n# - Enables covering index optimization\n# - Breaking changes when schema changes\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "select_*_instead_of_specific_columns"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM logs ORDER BY created_at DESC\n# Table has 10M+ rows\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Missing LIMIT on unbounded query**\n\n**Fix:**\n```sql\nSELECT id, message, created_at FROM logs ORDER BY created_at DESC LIMIT 100\n# Always bound result sets for large tables\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "missing_limit_on_unbounded_query"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM orders WHERE YEAR(created_at) = 2024\n# created_at is indexed but YEAR() prevents index use\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Function on indexed column in WHERE**\n\n**Fix:**\n```sql\nSELECT * FROM orders WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01'\n# Range on raw column uses the index\n# Functions on columns prevent index usage\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "function_on_indexed_column_in_where"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM users WHERE LEFT(email, 3) = 'abc'\n# email has an index but LEFT() prevents its use\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Function on indexed column (LEFT)**\n\n**Fix:**\n```sql\nSELECT * FROM users WHERE email LIKE 'abc%'\n# LIKE with leading wildcard-free prefix uses index\n# Avoid wrapping indexed columns in functions\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "function_on_indexed_column_(left)"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM users WHERE phone = 1234567890\n-- phone is VARCHAR but compared to integer\n-- Causes full table scan due to type conversion\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Implicit type conversion**\n\n**Fix:**\n```sql\nSELECT * FROM users WHERE phone = '1234567890'\n-- Match the column type in your comparison\n-- Implicit casts prevent index usage\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "implicit_type_conversion"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM products WHERE name LIKE '%widget%'\n# Cannot use index - leading % prevents seek\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: LIKE with leading wildcard**\n\n**Fix:**\n```sql\nSELECT * FROM products WHERE name LIKE 'widget%'\n-- Leading wildcard prevents index use\n-- For full-text search, use: FULLTEXT index, pg_trgm, or dedicated search engine\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "like_with_leading_wildcard"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- In application code:\nusers = db.query(\"SELECT * FROM users\")\nfor user in users:\n    orders = db.query(f\"SELECT * FROM orders WHERE user_id = {user.id}\")\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: N+1 query pattern**\n\n**Fix:**\n```sql\n-- Single query with JOIN:\nSELECT u.id, u.name, o.id as order_id, o.total\nFROM users u\nLEFT JOIN orders o ON o.user_id = u.id\n-- Or fetch all needed orders in one query:\nSELECT * FROM orders WHERE user_id IN (1, 2, 3, ...)\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "n+1_query_pattern"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT u.name,\n  (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id)\nFROM users u\n-- Runs COUNT(*) once per user row\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Subquery in SELECT (correlated)**\n\n**Fix:**\n```sql\nSELECT u.name, COUNT(o.id) as order_count\nFROM users u\nLEFT JOIN orders o ON o.user_id = u.id\nGROUP BY u.id, u.name\n-- JOIN + GROUP BY is one pass instead of N queries\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "subquery_in_select_(correlated)"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT department, AVG(salary) as avg_sal\nFROM employees\nGROUP BY department\nHAVING AVG(salary) > 50000\n-- HAVING filters after grouping\n-- If filtering rows before aggregation, use WHERE\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: HAVING instead of WHERE for filtering**\n\n**Fix:**\n```sql\nSELECT department, AVG(salary) as avg_sal\nFROM employees\nWHERE hire_date >= '2020-01-01'\nGROUP BY department\nHAVING AVG(salary) > 50000\n-- WHERE filters rows before aggregation (cheaper)\n-- HAVING only for post-aggregation filters\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "having_instead_of_where_for_filtering"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM users WHERE email = 'a@b.com' OR phone = '123'\n-- May cause full table scan if both columns indexed separately\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: OR conditions preventing index use**\n\n**Fix:**\n```sql\nSELECT * FROM users WHERE email = 'a@b.com'\nUNION\nSELECT * FROM users WHERE phone = '123'\n-- UNION of two index seeks > OR causing full scan\n-- Check EXPLAIN to verify query plan\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "or_conditions_preventing_index_use"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT user_id, COUNT(*) FROM events GROUP BY user_id\n-- Full table scan + sort on 10M+ row table\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: COUNT(*) with GROUP BY on large table**\n\n**Fix:**\n```sql\nSELECT user_id, COUNT(*) FROM events GROUP BY user_id\n-- Consider:\n-- 1. Partial materialized view refreshed periodically\nREFRESH MATERIALIZED VIEW CONCURRENTLY user_event_counts;\n-- 2. Approximate with COUNT(DISTINCT) on sampled data\n-- 3. Time-bound: WHERE created_at >= '2024-01-01'\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "count(*)_with_group_by_on_large_table"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT DISTINCT u.name FROM users u JOIN orders o ON o.user_id = u.id\n-- DISTINCT adds sort/dedup step\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Using DISTINCT unnecessarily**\n\n**Fix:**\n```sql\nSELECT u.name FROM users u INNER JOIN orders o ON o.user_id = u.id\n-- Or: SELECT DISTINCT ON to deduplicate intentionally\n-- Check if JOIN already guarantees uniqueness\n-- DISTINCT = extra sort pass in the query plan\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "using_distinct_unnecessarily"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM users\nWHERE id IN (SELECT user_id FROM orders\n  WHERE id IN (SELECT order_id FROM payments WHERE amount > 100))\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Nested subqueries instead of JOIN**\n\n**Fix:**\n```sql\nSELECT DISTINCT u.*\nFROM users u\nJOIN orders o ON o.user_id = u.id\nJOIN payments p ON p.order_id = o.id\nWHERE p.amount > 100\n-- JOINs are more efficient than nested IN subqueries\n-- Optimizer can choose better join strategies\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "nested_subqueries_instead_of_join"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM users WHERE id NOT IN (SELECT user_id FROM banned)\n-- If banned.user_id contains NULL, entire NOT IN returns empty\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: NOT IN with NULL values**\n\n**Fix:**\n```sql\nSELECT * FROM users WHERE id NOT IN (SELECT user_id FROM banned WHERE user_id IS NOT NULL)\n-- Or better: NOT EXISTS\nSELECT * FROM users u\nWHERE NOT EXISTS (SELECT 1 FROM banned b WHERE b.user_id = u.id)\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "not_in_with_null_values"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM orders o\nJOIN users u ON u.id = o.user_id\nJOIN addresses a ON a.user_id = u.id\nJOIN payments p ON p.order_id = o.id\nJOIN items i ON i.order_id = o.id\nJOIN products pr ON pr.id = i.product_id\nJOIN categories c ON c.id = pr.category_id\nJOIN suppliers s ON s.id = pr.supplier_id\n-- 7 JOINs - likely too wide\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Excessive JOINs in single query**\n\n**Fix:**\n```sql\n-- Break into focused queries:\n-- Query 1: orders + users (list view)\n-- Query 2: order details (on-demand)\n-- Or use a denormalized view:\nCREATE VIEW order_summary AS\nSELECT o.id, o.total, u.name, u.email\nFROM orders o JOIN users u ON u.id = o.user_id\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "excessive_joins_in_single_query"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM config WHERE key = 'site_name'\n-- Run on every request, rarely changes\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Missing query result caching**\n\n**Fix:**\n```sql\n-- Cache infrequently-changing data in application:\n# Python example\nfrom functools import lru_cache\n\n@lru_cache(maxsize=256)\ndef get_config(key):\n    return db.query(\"SELECT value FROM config WHERE key = ?\", (key,))\n\n-- Or use Redis/memcached for distributed caching\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "missing_query_result_caching"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nrows = cursor.execute(\"SELECT * FROM transactions WHERE status != 'cancelled'\").fetchall()\n# Fetches cancelled rows too, filters in Python\n-- Actually bad: no WHERE clause at all\nrows = cursor.execute(\"SELECT * FROM transactions\").fetchall()\nfiltered = [r for r in rows if r.status != 'cancelled']\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Fetching data then filtering in application**\n\n**Fix:**\n```sql\nrows = cursor.execute(\"SELECT id, amount, date FROM transactions WHERE status != 'cancelled'\").fetchall()\n-- Filter in database, not application\n-- Database has indexes, your app doesn't\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "fetching_data_then_filtering_in_application"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM products ORDER BY created_at DESC LIMIT 20 OFFSET 10000\n-- OFFSET 10000 scans and discards 10000 rows\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Pagination with OFFSET on large tables**\n\n**Fix:**\n```sql\nSELECT * FROM products\nWHERE created_at < '2024-01-15T10:30:00'  -- last seen timestamp\nORDER BY created_at DESC\nLIMIT 20\n-- Keyset pagination: use last-seen value instead of OFFSET\n-- O(1) vs O(n) for deep pagination\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "pagination_with_offset_on_large_tables"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE orders (\n  id SERIAL PRIMARY KEY,\n  user_id INT REFERENCES users(id)\n);\n-- user_id has no index\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Missing index on foreign key**\n\n**Fix:**\n```sql\nCREATE TABLE orders (\n  id SERIAL PRIMARY KEY,\n  user_id INT REFERENCES users(id)\n);\nCREATE INDEX idx_orders_user_id ON orders(user_id);\n-- Foreign keys are commonly queried/joined\n-- Always index them\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "missing_index_on_foreign_key"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE INDEX idx_users_email ON users(email);\nCREATE INDEX idx_users_status ON users(status);\n-- Query: SELECT * FROM users WHERE status = 'active' AND email LIKE 'a%'\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Single-column index when composite needed**\n\n**Fix:**\n```sql\nCREATE INDEX idx_users_status_email ON users(status, email);\n-- Composite index: most selective filter first\n-- Single index covers both conditions\n-- Leading column (status) used for equality, second for range\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "single-column_index_when_composite_needed"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE INDEX idx_events ON events(user_id, created_at);\n-- Most queries filter by date range, then group by user\nSELECT * FROM events WHERE created_at > '2024-01-01' GROUP BY user_id\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Index with wrong column order**\n\n**Fix:**\n```sql\nCREATE INDEX idx_events_date_user ON events(created_at, user_id);\n-- Equality/equivalence columns first, then range\n-- For range queries: the ranged column should lead\n-- Columns after a range column aren't used for index seeks\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "index_with_wrong_column_order"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE INDEX idx1 ON users(first_name);\nCREATE INDEX idx2 ON users(last_name);\nCREATE INDEX idx3 ON users(email);\nCREATE INDEX idx4 ON users(phone);\nCREATE INDEX idx5 ON users(city);\nCREATE INDEX idx6 ON users(zip);\nCREATE INDEX idx7 ON users(created_at);\nCREATE INDEX idx8 ON users(updated_at);\n-- Every INSERT/UPDATE must maintain all indexes\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Over-indexing (too many indexes)**\n\n**Fix:**\n```sql\nCREATE INDEX idx_users_email ON users(email);\nCREATE INDEX idx_users_name ON users(last_name, first_name);\nCREATE INDEX idx_users_created ON users(created_at);\n-- Only index columns actually used in WHERE/JOIN/ORDER BY\n-- Each unused index slows writes and wastes space\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "over-indexing_(too_many_indexes)"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE INDEX idx_users_gender ON users(gender);\n-- gender: M/F/other - very few distinct values\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Index on low-cardinality column**\n\n**Fix:**\n```sql\n-- Low-cardinality columns rarely benefit from indexes\n-- Optimizer often chooses sequential scan\n-- Exception: when combined in composite index or with high selectivity filter\n-- Check: SELECT COUNT(DISTINCT gender)::float / COUNT(*) FROM users;  -- ratio near 0\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "index_on_low-cardinality_column"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE INDEX idx_orders_user ON orders(user_id);\n-- Query does index lookup then table lookup for each row\nSELECT user_id, total, status FROM orders WHERE user_id = 42\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Missing covering index**\n\n**Fix:**\n```sql\nCREATE INDEX idx_orders_covering ON orders(user_id) INCLUDE (total, status);\n-- Covering index: all needed columns in the index\n-- No table lookup needed (index-only scan)\n-- PostgreSQL: INCLUDE, MySQL: (user_id, total, status)\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "missing_covering_index"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE INDEX idx_lower_email ON users(LOWER(email));\n-- Query uses: WHERE email = 'A@B.COM' (case-sensitive)\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Index on expression not used in query**\n\n**Fix:**\n```sql\nCREATE INDEX idx_lower_email ON users(LOWER(email));\n-- Query must match the expression:\nSELECT * FROM users WHERE LOWER(email) = LOWER('A@B.COM')\n-- Or use a case-insensitive collation:\nCREATE TABLE users (email CITEXT);  -- PostgreSQL extension\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "index_on_expression_not_used_in_query"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE INDEX idx_orders_status ON orders(status);\n-- 95% of orders are 'completed', only filter active ones\nSELECT * FROM orders WHERE status = 'active'\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Partial index opportunity missed**\n\n**Fix:**\n```sql\nCREATE INDEX idx_orders_active ON orders(status) WHERE status = 'active';\n-- Partial index: only indexes rows where status = 'active'\n-- Smaller index, faster queries, less write overhead\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "partial_index_opportunity_missed"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE users (\n  id SERIAL PRIMARY KEY,\n  email VARCHAR(255),\n  CONSTRAINT unique_email UNIQUE (email)\n);\n-- UNIQUE creates an index implicitly\n-- But sometimes people forget UNIQUE entirely\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Unique constraint without index**\n\n**Fix:**\n```sql\nCREATE TABLE users (\n  id SERIAL PRIMARY KEY,\n  email VARCHAR(255) UNIQUE NOT NULL\n);\n-- UNIQUE constraint automatically creates a unique index\n-- Provides both data integrity and query optimization\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "unique_constraint_without_index"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- After millions of inserts and deletes, index is fragmented\n-- Performance degrades over time\nEXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 42\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Index fragmentation**\n\n**Fix:**\n```sql\n-- PostgreSQL:\nREINDEX INDEX CONCURRENTLY idx_orders_user_id;\n-- MySQL:\nALTER TABLE orders FORCE;\n-- Or schedule periodic maintenance:\nVACUUM ANALYZE orders;\n-- Monitor: pg_stat_user_indexes, sys.schema_index_statistics\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "index_fragmentation"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM products WHERE attributes->>'color' = 'red'\n-- attributes is JSONB, full scan on every query\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: JSON column query without GIN index**\n\n**Fix:**\n```sql\nCREATE INDEX idx_products_attrs ON products USING GIN (attributes);\n-- Or for specific key:\nCREATE INDEX idx_products_color ON products ((attributes->>'color'));\n-- GIN: good for containment (@>), key existence (?|)\n-- B-tree expression index: good for equality on specific key\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "json_column_query_without_gin_index"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM articles WHERE to_tsvector('english', body) @@ to_tsquery('english', 'database & optimization')\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Full-text search without index**\n\n**Fix:**\n```sql\nCREATE INDEX idx_articles_search ON articles USING GIN (to_tsvector('english', body));\n-- GIN index on tsvector for fast full-text search\n-- Or generated column for cleaner syntax:\nALTER TABLE articles ADD COLUMN search_vector TSVECTOR GENERATED ALWAYS AS (to_tsvector('english', body)) STORED;\nCREATE INDEX idx_articles_search ON articles USING GIN (search_vector);\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "full-text_search_without_index"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE INDEX idx_orders ON orders(user_id, status);\n-- Query filters user_id but status is NULL for new orders\nSELECT * FROM orders WHERE user_id = 42 AND status IS NULL\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Composite index with NULLs**\n\n**Fix:**\n```sql\nCREATE INDEX idx_orders ON orders(user_id, status);\n-- Index works for IS NULL (PostgreSQL)\n-- MySQL: NULL values are indexed normally in B-tree\n-- For high NULL ratio, consider partial index:\nCREATE INDEX idx_orders_new ON orders(user_id) WHERE status IS NULL;\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "composite_index_with_nulls"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- Index created for a one-off report, never used\nCREATE INDEX idx_users_last_login ON users(last_login);\n-- Every INSERT/UPDATE on users pays the cost\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Unused index consuming write overhead**\n\n**Fix:**\n```sql\n-- Check for unused indexes before removing:\nSELECT indexrelid::regclass, idx_scan, idx_tup_read, idx_tup_fetch\nFROM pg_stat_user_indexes\nWHERE idx_scan = 0\nORDER BY pg_relation_size(indexrelid) DESC;\n\n-- If truly unused:\nDROP INDEX idx_users_last_login;\n-- Rule: if an index hasn't been scanned in 90 days, drop it\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "unused_index_consuming_write_overhead"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE INDEX idx_geo ON locations(lat, lon);\n-- Query: find all locations within radius\nSELECT * FROM locations WHERE sqrt((lat - 40.7)::2 + (lon - -74)::2) < 0.1\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Wrong index type for the query**\n\n**Fix:**\n```sql\nCREATE EXTENSION IF NOT EXISTS postgis;\nALTER TABLE locations ADD COLUMN geom GEOMETRY(Point, 4326) GENERATED ALWAYS AS (ST_SetSRID(ST_MakePoint(lon, lat), 4326)) STORED;\nCREATE INDEX idx_locations_geo ON locations USING GIST (geom);\n-- Spatial queries need spatial indexes (GiST, SP-GiST)\n-- B-tree indexes can't handle geometric operations\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "wrong_index_type_for_the_query"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT u.name, o.total\nFROM users u, orders o\nWHERE u.id = o.user_id\n-- Implicit join syntax - easy to miss missing condition\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Cross join instead of inner join**\n\n**Fix:**\n```sql\nSELECT u.name, o.total\nFROM users u\nINNER JOIN orders o ON u.id = o.user_id\n-- Explicit JOIN syntax:\n-- Clearer intent, harder to accidentally omit ON clause\n-- Implicit syntax can cause accidental cross joins\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "cross_join_instead_of_inner_join"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT u.name, o.total\nFROM users u\nINNER JOIN orders o\n-- Missing ON clause - returns all combinations\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Cartesian product (missing JOIN condition)**\n\n**Fix:**\n```sql\nSELECT u.name, o.total\nFROM users u\nINNER JOIN orders o ON u.id = o.user_id\n-- Always verify JOIN has an ON condition\n-- Cartesian products: rows(users) * rows(orders)\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "cartesian_product_(missing_join_condition)"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT u.name, o.total\nFROM users u\nLEFT JOIN orders o ON o.user_id = u.id\n-- Only need users who have orders\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: LEFT JOIN used when INNER JOIN is correct**\n\n**Fix:**\n```sql\nSELECT u.name, o.total\nFROM users u\nINNER JOIN orders o ON o.user_id = u.id\n-- INNER JOIN is clearer and may be faster\n-- LEFT JOIN preserves non-matching rows with NULLs\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "left_join_used_when_inner_join_is_correct"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE employees (\n  id INT PRIMARY KEY,\n  name VARCHAR(100),\n  manager_id INT REFERENCES employees(id)\n);\n-- Find manager names\ne.name as employee, m.name as manager\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Self-join for hierarchical data**\n\n**Fix:**\n```sql\nSELECT e.name as employee, m.name as manager\nFROM employees e\nLEFT JOIN employees m ON e.manager_id = m.id\n-- Self-join: same table aliased differently\n-- LEFT JOIN: top-level managers have NULL manager\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "self-join_for_hierarchical_data"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM orders o\nJOIN users u ON u.id = o.user_id OR u.email = o.guest_email\n-- OR in ON clause can cause performance issues\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: JOIN with OR in ON clause**\n\n**Fix:**\n```sql\nSELECT * FROM orders o\nJOIN users u ON u.id = o.user_id\nWHERE o.guest_email IS NULL\nUNION ALL\nSELECT * FROM orders o\nJOIN users u ON u.email = o.guest_email\nWHERE o.guest_email IS NOT NULL\n-- Split OR into separate queries with UNION\n-- Each can use its own index efficiently\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "join_with_or_in_on_clause"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT u.name, COUNT(o.id)\nFROM users u\nJOIN orders o ON o.user_id = u.id\nJOIN payments p ON p.order_id = o.id\nGROUP BY u.id, u.name\n-- If multiple payments per order, orders are counted wrong\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Multiple JOINs creating duplicate rows**\n\n**Fix:**\n```sql\nSELECT u.name, COUNT(DISTINCT o.id)\nFROM users u\nJOIN orders o ON o.user_id = u.id\nJOIN payments p ON p.order_id = o.id\nGROUP BY u.id, u.name\n-- Or pre-aggregate:\nSELECT u.name, sub.order_count\nFROM users u\nJOIN (SELECT user_id, COUNT(DISTINCT id) as order_count FROM orders GROUP BY user_id) sub\n  ON sub.user_id = u.id\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "multiple_joins_creating_duplicate_rows"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE total > 100)\n-- IN subquery returns all matching IDs\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Using EXISTS instead of IN for existence check**\n\n**Fix:**\n```sql\nSELECT * FROM users u\nWHERE EXISTS (\n  SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.total > 100\n)\n-- EXISTS short-circuits on first match\n-- More efficient for large result sets\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "using_exists_instead_of_in_for_existence_check"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM users WHERE id NOT IN (SELECT user_id FROM orders)\n-- Returns users with no orders\n-- Fails silently if orders.user_id contains NULL\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: ANTI-JOIN pattern (NOT IN vs NOT EXISTS)**\n\n**Fix:**\n```sql\nSELECT * FROM users u\nWHERE NOT EXISTS (\n  SELECT 1 FROM orders o WHERE o.user_id = u.id\n)\n-- NOT EXISTS handles NULLs correctly\n-- Also: LEFT JOIN ... WHERE right_side IS NULL\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "anti-join_pattern_(not_in_vs_not_exists)"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT DISTINCT u.*\nFROM users u\nJOIN orders o ON o.user_id = u.id\nWHERE o.total > 100\n-- DISTINCT needed because multiple orders per user\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Semi-join for filtering with duplicates**\n\n**Fix:**\n```sql\nSELECT * FROM users u\nWHERE EXISTS (\n  SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.total > 100\n)\n-- Semi-join: returns each user once\n-- No DISTINCT needed, often faster\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "semi-join_for_filtering_with_duplicates"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- Get top order per user\nSELECT u.name, sub.total\nFROM users u\nCROSS JOIN LATERAL (\n  SELECT total FROM orders WHERE user_id = u.id ORDER BY total DESC LIMIT 1\n) sub\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Lateral join for per-row subquery**\n\n**Fix:**\n```sql\n-- PostgreSQL: LATERAL is the right tool here\n-- Alternatively with window function:\nSELECT name, total FROM (\n  SELECT u.name, o.total,\n    ROW_NUMBER() OVER (PARTITION BY u.id ORDER BY o.total DESC) as rn\n  FROM users u JOIN orders o ON o.user_id = u.id\n) sub WHERE rn = 1\n-- Window function avoids correlated subquery per row\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "lateral_join_for_per-row_subquery"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM orders o\nJOIN order_items i ON i.order_id = o.id\nJOIN products p ON p.slug = i.product_slug\n-- product_slug has no index\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: JOIN on non-indexed columns**\n\n**Fix:**\n```sql\n-- Add index on the join column:\nCREATE INDEX idx_items_product_slug ON order_items(product_slug);\nCREATE INDEX idx_products_slug ON products(slug);\n-- JOINs without indexes = nested loop with full scan\n-- Each row in the outer table scans the entire inner table\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "join_on_non-indexed_columns"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM users NATURAL JOIN orders\n-- Joins on all same-named columns\n-- Fragile: schema changes break silently\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Natural join (implicit column matching)**\n\n**Fix:**\n```sql\nSELECT u.name, o.total, o.created_at\nFROM users u\nINNER JOIN orders o ON o.user_id = u.id\n-- Always specify JOIN conditions explicitly\n-- NATURAL JOIN = hidden coupling between schemas\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "natural_join_(implicit_column_matching)"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- Transfer money without transaction\nUPDATE accounts SET balance = balance - 100 WHERE id = 1;\nUPDATE accounts SET balance = balance + 100 WHERE id = 2;\n-- If second fails, money disappears\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Missing transaction for multi-step operation**\n\n**Fix:**\n```sql\nBEGIN;\nUPDATE accounts SET balance = balance - 100 WHERE id = 1;\nUPDATE accounts SET balance = balance + 100 WHERE id = 2;\nCOMMIT;\n-- Transaction ensures atomicity:\n-- Either both succeed or both rollback\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "missing_transaction_for_multi-step_operation"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- Two sessions read balance simultaneously\nSELECT balance FROM accounts WHERE id = 1;  -- Both see 1000\nUPDATE accounts SET balance = 900 WHERE id = 1;  -- Session A deducts 100\nUPDATE accounts SET balance = 800 WHERE id = 1;  -- Session B deducts 200, overwrites A\n-- Result: 800 instead of 700\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Lost update race condition**\n\n**Fix:**\n```sql\nBEGIN;\nSELECT balance FROM accounts WHERE id = 1 FOR UPDATE;\n-- Read balance (locked)\n-- Calculate new balance\nUPDATE accounts SET balance = balance - 200 WHERE id = 1;\nCOMMIT;\n-- FOR UPDATE locks the row\n-- Session B waits for Session A to commit\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "lost_update_race_condition"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- Session A:\nBEGIN;\nUPDATE accounts SET balance = -500 WHERE id = 1;\n-- Session B (READ UNCOMMITTED):\nSELECT balance FROM accounts WHERE id = 1;  -- Sees -500\n-- Session A: ROLLBACK;\n-- Session B saw data that never existed\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Dirty read (uncommitted data)**\n\n**Fix:**\n```sql\nSET TRANSACTION ISOLATION LEVEL READ COMMITTED;\n-- Default in PostgreSQL and MySQL\n-- Only reads committed data\n-- For stronger guarantees use REPEATABLE READ or SERIALIZABLE\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "dirty_read_(uncommitted_data)"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- Session A:\nBEGIN;\nSELECT balance FROM accounts WHERE id = 1;  -- 1000\n-- Session B:\nUPDATE accounts SET balance = 500 WHERE id = 1;\nCOMMIT;\n-- Session A:\nSELECT balance FROM accounts WHERE id = 1;  -- 500 (changed!)\n-- Same query, different result within transaction\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Non-repeatable read**\n\n**Fix:**\n```sql\nSET TRANSACTION ISOLATION LEVEL REPEATABLE READ;\n-- Guarantees same result for repeated reads\n-- Uses multiversion concurrency control (MVCC)\n-- Trade-off: more locking, potential for serialization failures\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "non-repeatable_read"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- Session A:\nBEGIN;\nSELECT COUNT(*) FROM orders WHERE user_id = 42;  -- 5\n-- Session B:\nINSERT INTO orders (user_id, total) VALUES (42, 99.99);\nCOMMIT;\n-- Session A:\nSELECT COUNT(*) FROM orders WHERE user_id = 42;  -- 6 (phantom!)\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Phantom read**\n\n**Fix:**\n```sql\nSET TRANSACTION ISOLATION LEVEL SERIALIZABLE;\n-- Prevents phantom reads entirely\n-- Or use SELECT ... FOR UPDATE/SKIP LOCKED\n-- Or application-level idempotency to handle duplicates\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "phantom_read"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nBEGIN;\nUPDATE users SET status = 'processing' WHERE id = 42;\n-- ... complex processing that takes 30 seconds ...\nUPDATE users SET status = 'done' WHERE id = 42;\nCOMMIT;\n-- Row locked for 30 seconds, blocking other sessions\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Long-running transaction holding locks**\n\n**Fix:**\n```sql\nBEGIN;\nUPDATE users SET status = 'processing' WHERE id = 42;\nCOMMIT;\n-- Do processing outside transaction\nBEGIN;\nUPDATE users SET status = 'done' WHERE id = 42;\nCOMMIT;\n-- Keep transactions short\n-- Do CPU work between transactions, not inside them\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "long-running_transaction_holding_locks"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- Session A:\nBEGIN;\nUPDATE accounts SET balance = balance - 100 WHERE id = 1;\n-- Session B:\nBEGIN;\nUPDATE accounts SET balance = balance - 50 WHERE id = 2;\n-- Session A:\nUPDATE accounts SET balance = balance + 100 WHERE id = 2;  -- Waits\n-- Session B:\nUPDATE accounts SET balance = balance + 50 WHERE id = 1;  -- Deadlock!\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Deadlock**\n\n**Fix:**\n```sql\n-- Consistent lock ordering prevents deadlocks:\n-- Always lock lower ID first\nUPDATE accounts SET balance = balance - 100 WHERE id = LEAST(1, 2);\nUPDATE accounts SET balance = balance + 100 WHERE id = GREATEST(1, 2);\n-- Or let the database handle it: catch deadlock error and retry\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "deadlock"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nBEGIN;\nINSERT INTO orders (user_id, total) VALUES (42, 99.99);\nINSERT INTO order_items (order_id, product_id) VALUES (LASTVAL(), 1);\n-- If order_items fails, entire transaction rolls back\n-- Including the order insert that was fine\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Missing savepoint for partial rollback**\n\n**Fix:**\n```sql\nBEGIN;\nSAVEPOINT sp_order;\nINSERT INTO orders (user_id, total) VALUES (42, 99.99);\nSAVEPOINT sp_item;\nINSERT INTO order_items (order_id, product_id) VALUES (LASTVAL(), 1);\n-- If item insert fails:\nROLLBACK TO sp_item;\n-- Order is still there, retry item insert\nCOMMIT;\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "missing_savepoint_for_partial_rollback"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nINSERT INTO users (email) VALUES ('alice@example.com');\n-- Concurrent inserts can both pass application check\n-- Then one fails with duplicate key error\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Race condition on unique constraint**\n\n**Fix:**\n```sql\nINSERT INTO users (email) VALUES ('alice@example.com')\nON CONFLICT (email) DO NOTHING\nRETURNING id;\n-- Or handle the error:\ntry:\n    cursor.execute(\"INSERT INTO users (email) VALUES (?)\", (email,))\nexcept IntegrityError:\n    pass  # Already exists\n-- Database constraint is the source of truth\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "race_condition_on_unique_constraint"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- Worker picks next job\nSELECT * FROM jobs WHERE status = 'pending' LIMIT 1;\nUPDATE jobs SET status = 'running' WHERE id = selected_id;\n-- Race: multiple workers can pick the same job\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Skipped lock for queue pattern**\n\n**Fix:**\n```sql\n-- PostgreSQL: SKIP LOCKED\nSELECT * FROM jobs\nWHERE status = 'pending'\nORDER BY created_at\nLIMIT 1\nFOR UPDATE SKIP LOCKED;\n-- Atomically locks and retrieves\n-- Skips rows locked by other workers\n-- No race condition\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "skipped_lock_for_queue_pattern"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nBEGIN;\nUPDATE accounts SET balance = 0;\n-- Updates ALL accounts\n-- Meant to update one\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: UPDATE without WHERE on transaction**\n\n**Fix:**\n```sql\nBEGIN;\nUPDATE accounts SET balance = 0 WHERE id = 42;\n-- Always include WHERE on UPDATE/DELETE\n-- Consider: SELECT count first to verify scope\nSELECT COUNT(*) FROM accounts WHERE id = 42;\n-- Then UPDATE\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "update_without_where_on_transaction"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nUPDATE accounts SET balance = 500 WHERE id = 1;\n-- Overwrites concurrent changes\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Optimistic concurrency control**\n\n**Fix:**\n```sql\nUPDATE accounts\nSET balance = 500, version = version + 1\nWHERE id = 1 AND version = 3;\n-- Check affected rows:\n-- 0 rows = concurrent modification, retry\n-- 1 row = success\n-- Version column detects concurrent updates\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "optimistic_concurrency_control"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE orders (\n  id INT PRIMARY KEY,\n  user_id INT,\n  item1 VARCHAR(100),\n  item2 VARCHAR(100),\n  item3 VARCHAR(100)\n);\n-- Fixed number of items, repeating pattern\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Repeating groups in a single table**\n\n**Fix:**\n```sql\nCREATE TABLE orders (\n  id INT PRIMARY KEY,\n  user_id INT\n);\nCREATE TABLE order_items (\n  id INT PRIMARY KEY,\n  order_id INT REFERENCES orders(id),\n  product_name VARCHAR(100)\n);\n-- Normalize: separate repeating data into a child table\n-- No arbitrary limit on items per order\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "repeating_groups_in_a_single_table"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE orders (\n  id INT PRIMARY KEY,\n  subtotal DECIMAL(10,2),\n  tax DECIMAL(10,2),\n  total DECIMAL(10,2),\n  -- total = subtotal + tax, stored redundantly\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Storing computed data as column**\n\n**Fix:**\n```sql\nCREATE TABLE orders (\n  id INT PRIMARY KEY,\n  subtotal DECIMAL(10,2),\n  tax_rate DECIMAL(5,4)\n);\n-- Compute total when needed:\nSELECT id, subtotal, subtotal * tax_rate as tax, subtotal * (1 + tax_rate) as total\nFROM orders;\n-- Derived data = update anomalies\n-- Exception: denormalize for performance if justified\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "storing_computed_data_as_column"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE order_details (\n  order_id INT,\n  user_id INT,\n  user_email VARCHAR(255),\n  user_city VARCHAR(100),\n  -- user_email and user_city depend on user_id, not order_id\n  PRIMARY KEY (order_id)\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Transitive dependency (2NF violation)**\n\n**Fix:**\n```sql\nCREATE TABLE users (\n  id INT PRIMARY KEY,\n  email VARCHAR(255),\n  city VARCHAR(100)\n);\nCREATE TABLE orders (\n  id INT PRIMARY KEY,\n  user_id INT REFERENCES users(id)\n);\n-- 3NF: every non-key column depends on the whole key\n-- User attributes belong in users table\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "transitive_dependency_(2nf_violation)"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE orders (\n  id INT PRIMARY KEY,\n  items JSONB  -- [{product_id: 1, qty: 2}, ...]\n);\n-- Relational data stored as JSON in a column\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: JSON/array column for relational data**\n\n**Fix:**\n```sql\nCREATE TABLE orders (\n  id INT PRIMARY KEY\n);\nCREATE TABLE order_items (\n  order_id INT REFERENCES orders(id),\n  product_id INT REFERENCES products(id),\n  quantity INT,\n  PRIMARY KEY (order_id, product_id)\n);\n-- Normalize relational data into proper tables\n-- Use JSON for truly semi-structured data\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "json/array_column_for_relational_data"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE order_items (\n  order_id INT,\n  product_id INT,\n  quantity INT,\n  price DECIMAL(10,2),\n  PRIMARY KEY (order_id, product_id)\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Composite key as surrogate primary key**\n\n**Fix:**\n```sql\nCREATE TABLE order_items (\n  id SERIAL PRIMARY KEY,\n  order_id INT REFERENCES orders(id),\n  product_id INT REFERENCES products(id),\n  quantity INT,\n  price DECIMAL(10,2),\n  UNIQUE (order_id, product_id)\n);\n-- Surrogate PK simplifies foreign key references\n-- Unique constraint maintains data integrity\n-- Composite keys are fine if nothing references them\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "composite_key_as_surrogate_primary_key"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE orders (\n  id INT PRIMARY KEY,\n  user_id INT,\n  user_name VARCHAR(100),\n  user_email VARCHAR(255),\n  user_address TEXT\n  -- User data duplicated in every order\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Denormalized user data in orders**\n\n**Fix:**\n```sql\nCREATE TABLE orders (\n  id INT PRIMARY KEY,\n  user_id INT REFERENCES users(id)\n);\n-- Get user data via JOIN when needed\n-- If performance requires denormalization:\n-- Document it explicitly as intentional\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "denormalized_user_data_in_orders"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE users (\n  id INT PRIMARY KEY,\n  phone_numbers VARCHAR(255)  -- '555-1111,555-2222'\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Multi-value attribute in single column**\n\n**Fix:**\n```sql\nCREATE TABLE users (\n  id INT PRIMARY KEY\n);\nCREATE TABLE user_phones (\n  user_id INT REFERENCES users(id),\n  number VARCHAR(20),\n  type VARCHAR(20),  -- 'mobile', 'home'\n  PRIMARY KEY (user_id, number)\n);\n-- One value per cell = 1NF\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "multi-value_attribute_in_single_column"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE categories (\n  id INT PRIMARY KEY,\n  name VARCHAR(100),\n  parent_id INT,\n  grandparent_id INT  -- Hardcoded hierarchy depth\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Category hierarchy flat table**\n\n**Fix:**\n```sql\nCREATE TABLE categories (\n  id INT PRIMARY KEY,\n  name VARCHAR(100),\n  parent_id INT REFERENCES categories(id)\n);\n-- Adjacency list: any depth hierarchy\n-- For queries use recursive CTE:\nWITH RECURSIVE tree AS (\n  SELECT id, name, parent_id, 0 as depth FROM categories WHERE parent_id IS NULL\n  UNION ALL\n  SELECT c.id, c.name, c.parent_id, t.depth + 1\n  FROM categories c JOIN tree t ON c.parent_id = t.id\n)\nSELECT * FROM tree;\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "category_hierarchy_flat_table"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE images (\n  id INT PRIMARY KEY,\n  imageable_id INT,\n  imageable_type VARCHAR(50)  -- 'user' or 'product'\n);\n-- Single FK references multiple tables\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Polymorphic association (bad pattern)**\n\n**Fix:**\n```sql\nCREATE TABLE user_avatars (\n  user_id INT PRIMARY KEY REFERENCES users(id)\n);\nCREATE TABLE product_images (\n  product_id INT REFERENCES products(id),\n  image_url VARCHAR(255)\n);\n-- Separate junction tables per relationship\n-- Polymorphic associations: no FK constraint, hard to query\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "polymorphic_association_(bad_pattern)"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE products (\n  id INT PRIMARY KEY,\n  name VARCHAR(100),\n  -- Electronics-specific:\n  cpu VARCHAR(50),\n  ram_gb INT,\n  -- Clothing-specific:\n  size VARCHAR(10),\n  material VARCHAR(50),\n  -- Food-specific:\n  expiry_date DATE,\n  calories INT\n  -- Most rows have NULLs in most columns\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Wide table with sparse columns**\n\n**Fix:**\n```sql\nCREATE TABLE products (\n  id INT PRIMARY KEY,\n  name VARCHAR(100)\n);\nCREATE TABLE product_attributes (\n  product_id INT REFERENCES products(id),\n  attribute_key VARCHAR(50),\n  attribute_value TEXT,\n  PRIMARY KEY (product_id, attribute_key)\n);\n-- EAV pattern for truly variable attributes\n-- Or use JSONB column for flexible attributes\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "wide_table_with_sparse_columns"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT a.id, a.date, a.amount,\n  (SELECT SUM(b.amount) FROM daily_sales b WHERE b.date <= a.date) as running_total\nFROM daily_sales a\nORDER BY a.date\n-- Correlated subquery for each row\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Self-join for running total**\n\n**Fix:**\n```sql\nSELECT id, date, amount,\n  SUM(amount) OVER (ORDER BY date) as running_total\nFROM daily_sales\nORDER BY date\n-- Window function: single pass\n-- Much faster than correlated subquery\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "self-join_for_running_total"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT a.name, a.score,\n  (SELECT COUNT(*) FROM students b WHERE b.score > a.score) + 1 as rank\nFROM students a\nORDER BY a.score DESC\n-- O(n^2) self-join\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Ranking with self-join**\n\n**Fix:**\n```sql\nSELECT name, score,\n  RANK() OVER (ORDER BY score DESC) as rank\nFROM students\nORDER BY score DESC\n-- Window function: O(n log n) sort\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "ranking_with_self-join"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT name, department, salary,\n  RANK() OVER (ORDER BY salary DESC) as salary_rank\nFROM employees\n-- Ranks across entire company, not per department\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Missing PARTITION BY in window function**\n\n**Fix:**\n```sql\nSELECT name, department, salary,\n  RANK() OVER (PARTITION BY department ORDER BY salary DESC) as dept_salary_rank\nFROM employees\n-- PARTITION BY creates separate windows per group\n-- Without it, window spans all rows\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "missing_partition_by_in_window_function"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- Repeated subquery\nSELECT * FROM (\n  SELECT user_id, COUNT(*) as order_count FROM orders WHERE status = 'completed' GROUP BY user_id\n) sub\nWHERE order_count > 5\nORDER BY order_count DESC\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: CTE for reusability**\n\n**Fix:**\n```sql\nWITH completed_orders AS (\n  SELECT user_id, COUNT(*) as order_count\n  FROM orders WHERE status = 'completed'\n  GROUP BY user_id\n)\nSELECT * FROM completed_orders\nWHERE order_count > 5\nORDER BY order_count DESC\n-- CTE: readable, reusable\n-- Can reference CTE multiple times\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "cte_for_reusability"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- Find all descendants of a category\n-- Requires application-level recursive query building\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Recursive CTE for tree traversal**\n\n**Fix:**\n```sql\nWITH RECURSIVE descendants AS (\n  SELECT id, name, parent_id, 0 as depth\n  FROM categories WHERE id = 1\n  UNION ALL\n  SELECT c.id, c.name, c.parent_id, d.depth + 1\n  FROM categories c JOIN descendants d ON c.parent_id = d.id\n)\nSELECT * FROM descendants\n-- Recursive CTE handles arbitrary depth\n-- No application-level recursion needed\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "recursive_cte_for_tree_traversal"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nDELETE FROM users\nWHERE id NOT IN (\n  SELECT MIN(id) FROM users GROUP BY email\n);\n-- Keep one user per email, delete duplicates\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: ROW_NUMBER for deduplication**\n\n**Fix:**\n```sql\nWITH numbered AS (\n  SELECT id, ROW_NUMBER() OVER (PARTITION BY email ORDER BY id) as rn\n  FROM users\n)\nDELETE FROM users WHERE id IN (\n  SELECT id FROM numbered WHERE rn > 1\n);\n-- ROW_NUMBER: deterministic dedup\n-- ORDER BY id keeps the earliest record\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "row_number_for_deduplication"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT a.date, a.revenue,\n  a.revenue - (\n    SELECT b.revenue FROM daily_revenue b\n    WHERE b.date = (SELECT MAX(date) FROM daily_revenue WHERE date < a.date)\n  ) as day_over_day_change\nFROM daily_revenue a\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: LAG/LEAD for row comparison**\n\n**Fix:**\n```sql\nSELECT date, revenue,\n  revenue - LAG(revenue) OVER (ORDER BY date) as day_over_day_change,\n  revenue - LAG(revenue, 7) OVER (ORDER BY date) as week_over_week_change\nFROM daily_revenue\n-- LAG/LEAD: access previous/next rows\n-- Second arg = offset (7 = last week)\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "lag/lead_for_row_comparison"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT department, COUNT(*) as dept_count\nFROM employees GROUP BY department\n-- Separate query for total count\nSELECT COUNT(*) FROM employees\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Multiple aggregations with GROUP BY vs window**\n\n**Fix:**\n```sql\nSELECT department,\n  COUNT(*) as dept_count,\n  COUNT(*) OVER () as total_count,\n  ROUND(COUNT(*) * 100.0 / COUNT(*) OVER (), 1) as pct_of_total\nFROM employees\nGROUP BY department\n-- Window function on aggregated result\n-- Single query, no self-join needed\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "multiple_aggregations_with_group_by_vs_window"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT date, amount,\n  SUM(amount) OVER (ORDER BY date) as running_total\nFROM daily_sales\n-- Default frame: ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n-- But be explicit about frame boundaries\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Frame clause in window function**\n\n**Fix:**\n```sql\nSELECT date, amount,\n  SUM(amount) OVER (\n    ORDER BY date\n    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW\n  ) as running_total,\n  SUM(amount) OVER (\n    ORDER BY date\n    ROWS BETWEEN 6 PRECEDING AND CURRENT ROW\n  ) as rolling_7day\nFROM daily_sales\n-- Be explicit about frame boundaries\n-- ROWS vs RANGE matters with duplicate dates\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "frame_clause_in_window_function"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nWITH stats AS (\n  SELECT user_id, COUNT(*) as cnt, AVG(total) as avg_total\n  FROM orders GROUP BY user_id\n)\nSELECT * FROM stats WHERE cnt > 10\n-- CTE may be inlined and recomputed\n-- PostgreSQL: non-materialized CTEs are optimization fences\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Materialized CTE for large intermediate result**\n\n**Fix:**\n```sql\nWITH stats AS MATERIALIZED (\n  SELECT user_id, COUNT(*) as cnt, AVG(total) as avg_total\n  FROM orders GROUP BY user_id\n)\nSELECT * FROM stats WHERE cnt > 10\n-- MATERIALIZED hint (PostgreSQL 12+)\n-- Forces materialization when beneficial\n-- Let optimizer decide: omit hint for small CTEs\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "materialized_cte_for_large_intermediate_result"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE users (\n  email VARCHAR(255),\n  phone VARCHAR(500)  -- Phone doesn't need 500 chars\n  bio VARCHAR(10000)   -- Use TEXT for long content\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: VARCHAR(n) with arbitrary length**\n\n**Fix:**\n```sql\nCREATE TABLE users (\n  email VARCHAR(255) NOT NULL,\n  phone VARCHAR(20),    -- E.164 format: +1234567890\n  bio TEXT               -- TEXT has no length limit\n);\n-- Match column size to actual data\n-- TEXT and VARCHAR have no performance difference in PostgreSQL\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "varchar(n)_with_arbitrary_length"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE events (\n  id INT PRIMARY KEY,\n  event_date VARCHAR(10)  -- '2024-01-15'\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Storing dates as strings**\n\n**Fix:**\n```sql\nCREATE TABLE events (\n  id INT PRIMARY KEY,\n  event_date DATE NOT NULL\n);\n-- Use proper types:\n-- DATE for dates, TIMESTAMP for timestamps\n-- Enables date arithmetic, indexing, validation\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "storing_dates_as_strings"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE users (\n  id INT PRIMARY KEY,\n  email VARCHAR(255),       -- Can be NULL?\n  created_at TIMESTAMP,     -- Every row has a creation time\n  status VARCHAR(20),       -- Can be NULL?\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: NULL where NOT NULL is appropriate**\n\n**Fix:**\n```sql\nCREATE TABLE users (\n  id SERIAL PRIMARY KEY,\n  email VARCHAR(255) NOT NULL UNIQUE,\n  created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n  status VARCHAR(20) NOT NULL DEFAULT 'active'\n);\n-- NOT NULL + DEFAULT: enforce constraints at DB level\n-- Application-level validation is not enough\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "null_where_not_null_is_appropriate"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE users (\n  id INT PRIMARY KEY,\n  is_active TINYINT  -- 0 or 1\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Using TINYINT for boolean**\n\n**Fix:**\n```sql\nCREATE TABLE users (\n  id INT PRIMARY KEY,\n  is_active BOOLEAN NOT NULL DEFAULT TRUE\n);\n-- BOOLEAN: clear intent, proper type\n-- TINYINT: ambiguous (what about values > 1?)\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "using_tinyint_for_boolean"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE products (\n  id INT PRIMARY KEY,\n  price DECIMAL(10,2),\n  quantity INT\n  -- Negative prices or quantities possible\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Check constraint for business rules**\n\n**Fix:**\n```sql\nCREATE TABLE products (\n  id SERIAL PRIMARY KEY,\n  price DECIMAL(10,2) NOT NULL CHECK (price >= 0),\n  quantity INT NOT NULL DEFAULT 0 CHECK (quantity >= 0)\n);\n-- CHECK constraints enforce business rules at DB level\n-- Cannot be bypassed by application bugs\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "check_constraint_for_business_rules"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE events (\n  id INT PRIMARY KEY,\n  -- INT max: 2,147,483,647\n  -- High-traffic event log will overflow\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Using INTEGER for large IDs (overflow)**\n\n**Fix:**\n```sql\nCREATE TABLE events (\n  id BIGSERIAL PRIMARY KEY,\n  -- BIGINT max: 9,223,372,036,854,775,807\n  -- Won't overflow at reasonable insertion rates\n);\n-- Use BIGSERIAL/BIGINT for high-volume tables\n-- INT is fine for bounded datasets\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "using_integer_for_large_ids_(overflow)"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE orders (\n  id INT PRIMARY KEY,\n  status VARCHAR(20)  -- 'pending', 'shipped', 'delivered'\n  -- No enforcement - garbage values possible\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Enum stored as string without constraint**\n\n**Fix:**\n```sql\nCREATE TYPE order_status AS ENUM ('pending', 'shipped', 'delivered', 'cancelled');\nCREATE TABLE orders (\n  id SERIAL PRIMARY KEY,\n  status order_status NOT NULL DEFAULT 'pending'\n);\n-- PostgreSQL ENUM type enforces valid values\n-- Or CHECK constraint: CHECK (status IN ('pending', 'shipped', 'delivered'))\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "enum_stored_as_string_without_constraint"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE events (\n  id INT PRIMARY KEY,\n  created_at TIMESTAMP  -- No timezone info\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Timestamp without timezone**\n\n**Fix:**\n```sql\nCREATE TABLE events (\n  id SERIAL PRIMARY KEY,\n  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()\n);\n-- TIMESTAMPTZ stores UTC internally\n-- Converts on read based on session timezone\n-- Never use TIMESTAMP without timezone for application data\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "timestamp_without_timezone"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nALTER TABLE users ADD COLUMN phone VARCHAR(20);\n-- Existing rows get NULL\n-- If NOT NULL needed, this fails on existing data\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Adding column with no default to existing table**\n\n**Fix:**\n```sql\nALTER TABLE users ADD COLUMN phone VARCHAR(20) DEFAULT '';\nUPDATE users SET phone = 'unknown' WHERE phone = '';\nALTER TABLE users ALTER COLUMN phone SET NOT NULL;\n-- Add with default, backfill, then enforce NOT NULL\n-- Or: ALTER TABLE users ADD COLUMN phone VARCHAR(20);\n--   (accept NULLs temporarily, migrate in phases)\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "adding_column_with_no_default_to_existing_table"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nALTER TABLE users DROP COLUMN phone;\n-- Data lost immediately, no rollback\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Dropping column directly**\n\n**Fix:**\n```sql\n-- Phase 1: Mark as deprecated, stop writing\n-- Phase 2: Migrate data if needed\n-- Phase 3: Drop in separate migration\nALTER TABLE users DROP COLUMN IF EXISTS phone;\n-- Or use a migration framework with rollback:\n# migrations/003_drop_phone.sql\n# up:\nALTER TABLE users DROP COLUMN phone;\n# down:\nALTER TABLE users ADD COLUMN phone VARCHAR(20);\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "dropping_column_directly"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nDELETE FROM users WHERE id = 42;\n-- Hard delete: data gone, orphaned foreign keys\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Missing soft delete**\n\n**Fix:**\n```sql\nALTER TABLE users ADD COLUMN deleted_at TIMESTAMP;\n-- Soft delete:\nUPDATE users SET deleted_at = NOW() WHERE id = 42;\n-- Query excludes deleted:\nSELECT * FROM users WHERE deleted_at IS NULL;\n-- Or partial index:\nCREATE INDEX idx_users_active ON users(id) WHERE deleted_at IS NULL;\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "missing_soft_delete"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nUPDATE users SET email = 'new@email.com' WHERE id = 42;\n-- Previous email lost, no history\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: No audit trail**\n\n**Fix:**\n```sql\nCREATE TABLE user_audit (\n  id BIGSERIAL PRIMARY KEY,\n  user_id INT REFERENCES users(id),\n  action VARCHAR(20),\n  old_values JSONB,\n  new_values JSONB,\n  changed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n  changed_by INT\n);\n-- Log changes via triggers or application code\n-- Essential for compliance and debugging\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "no_audit_trail"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nALTER TABLE orders ADD COLUMN metadata JSONB;\n-- PostgreSQL: locks table for exclusive access\n-- Blocks all reads and writes during ALTER\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Online schema change on large table**\n\n**Fix:**\n```sql\n-- PostgreSQL 11+: ADD COLUMN with DEFAULT is instant (no lock)\nALTER TABLE orders ADD COLUMN metadata JSONB;\n-- For operations that DO lock:\n-- Use pg_online_schema_change or similar tools\n-- Or: add column, backfill in batches, verify\n-- MySQL: use pt-online-schema-change or gh-ost\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "online_schema_change_on_large_table"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE order_items (\n  id SERIAL PRIMARY KEY,\n  order_id INT REFERENCES orders(id)\n  -- order_id can be NULL - orphan items possible\n);\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Missing NOT NULL on foreign key**\n\n**Fix:**\n```sql\nCREATE TABLE order_items (\n  id SERIAL PRIMARY KEY,\n  order_id INT NOT NULL REFERENCES orders(id) ON DELETE CASCADE\n);\n-- NOT NULL on FK: every item must belong to an order\n-- ON DELETE CASCADE: cleaning up automatically\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "missing_not_null_on_foreign_key"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE users (\n  id SERIAL PRIMARY KEY\n);\n-- SERIAL is PostgreSQL-specific, uses sequences\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Using SERIAL instead of IDENTITY**\n\n**Fix:**\n```sql\nCREATE TABLE users (\n  id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY\n);\n-- SQL standard IDENTITY column\n-- Better portability, safer (cannot be inserted manually)\n-- SERIAL is fine for PostgreSQL-only projects\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "using_serial_instead_of_identity"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE TABLE logs (\n  message TEXT,\n  level VARCHAR(10),\n  created_at TIMESTAMP\n);\n-- No primary key: cannot update/delete specific rows\n-- PostgreSQL heap-organized: no clustering\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Table without primary key**\n\n**Fix:**\n```sql\nCREATE TABLE logs (\n  id BIGSERIAL PRIMARY KEY,\n  message TEXT NOT NULL,\n  level VARCHAR(10) NOT NULL,\n  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()\n);\n-- Primary key enables:\n-- Targeted updates/deletes\n-- Foreign key references\n-- Row identification\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "table_without_primary_key"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT user_id, email\nFROM users\nGROUP BY user_id\n-- GROUP BY without aggregate = confusing\n-- Same as DISTINCT on user_id\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: GROUP BY without aggregation**\n\n**Fix:**\n```sql\nSELECT DISTINCT ON (user_id) user_id, email\nFROM users\nORDER BY user_id, created_at DESC\n-- If you want one row per user: DISTINCT ON or window function\n-- GROUP BY should have aggregate functions\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "group_by_without_aggregation"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- Application code builds comma-separated list\nSELECT id FROM tags WHERE post_id = 42\n-- Then joins in Python: ','.join(rows)\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: String aggregation with concatenation loop**\n\n**Fix:**\n```sql\nSELECT STRING_AGG(tag, ', ' ORDER BY tag) as tags\nFROM tags WHERE post_id = 42\n-- STRING_AGG: database-level aggregation\n-- GROUP_CONCAT in MySQL, LISTAGG in Oracle\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "string_aggregation_with_concatenation_loop"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT department,\n  SUM(CASE WHEN quarter = 'Q1' THEN revenue END) as q1,\n  SUM(CASE WHEN quarter = 'Q2' THEN revenue END) as q2,\n  SUM(CASE WHEN quarter = 'Q3' THEN revenue END) as q3,\n  SUM(CASE WHEN quarter = 'Q4' THEN revenue END) as q4\nFROM quarterly_revenue\nGROUP BY department\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: PIVOT with CASE WHEN**\n\n**Fix:**\n```sql\n-- PostgreSQL 14+: native PIVOT via tablefunc\nSELECT * FROM crosstab(\n  'SELECT department, quarter, revenue FROM quarterly_revenue ORDER BY 1,2'\n) AS ct(department text, q1 int, q2 int, q3 int, q4 int);\n-- Or stick with CASE WHEN for compatibility\n-- Both are correct, CASE is more portable\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "pivot_with_case_when"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT a.date, a.orders,\n  (SELECT COUNT(*) FROM daily_stats b WHERE b.date <= a.date) as cumulative\nFROM daily_stats a\nORDER BY a.date\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Running count with self-join**\n\n**Fix:**\n```sql\nSELECT date, orders,\n  COUNT(*) OVER (ORDER BY date) as cumulative,\n  SUM(orders) OVER (ORDER BY date) as cumulative_orders\nFROM daily_stats\nORDER BY date\n-- Window functions replace correlated subqueries\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "running_count_with_self-join"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT department, SUM(salary) FROM employees GROUP BY department\nUNION ALL\nSELECT NULL, SUM(salary) FROM employees\n-- Manual subtotal/total\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Grouping sets for multi-level totals**\n\n**Fix:**\n```sql\nSELECT department, SUM(salary) as total_salary\nFROM employees\nGROUP BY GROUPING SETS ((department), ())\n-- GROUPING SETS: multiple groupings in one pass\n-- ROLLUP: hierarchical totals\n-- CUBE: all combinations\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "grouping_sets_for_multi-level_totals"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT department, COUNT(*) as active_count\nFROM employees WHERE status = 'active'\nGROUP BY department\n-- Separate query for inactive\nSELECT department, COUNT(*) as inactive_count\nFROM employees WHERE status = 'inactive'\nGROUP BY department\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Conditional aggregation**\n\n**Fix:**\n```sql\nSELECT department,\n  COUNT(*) FILTER (WHERE status = 'active') as active_count,\n  COUNT(*) FILTER (WHERE status = 'inactive') as inactive_count,\n  COUNT(*) as total\nFROM employees\nGROUP BY department\n-- FILTER clause: conditional aggregation in one pass\n-- MySQL: COUNT(CASE WHEN status = 'active' THEN 1 END)\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "conditional_aggregation"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM salaries\nORDER BY amount\n-- Manual percentile calculation in application code\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Percentile calculation**\n\n**Fix:**\n```sql\nSELECT\n  PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY amount) as median,\n  PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY amount) as p90,\n  PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY amount) as p95\nFROM salaries\n-- ORDERED-SET aggregate functions\n-- PERCENTILE_CONT: continuous interpolation\n-- PERCENTILE_DISC: nearest rank\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "percentile_calculation"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\n-- Application collects rows into JSON array\nrows = cursor.execute(\"SELECT id, name FROM tags WHERE post_id = 42\").fetchall()\ntags = json.dumps([{\"id\": r[0], \"name\": r[1]} for r in rows])\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: JSON aggregation**\n\n**Fix:**\n```sql\nSELECT json_agg(to_jsonb(t)) as tags\nFROM (SELECT id, name FROM tags WHERE post_id = 42) t\n-- Or JSON_OBJECTAGG for key-value:\nSELECT json_object_agg(id, name) as tag_map\nFROM tags WHERE post_id = 42\n-- Database builds JSON, application consumes it\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "json_aggregation"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT u.name, COUNT(o.id), SUM(o.total)\nFROM users u JOIN orders o ON o.user_id = u.id\nWHERE o.created_at >= NOW() - INTERVAL '30 days'\nGROUP BY u.id, u.name\n-- This query appears in 5 different places\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Complex repeated query logic**\n\n**Fix:**\n```sql\nCREATE VIEW user_monthly_stats AS\nSELECT u.id, u.name,\n  COUNT(o.id) as order_count,\n  SUM(o.total) as total_spent\nFROM users u\nLEFT JOIN orders o ON o.user_id = u.id\n  AND o.created_at >= NOW() - INTERVAL '30 days'\nGROUP BY u.id, u.name;\n\n-- Now: SELECT * FROM user_monthly_stats;\n-- Centralized logic, single source of truth\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "complex_repeated_query_logic"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT department, COUNT(*), AVG(salary), MAX(salary)\nFROM employees\nWHERE hire_date >= '2020-01-01'\nGROUP BY department\n-- Runs on every page load against 500K rows\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Slow dashboard query on large tables**\n\n**Fix:**\n```sql\nCREATE MATERIALIZED VIEW dept_stats AS\nSELECT department, COUNT(*) as emp_count,\n  AVG(salary) as avg_salary, MAX(salary) as max_salary\nFROM employees\nGROUP BY department;\n\nCREATE INDEX idx_dept_stats ON dept_stats(department);\n\n-- Refresh periodically:\nREFRESH MATERIALIZED VIEW CONCURRENTLY dept_stats;\n-- CONCURRENTLY: no read locks during refresh\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "slow_dashboard_query_on_large_tables"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nCREATE MATERIALIZED VIEW order_summary AS\nSELECT user_id, COUNT(*), SUM(total)\nFROM orders GROUP BY user_id;\n-- Stale data after inserts\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: View with no refresh schedule**\n\n**Fix:**\n```sql\n-- Option 1: Scheduled refresh\n-- pg_cron extension:\nSELECT cron.schedule('refresh_order_summary', '*/5 * * * *',\n  'REFRESH MATERIALIZED VIEW CONCURRENTLY order_summary');\n\n-- Option 2: Trigger-based refresh\nCREATE OR REPLACE FUNCTION refresh_order_summary()\nRETURNS TRIGGER AS $$\nBEGIN\n  REFRESH MATERIALIZED VIEW CONCURRENTLY order_summary;\n  RETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "view_with_no_refresh_schedule"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM employees\n-- Application filters: WHERE department = user_department\n-- Risk: admin sees all data\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: View for security filtering**\n\n**Fix:**\n```sql\nCREATE VIEW my_department AS\nSELECT id, name, role\nFROM employees\nWHERE department = current_setting('app.department');\n\n-- Grant access to view, not table:\nGRANT SELECT ON my_department TO app_user;\nREVOKE SELECT ON employees FROM app_user;\n-- Row-level security via view\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "view_for_security_filtering"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nuser_ids = [1, 2, 3, 4, 5]\nfor uid in user_ids:\n    user = db.query(f\"SELECT * FROM users WHERE id = {uid}\")\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: SELECT in a loop (N+1)**\n\n**Fix:**\n```sql\nusers = db.query(\"SELECT * FROM users WHERE id IN (?, ?, ?, ?, ?)\", user_ids)\n-- Single query with IN clause\n-- Or use a dict to map results:\nusers_by_id = {u['id']: u for u in users}\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "select_in_a_loop_(n+1)"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM products ORDER BY popularity\n-- popularity has no index, full table scan + sort\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: ORDER BY on non-indexed column**\n\n**Fix:**\n```sql\nCREATE INDEX idx_products_popularity ON products(popularity DESC);\nSELECT * FROM products ORDER BY popularity DESC LIMIT 20\n-- Index on ORDER BY column avoids sort step\n-- Match index sort direction to query\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "order_by_on_non-indexed_column"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT status, COUNT(*) FROM events GROUP BY status\n-- Full table scan on 100M+ row table\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: COUNT(*) with GROUP BY on large table**\n\n**Fix:**\n```sql\n-- Option 1: Summary table\nCREATE TABLE event_counts (\n  status VARCHAR(20) PRIMARY KEY,\n  count BIGINT DEFAULT 0\n);\n-- Maintain via triggers or periodic job\n\n-- Option 2: Approximate\nSELECT status, COUNT(*) FROM TABLESAMPLE (1) events GROUP BY status\n-- TABLESAMPLE: statistical estimate\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "count(*)_with_group_by_on_large_table"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM large_table WHERE id = 42\n-- large_table has 50 columns, only need 3\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Wide row scanning**\n\n**Fix:**\n```sql\nSELECT id, name, created_at FROM large_table WHERE id = 42\n-- Only select needed columns:\n-- Less I/O, fits in buffer cache better\n-- Enables covering index\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "wide_row_scanning"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM (\n  SELECT id, name, email FROM users WHERE status = 'active'\n) sub\nWHERE sub.name LIKE 'A%'\n-- Extra layer of subquery\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Unnecessary subquery**\n\n**Fix:**\n```sql\nSELECT id, name, email FROM users\nWHERE status = 'active' AND name LIKE 'A%'\n-- Flatten: no subquery needed\n-- Subquery adds a materialization step\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "unnecessary_subquery"
    ]
  },
  {
    "messages": [
      {
        "role": "user",
        "content": "Review this SQL code:\n\n```sql\nSELECT * FROM products ORDER BY COALESCE(sort_order, id)\n-- COALESCE prevents index use on sort_order\n```"
      },
      {
        "role": "assistant",
        "content": "**Issue: Coalesce in ORDER BY**\n\n**Fix:**\n```sql\nSELECT * FROM products\nORDER BY CASE WHEN sort_order IS NOT NULL THEN 0 ELSE 1 END,\n         COALESCE(sort_order, id)\n-- Or: partial indexes\nCREATE INDEX idx_products_sorted ON products(sort_order) WHERE sort_order IS NOT NULL;\nCREATE INDEX idx_products_unsorted ON products(id) WHERE sort_order IS NULL;\n```"
      }
    ],
    "source": "sql_training",
    "tags": [
      "sql",
      "coalesce_in_order_by"
    ]
  }
]