translate natural-language analytics requests into mysql queries, connect to a live mysql database, inspect schema and column comments, execute read-only sql...
--- name: mysql-query-assistant description: translate natural-language analytics requests into mysql queries, connect to a live mysql database, inspect schema and column comments, execute read-only sql, and validate query correctness against real results. use when chatgpt needs to work with mysql through direct connection details provided by environment variables, especially for ad hoc analysis, sql generation, schema discovery, query debugging, or cautious database workflows that must verify results before presenting them. also use for restricted write workflows that first generate a preview select and never auto-execute the write statement. --- # Mysql Query Assistant Use this skill to turn a user's request into safe MySQL work against a live database. ## Core workflow For every request, follow this sequence: 1. Inspect connection prerequisites from `references/connection-and-safety.md`. 2. Discover relevant schema first. Prefer column comments when available. 3. Draft the SQL. 4. Execute only read-only SQL with `scripts/run_read_query.py`. 5. Perform double validation: - structural validation: tables, columns, joins, filters, grouping, and syntax match the request. - result validation: returned rows and aggregates look semantically consistent with the user's intent. 6. If validation fails, revise the SQL and run it again. 7. Present the final answer using the output template below. ## Default behavior - Prefer `SELECT` queries only. - Never auto-execute `INSERT`, `UPDATE`, `DELETE`, `REPLACE`, `ALTER`, `DROP`, `TRUNCATE`, `CREATE`, `GRANT`, or `REVOKE`. - Keep result samples small by default. - When the request is ambiguous, use schema inspection to narrow candidate tables before writing SQL. - Prefer explicit column lists over `SELECT *` unless schema exploration is the user's goal. - Prefer bounded queries. Add `LIMIT` when the user did not ask for a full extract. ## Schema discovery workflow Before generating SQL, inspect schema with `scripts/introspect_schema.py`. Use this order: 1. List candidate tables. 2. Inspect columns, data types, keys, and column comments for the most relevant tables. 3. Infer business meaning from comments and names. 4. Only then draft SQL. If comments are missing, fall back to table names, column names, keys, and a few small probing queries. ## Read-only execution workflow Use `scripts/run_read_query.py` to execute the SQL. The script rejects non-read-only statements. It also blocks multi-statement execution. When verifying a query: 1. Run the first candidate SQL. 2. Review row count, sample rows, and whether the columns answer the request. 3. If the result is empty or suspicious, explain why and try a corrected query when appropriate. 4. If multiple interpretations are plausible, prefer the query best supported by schema and results, and say what assumption you made. ## Restricted write workflow When the user asks for a write operation: 1. Do not execute the write statement. 2. First produce a preview `SELECT` that shows exactly which rows would be affected. 3. Then produce the write SQL separately. 4. Clearly label the write SQL as not executed. 5. Call out any missing safety condition such as a weak or absent `WHERE` clause. ## Output template Use this structure unless the user asks for a different format. ### Final SQL ```sql [final sql] ``` ### Validation - Structural check: [why the sql shape matches the request] - Result check: [why the returned data seems correct, or why confidence is limited] ### Sample results Show 5 to 20 rows when available and useful. Keep wide tables compact. ### Result summary Provide a brief natural-language summary of what the query shows. ### Notes Include assumptions, caveats, and any schema uncertainties. ## Execution details - Use environment variables described in `references/connection-and-safety.md`. - Use `scripts/introspect_schema.py` for schema discovery. - Use `scripts/run_read_query.py` for executing read-only SQL. - If the python mysql driver is missing, install one of the documented options before running the scripts. ## Examples ### Example: analytics request User request: `统计最近 7 天每天新增用户数` Expected approach: 1. Inspect likely user table and created-at column. 2. Confirm time column semantics from comments or names. 3. Generate grouped date query. 4. Run it. 5. Verify the date buckets and counts look plausible. ### Example: restricted write request User request: `把 status = 'pending' 且 30 天前创建的订单改成 expired` Expected approach: 1. Generate preview `SELECT` for the target rows. 2. Generate `UPDATE` SQL separately. 3. Do not execute the `UPDATE`. 4. Warn if the table lacks a reliable key or if the filter looks too broad.
don't have the plugin yet? install it then click "run inline in claude" again.
added explicit inputs section with env var and script details, separated decision points into if-else branches, added outcome signal and expanded edge cases, kept original procedure steps faithful and renumbered for clarity, added structured execution workflows with call-outs for timeouts and connection failures.
turn a user's natural-language analytics request into safe, validated SQL queries executed against a live MySQL database. use this when you need to explore schema, generate read-only queries, debug SQL logic, or handle restricted write workflows that require preview-before-execute. this skill is for ad hoc analysis, schema discovery, and cautious database work where validation against real results matters before presenting answers.
environment variables (set before running):
MYSQL_HOST: hostname or ip of the mysql serverMYSQL_PORT: port number, default 3306MYSQL_USER: database user with select privileges (and insert/update/delete for preview workflows only)MYSQL_PASSWORD: password for the userMYSQL_DB: database name to querypython dependencies:
mysql-connector-python or PyMySQL or mysqlclient (at least one must be installed; see execution details)external scripts (included in skill context):
scripts/introspect_schema.py: discover tables, columns, data types, keys, and commentsscripts/run_read_query.py: execute read-only sql only; rejects write statements and multi-statement executionedge cases to handle:
input: environment variables MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB
output: confirmation that env vars are set and connection can be established
SELECT 1) against the databaseinput: user's natural-language request, env vars output: list of candidate tables with column metadata
scripts/introspect_schema.py to list all tables in the databaseSELECT * FROM table LIMIT 1) to infer meaninginput: user request, discovered schema output: candidate sql query as a string
SELECT query only (never draft write statements at this stage)SELECT * unless the user explicitly asks for schema explorationLIMIT by default to keep results bounded, unless the user asks for a full extract or row countinput: candidate sql query, env vars output: result set (rows), row count, and any error messages
scripts/run_read_query.py with the sql stringLIMIT, narrower date range, or indexed filter)input: final sql, user request, schema metadata output: validation note (pass or fail with reason)
WHERE filters, JOIN conditions, and GROUP BY clauses match the user's intentinput: returned rows, user request, schema semantics output: validation note (pass or fail with reason)
input: validated query, result rows, validation notes, schema assumptions output: formatted response following the output contract
if the user asks for a write operation (insert, update, delete, replace, alter, drop, truncate, create):
SELECT query that shows exactly which rows would be affectedWHERE clause, or absence of a reliable unique key for the update targetif the result set is empty:
if schema discovery returns no column comments:
SELECT * FROM table LIMIT 3) to confirm data types and plausible valuesif the user's request is ambiguous (e.g., "revenue last month" without specifying which revenue column or time field):
if the sql execution times out or hits resource limits:
LIMIT, indexed filter, or smaller date range)if connection fails (invalid credentials, host unreachable, insufficient privileges):
all responses must follow this structure unless the user explicitly requests a different format:
[the final validated query, properly formatted]
[5 to 20 rows when available and useful; keep wide tables compact, e.g., truncate long text or use json formatting]
[brief natural-language summary, 2-4 sentences, of what the query shows and what the rows mean in business terms]
[any assumptions made about schema, caveats, edge cases, or uncertainties; mention if comments were missing or if multiple interpretations were plausible]
the user knows the skill worked when:
SELECT showing which rows would be affected and a separate unannotated write statement clearly marked as not executedenvironment setup:
MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DB in your shell or deployment environmentmysql-connector-python, PyMySQL, or mysqlclient is installed; if not, run pip install mysql-connector-python (or the alternative)scripts:
scripts/introspect_schema.py accepts env vars and outputs table and column metadata to stdout or jsonscripts/run_read_query.py accepts a sql string as input, rejects non-read-only statements and multi-statement execution, and outputs rows and metadataschema exploration workflow:
introspect_schema.pyread-only execution workflow:
scripts/run_read_query.pyuser request: "how many new users did we add each day in the last 7 days?"
expected approach:
SELECT DATE(created_at) as signup_date, COUNT(*) as new_users FROM users WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY DATE(created_at) ORDER BY signup_dateuser request: "update orders with status = 'pending' and created more than 30 days ago to status = 'expired'"
expected approach:
SELECT: SELECT id, created_at, status FROM orders WHERE status = 'pending' AND created_at < DATE_SUB(NOW(), INTERVAL 30 DAY)UPDATE orders SET status = 'expired' WHERE status = 'pending' AND created_at < DATE_SUB(NOW(), INTERVAL 30 DAY)