话不多说,直接上源码。
DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>高级SQL工具集title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql-formatter/11.0.2/sql-formatter.min.js">script>
<style>
:root {
--primary: #3498db;
--secondary: #2ecc71;
--danger: #e74c3c;
--warning: #f39c12;
--dark: #2c3e50;
--light: #ecf0f1;
--gray: #95a5a6;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a2980, #26d0ce);
color: #333;
min-height: 100vh;
padding: 20px;
line-height: 1.6;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
header {
text-align: center;
padding: 30px 0;
color: white;
}
h1 {
font-size: 2.8rem;
margin-bottom: 10px;
text-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
.subtitle {
font-size: 1.2rem;
opacity: 0.9;
max-width: 700px;
margin: 0 auto 20px;
}
.card {
background: white;
border-radius: 12px;
box-shadow: 0 10px 30px rgba(0,0,0,0.15);
overflow: hidden;
margin-bottom: 25px;
}
.card-header {
background: var(--dark);
color: white;
padding: 15px 20px;
display: flex;
align-items: center;
justify-content: space-between;
}
.card-title {
font-size: 1.3rem;
font-weight: 600;
display: flex;
align-items: center;
gap: 10px;
}
.card-body {
padding: 20px;
}
.tabs {
display: flex;
border-bottom: 1px solid #eee;
margin-bottom: 20px;
}
.tab {
padding: 12px 25px;
cursor: pointer;
font-weight: 500;
border-bottom: 3px solid transparent;
transition: all 0.3s;
}
.tab.active {
border-color: var(--primary);
color: var(--primary);
}
.tab:hover:not(.active) {
background: #f8f9fa;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.tools-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-top: 20px;
}
.tool-card {
background: #f8f9fa;
border-radius: 10px;
padding: 20px;
transition: all 0.3s ease;
border: 1px solid #e9ecef;
cursor: pointer;
}
.tool-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 15px rgba(0,0,0,0.1);
border-color: var(--primary);
}
.tool-card i {
font-size: 2.5rem;
margin-bottom: 15px;
color: var(--primary);
}
.tool-card h3 {
margin-bottom: 10px;
color: var(--dark);
}
.tool-card p {
color: #6c757d;
font-size: 0.95rem;
line-height: 1.5;
}
.editor-container {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-top: 20px;
}
.editor-panel {
flex: 1;
min-width: 300px;
}
.panel-title {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
color: var(--dark);
}
textarea {
width: 100%;
height: 250px;
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
font-family: 'Consolas', 'Courier New', monospace;
font-size: 15px;
resize: vertical;
background: #f8f9fa;
}
textarea:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
}
.converter-controls {
display: flex;
flex-wrap: wrap;
gap: 15px;
margin: 20px 0;
align-items: center;
justify-content: center;
}
select, button, input {
padding: 12px 20px;
border-radius: 6px;
font-size: 1rem;
border: none;
cursor: pointer;
}
select, input {
background: white;
border: 1px solid #ddd;
flex: 1;
min-width: 200px;
}
button {
background: var(--primary);
color: white;
font-weight: 600;
transition: all 0.2s ease;
display: flex;
align-items: center;
gap: 8px;
}
button:hover {
background: #2980b9;
transform: translateY(-2px);
}
button.secondary {
background: var(--secondary);
}
button.secondary:hover {
background: #27ae60;
}
button.danger {
background: var(--danger);
}
button.danger:hover {
background: #c0392b;
}
.actions {
display: flex;
gap: 10px;
flex-wrap: wrap;
margin: 15px 0;
}
.db-selector {
display: flex;
gap: 15px;
margin: 15px 0;
justify-content: center;
flex-wrap: wrap;
}
.db-option {
padding: 10px 20px;
background: #e9ecef;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s ease;
border: 2px solid transparent;
display: flex;
align-items: center;
gap: 8px;
}
.db-option.active {
background: var(--primary);
color: white;
border-color: #2980b9;
}
.db-option:hover:not(.active) {
background: #dae0e5;
}
.history {
margin-top: 30px;
}
.history-items {
max-height: 200px;
overflow-y: auto;
}
.history-item {
padding: 12px 15px;
border-bottom: 1px solid #eee;
font-family: 'Consolas', monospace;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
}
.history-item:last-child {
border-bottom: none;
}
.history-item:hover {
background: #f8f9fa;
}
.history-item .time {
font-size: 0.8rem;
color: #6c757d;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: 500;
color: var(--dark);
}
.form-row {
display: flex;
gap: 15px;
margin-bottom: 15px;
}
.form-field {
flex: 1;
}
.optimization-tips {
background: #e8f4fd;
border-left: 4px solid var(--primary);
padding: 15px;
border-radius: 0 4px 4px 0;
margin: 20px 0;
}
.optimization-tips h4 {
margin-bottom: 10px;
color: var(--primary);
display: flex;
align-items: center;
gap: 8px;
}
.tip-item {
display: flex;
gap: 10px;
margin-bottom: 8px;
}
.tip-item i {
color: var(--secondary);
}
footer {
text-align: center;
padding: 25px 0;
color: rgba(255, 255, 255, 0.7);
font-size: 0.9rem;
}
@media (max-width: 768px) {
.editor-container {
flex-direction: column;
}
.converter-controls {
flex-direction: column;
}
select, button, input {
width: 100%;
}
.form-row {
flex-direction: column;
gap: 10px;
}
}
style>
head>
<body>
<div class="container">
<header>
<h1><i class="fas fa-database">i> 高级SQL工具集h1>
<p class="subtitle">支持CRUD生成、SQL美化、性能优化及多数据库转换的一体化解决方案p>
header>
<div class="card">
<div class="card-header">
<div class="card-title">
<i class="fas fa-tools">i> SQL 工具集
div>
div>
<div class="card-body">
<div class="tabs">
<div class="tab active" data-tab="converter">SQL转换器div>
<div class="tab" data-tab="crud">CRUD生成器div>
<div class="tab" data-tab="optimize">SQL优化器div>
div>
<div class="tab-content active" id="converter-tab">
<div class="editor-container">
<div class="editor-panel">
<div class="panel-title">
<i class="fas fa-pen">i> 输入 SQL
div>
<textarea id="input-sql" placeholder="在此输入 SQL 语句...">SELECT employee_id, first_name, last_name, hire_date
FROM employees
WHERE department_id = 50
AND salary > 6000
ORDER BY last_name, first_name
LIMIT 10;textarea>
div>
<div class="editor-panel">
<div class="panel-title">
<i class="fas fa-file-code">i> 输出 SQL
div>
<textarea id="output-sql" placeholder="转换后的 SQL 将显示在这里..." readonly>textarea>
div>
div>
<div class="converter-controls">
<div class="db-selector">
<div class="db-option active" data-db="mysql">
<i class="fab fa-mysql">i> MySQL
div>
<div class="db-option" data-db="oracle">
<i class="fas fa-database">i> Oracle
div>
<div class="db-option" data-db="postgresql">
<i class="fas fa-elephant">i> PostgreSQL
div>
<div class="db-option" data-db="sqlserver">
<i class="fas fa-server">i> SQL Server
div>
div>
<select id="target-db">
<option value="mysql">转换为 MySQL 格式option>
<option value="oracle">转换为 Oracle 格式option>
<option value="postgresql">转换为 PostgreSQL 格式option>
<option value="sqlserver">转换为 SQL Server 格式option>
select>
<button id="convert-btn">
<i class="fas fa-exchange-alt">i> 转换 SQL
button>
div>
<div class="actions">
<button class="secondary" id="format-btn">
<i class="fas fa-align-left">i> 美化SQL
button>
<button class="secondary" id="uppercase-btn">
<i class="fas fa-text-height">i> 转为大写
button>
<button class="secondary" id="lowercase-btn">
<i class="fas fa-text-height">i> 转为小写
button>
<button class="danger" id="clear-btn">
<i class="fas fa-trash">i> 清空
button>
div>
div>
<div class="tab-content" id="crud-tab">
<div class="form-row">
<div class="form-field">
<label for="crud-table"><i class="fas fa-table">i> 表名label>
<input type="text" id="crud-table" placeholder="例如: employees">
div>
<div class="form-field">
<label for="crud-operation"><i class="fas fa-tasks">i> 操作类型label>
<select id="crud-operation">
<option value="select">SELECT (查询)option>
<option value="insert">INSERT (插入)option>
<option value="update">UPDATE (更新)option>
<option value="delete">DELETE (删除)option>
select>
div>
div>
<div class="form-group">
<label for="crud-columns"><i class="fas fa-columns">i> 列/字段 (逗号分隔)label>
<input type="text" id="crud-columns" placeholder="例如: id, name, email, created_at">
div>
<div class="form-group" id="insert-values-group">
<label for="crud-values"><i class="fas fa-list">i> 插入值 (逗号分隔)label>
<input type="text" id="crud-values" placeholder="例如: 101, 'John Doe', '[email protected]', NOW()">
div>
<div class="form-group" id="update-set-group">
<label for="crud-set"><i class="fas fa-edit">i> SET子句 (字段=值, 逗号分隔)label>
<input type="text" id="crud-set" placeholder="例如: name='Jane Smith', email='[email protected]'">
div>
<div class="form-group">
<label for="crud-where"><i class="fas fa-filter">i> WHERE条件label>
<input type="text" id="crud-where" placeholder="例如: id = 101 AND active = 1">
div>
<div class="form-group">
<label for="crud-order"><i class="fas fa-sort">i> ORDER BY排序label>
<input type="text" id="crud-order" placeholder="例如: created_at DESC">
div>
<div class="actions">
<button class="secondary" id="generate-sql">
<i class="fas fa-cogs">i> 生成SQL
button>
<button class="secondary" id="copy-crud">
<i class="fas fa-copy">i> 复制SQL
button>
<button class="danger" id="reset-crud">
<i class="fas fa-redo">i> 重置表单
button>
div>
<div class="editor-panel">
<div class="panel-title">
<i class="fas fa-code">i> 生成的SQL
div>
<textarea id="crud-output" placeholder="生成的SQL将显示在这里..." readonly>textarea>
div>
div>
<div class="tab-content" id="optimize-tab">
<div class="editor-panel">
<div class="panel-title">
<i class="fas fa-search">i> 输入SQL进行分析
div>
<textarea id="optimize-input" placeholder="在此输入SQL语句进行性能分析...">SELECT *
FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE o.order_date > '2023-01-01'
ORDER BY o.total_amount DESC;textarea>
div>
<div class="actions">
<button class="secondary" id="analyze-btn">
<i class="fas fa-chart-line">i> 分析性能
button>
<button class="secondary" id="optimize-btn">
<i class="fas fa-bolt">i> 优化SQL
button>
div>
<div class="optimization-tips">
<h4><i class="fas fa-lightbulb">i> 优化建议h4>
<div id="optimization-tips">
<div class="tip-item">
<i class="fas fa-check-circle">i>
<div>避免使用SELECT *,只选择需要的列div>
div>
<div class="tip-item">
<i class="fas fa-check-circle">i>
<div>检查WHERE子句中的字段是否已建立索引div>
div>
<div class="tip-item">
<i class="fas fa-check-circle">i>
<div>考虑在连接字段上创建索引div>
div>
div>
div>
<div class="editor-panel">
<div class="panel-title">
<i class="fas fa-star">i> 优化后的SQL
div>
<textarea id="optimized-sql" placeholder="优化后的SQL将显示在这里..." readonly>textarea>
div>
div>
div>
div>
<div class="card history">
<div class="card-header">
<div class="card-title">
<i class="fas fa-history">i> 最近操作记录
div>
div>
<div class="card-body">
<div class="history-items" id="history-container">
<div class="history-item">
<div class="sql">SELECT * FROM users WHERE active = 1div>
<div class="time">2分钟前div>
div>
<div class="history-item">
<div class="sql">UPDATE products SET price = price * 1.1 WHERE category = 'Electronics'div>
<div class="time">今天 10:23div>
div>
<div class="history-item">
<div class="sql">DELETE FROM logs WHERE created_at < '2023-01-01'div>
<div class="time">昨天 16:45div>
div>
div>
div>
div>
<footer>
<p>高级SQL工具集 © 2023 | 支持Oracle, MySQL, PostgreSQL, SQL Server | CRUD生成、SQL优化、跨数据库转换p>
footer>
div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 元素引用
const inputSql = document.getElementById('input-sql');
const outputSql = document.getElementById('output-sql');
const convertBtn = document.getElementById('convert-btn');
const formatBtn = document.getElementById('format-btn');
const uppercaseBtn = document.getElementById('uppercase-btn');
const lowercaseBtn = document.getElementById('lowercase-btn');
const clearBtn = document.getElementById('clear-btn');
const dbOptions = document.querySelectorAll('.db-option');
const targetDb = document.getElementById('target-db');
const historyContainer = document.getElementById('history-container');
const tabs = document.querySelectorAll('.tab');
const tabContents = document.querySelectorAll('.tab-content');
const crudTable = document.getElementById('crud-table');
const crudOperation = document.getElementById('crud-operation');
const crudColumns = document.getElementById('crud-columns');
const crudValues = document.getElementById('crud-values');
const crudSet = document.getElementById('crud-set');
const crudWhere = document.getElementById('crud-where');
const crudOrder = document.getElementById('crud-order');
const crudOutput = document.getElementById('crud-output');
const generateSqlBtn = document.getElementById('generate-sql');
const optimizeInput = document.getElementById('optimize-input');
const optimizedSql = document.getElementById('optimized-sql');
const analyzeBtn = document.getElementById('analyze-btn');
const optimizeBtn = document.getElementById('optimize-btn');
const insertValuesGroup = document.getElementById('insert-values-group');
const updateSetGroup = document.getElementById('update-set-group');
// 初始化显示/隐藏CRUD相关字段
updateCrudFieldsVisibility();
// 标签页切换
tabs.forEach(tab => {
tab.addEventListener('click', function() {
const tabId = this.dataset.tab;
// 更新活动标签
tabs.forEach(t => t.classList.remove('active'));
this.classList.add('active');
// 显示对应内容
tabContents.forEach(content => {
content.classList.remove('active');
if (content.id === `${tabId}-tab`) {
content.classList.add('active');
}
});
});
});
// 数据库选项切换
dbOptions.forEach(option => {
option.addEventListener('click', function() {
dbOptions.forEach(opt => opt.classList.remove('active'));
this.classList.add('active');
});
});
// 转换SQL
convertBtn.addEventListener('click', function() {
const sql = inputSql.value.trim();
if (!sql) {
alert('请输入SQL语句');
return;
}
const sourceDb = document.querySelector('.db-option.active').dataset.db;
const target = targetDb.value;
// 模拟转换过程
outputSql.value = simulateSqlConversion(sql, sourceDb, target);
// 添加到历史记录
addToHistory(sql);
});
// 格式化SQL
formatBtn.addEventListener('click', function() {
const sql = inputSql.value.trim();
if (!sql) return;
try {
// 使用sql-formatter库进行格式化
if (window.sqlFormatter) {
const formatted = sqlFormatter.format(sql, {
language: 'sql',
indent: ' ',
uppercase: true
});
inputSql.value = formatted;
} else {
// 回退到简单格式化
inputSql.value = simpleFormatSql(sql);
}
} catch (e) {
console.error('格式化错误:', e);
inputSql.value = simpleFormatSql(sql);
}
});
// 转为大写
uppercaseBtn.addEventListener('click', function() {
inputSql.value = inputSql.value.toUpperCase();
});
// 转为小写
lowercaseBtn.addEventListener('click', function() {
inputSql.value = inputSql.value.toLowerCase();
});
// 清空
clearBtn.addEventListener('click', function() {
if (confirm('确定要清空输入框吗?')) {
inputSql.value = '';
outputSql.value = '';
}
});
// CRUD操作类型变化
crudOperation.addEventListener('change', function() {
updateCrudFieldsVisibility();
});
// 生成SQL
generateSqlBtn.addEventListener('click', function() {
const table = crudTable.value.trim();
const operation = crudOperation.value;
const columns = crudColumns.value.trim();
const where = crudWhere.value.trim();
const order = crudOrder.value.trim();
if (!table) {
alert('请输入表名');
return;
}
let generatedSql = '';
switch(operation) {
case 'select':
if (!columns) {
alert('请选择要查询的列');
return;
}
generatedSql = `SELECT ${columns} FROM ${table}`;
if (where) generatedSql += ` WHERE ${where}`;
if (order) generatedSql += ` ORDER BY ${order}`;
generatedSql += ';';
break;
case 'insert':
const values = crudValues.value.trim();
if (!columns || !values) {
alert('请填写列和对应的值');
return;
}
generatedSql = `INSERT INTO ${table} (${columns}) VALUES (${values});`;
break;
case 'update':
const setClause = crudSet.value.trim();
if (!setClause || !where) {
alert('请填写SET子句和WHERE条件');
return;
}
generatedSql = `UPDATE ${table} SET ${setClause} WHERE ${where};`;
break;
case 'delete':
if (!where) {
alert('请填写WHERE条件');
return;
}
generatedSql = `DELETE FROM ${table} WHERE ${where};`;
break;
}
crudOutput.value = generatedSql;
addToHistory(generatedSql);
});
// 分析SQL性能
analyzeBtn.addEventListener('click', function() {
const sql = optimizeInput.value.trim();
if (!sql) {
alert('请输入SQL语句');
return;
}
// 模拟分析过程
const tipsContainer = document.getElementById('optimization-tips');
tipsContainer.innerHTML = `
检测到SELECT *,建议明确指定所需列
WHERE子句中的order_date字段可能需要索引
JOIN操作涉及customers表,确认customer_id已索引
ORDER BY子句使用total_amount,大表排序可能影响性能
`;
});
// 优化SQL
optimizeBtn.addEventListener('click', function() {
const sql = optimizeInput.value.trim();
if (!sql) {
alert('请输入SQL语句');
return;
}
// 模拟优化过程
optimizedSql.value = sql
.replace(/\*\s*FROM/, 'o.id, o.order_date, o.total_amount, c.name FROM')
.replace(/JOIN customers c/, 'INNER JOIN customers c')
+ '\n-- 建议在order_date和customer_id字段上创建索引';
});
// 更新CRUD字段可见性
function updateCrudFieldsVisibility() {
const operation = crudOperation.value;
insertValuesGroup.style.display = operation === 'insert' ? 'block' : 'none';
updateSetGroup.style.display = operation === 'update' ? 'block' : 'none';
}
// 模拟SQL转换
function simulateSqlConversion(sql, sourceDb, targetDb) {
// 这里只是一个模拟实现,实际应用中需要更复杂的转换规则
let converted = sql;
// 处理LIMIT子句的转换
if (sourceDb === 'mysql' && targetDb === 'oracle') {
converted = converted.replace(/LIMIT\s+(\d+);?$/i, (match, p1) => {
return `FETCH FIRST ${p1} ROWS ONLY`;
});
}
if (sourceDb === 'mysql' && targetDb === 'sqlserver') {
converted = converted.replace(/LIMIT\s+(\d+);?$/i, (match, p1) => {
return `TOP ${p1}`;
});
}
if (sourceDb === 'oracle' && targetDb === 'mysql') {
converted = converted.replace(/FETCH FIRST\s+(\d+)\s+ROWS ONLY;?$/i, (match, p1) => {
return `LIMIT ${p1}`;
});
}
// 处理日期函数
if (targetDb === 'mysql') {
converted = converted.replace(/SYSDATE/gi, 'CURRENT_TIMESTAMP');
}
if (targetDb === 'sqlserver') {
converted = converted.replace(/SYSDATE/gi, 'GETDATE()');
converted = converted.replace(/CURRENT_TIMESTAMP/gi, 'GETDATE()');
}
// 处理字符串连接
if (sourceDb === 'mysql' && targetDb !== 'mysql') {
converted = converted.replace(/\|\|/g, ' + ');
}
// 添加目标数据库注释
converted = `-- 已转换为 ${getDbName(targetDb)} 格式\n${converted}`;
return converted;
}
function getDbName(db) {
const names = {
'mysql': 'MySQL',
'oracle': 'Oracle',
'postgresql': 'PostgreSQL',
'sqlserver': 'SQL Server'
};
return names[db] || db;
}
// 简单SQL格式化
function simpleFormatSql(sql) {
// 添加换行和缩进
return sql
.replace(/\b(SELECT|FROM|WHERE|JOIN|LEFT JOIN|RIGHT JOIN|INNER JOIN|GROUP BY|HAVING|ORDER BY|LIMIT)\b/gi, '\n$1')
.replace(/\,/g, ',\n ')
.replace(/\bAND\b/gi, '\n AND')
.replace(/\bOR\b/gi, '\n OR');
}
// 添加到历史记录
function addToHistory(sql) {
if (sql.length > 100) {
sql = sql.substring(0, 100) + '...';
}
const now = new Date();
const timeStr = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
const historyItem = document.createElement('div');
historyItem.className = 'history-item';
historyItem.innerHTML = `
${escapeHtml(sql)}
${timeStr}
`;
historyContainer.insertBefore(historyItem, historyContainer.firstChild);
// 限制历史记录数量
if (historyContainer.children.length > 10) {
historyContainer.removeChild(historyContainer.lastChild);
}
}
// 防止XSS攻击
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
});
script>
body>
html>
SQL转换器:
CRUD生成器:
SQL优化器: