PHP中MySQL子查询报1064语法错误,求高效查询解决方案
解决MySQL语法错误+优化查询逻辑+修复SQL注入风险
咱们一步步拆解你的问题,先搞定语法错误,再优化查询,最后必须提个关乎数据库安全的重要点:
1. 先修正你的MySQL语法错误
你之前尝试的嵌套查询有两处明显的语法问题:
错误语句:
SELECT *(events) FROM (SELECT * AS events FROM calendar WHERE event_key LIKE '201974000') AS lineitems
*(events)是无效写法,正确引用子查询字段应该用events.*- 子查询里的
SELECT * AS events逻辑错误,表别名应该放在子查询括号的后面,不是字段后面
修正后的嵌套查询应该是这样:
SELECT events.* FROM (SELECT * FROM calendar WHERE event_key LIKE '201974000%') AS events WHERE events.event = 'Event Name'
但其实完全没必要用嵌套子查询,你的需求直接用一条WHERE语句就能实现,更简洁高效:
SELECT * FROM calendar WHERE event_key LIKE '{$eventKey}%' AND event = '{$eventTitle}'
你之前尝试过类似写法,但少了一个右括号(WHERE (event_key LIKE ... AND event='" . $event . "'),这也是导致报错的原因之一。
2. 重中之重:修复SQL注入漏洞
你现在直接把$eventKey、$eventTitle这类外部变量拼进SQL语句里,存在严重的SQL注入风险——攻击者可以构造恶意值篡改你的数据库操作,甚至删库跑路。必须改用MySQLi的预处理语句来避免这个问题。
比如把查询逻辑改成预处理方式:
// 用?作为占位符代替变量 $sql = "SELECT * FROM calendar WHERE event_key LIKE ? AND event = ?"; // 初始化预处理语句 $stmt = $connection->prepare($sql); // 给LIKE条件拼接%,绑定参数(s表示字符串类型) $like_event_key = $eventKey . "%"; $stmt->bind_param("ss", $like_event_key, $eventTitle); // 执行查询 $stmt->execute(); // 获取查询结果 $result = $stmt->get_result(); // 检查匹配行数 if ($result->num_rows > 0) { // 处理已有数据 } // 关闭语句 $stmt->close();
同样,你的UPDATE和INSERT语句也需要改成预处理写法,比如插入操作:
// 明确指定字段名(避免表结构变化导致插入错误) $insert = "INSERT INTO calendar (event_num, event, url, image, description, location, start_date, end_date, color) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; $stmt = $connection->prepare($insert); // 绑定参数,按字段顺序对应 $stmt->bind_param("sssssssss", $eventNum, $eventTitle, $eventURL, $eventImage, $eventDesc, $eventLocat, $eventStart, $eventEnd, 'FFB819'); $stmt->execute(); $stmt->close();
3. 修正你PHP代码里的小bug
你的seoUrl函数里有一行无效代码:$string = str_replace("");,缺少参数会导致报错,直接删掉这行即可。
另外,建议在INSERT语句中明确指定字段名(如上例),避免表结构调整后插入数据错位。
修正后的核心数据库操作代码
foreach($vcalendar->VEVENT as $event){ $eventTitle = $event->SUMMARY; $eventStart = strtotime($event->DTSTART); $eventEnd = strtotime($event->DTEND); $eventDesc = $event->DESCRIPTION; $eventLocat = $event->LOCATION; $eventImage = imageCorrection($event->ATTACH); $eventKey = date('YzB',$eventStart); $eventURL = seoUrl($eventTitle); echo $eventKey."<br>"; echo $eventTitle."<br>"; echo $eventURL."<br>"; echo $eventDesc."<br>"; echo $eventLocat."<br>"; echo $eventImage."<br>"; echo date('m-d-Y h:ia',$eventStart)."<br>"; echo date('m-d-Y h:ia',$eventEnd)."<br>"; // 预处理查询事件是否存在 $sql = "SELECT * FROM calendar WHERE event_key LIKE ? AND event = ?"; $stmt = $connection->prepare($sql); $like_event_key = $eventKey . "%"; $stmt->bind_param("ss", $like_event_key, $eventTitle); $stmt->execute(); $result = $stmt->get_result(); echo "Query Results: " . $result->num_rows . " EventKey: " . $eventKey . " " . $eventTitle . "<br>"; if($result->num_rows > 0){ echo "Rows: ==" . $result->num_rows . "<br>"; // 预处理执行更新 $update = "UPDATE calendar SET url=?, image=?, description=?, location=?, start_date=?, end_date=?, color='FFB819' WHERE event_key LIKE ? AND event=?"; $update_stmt = $connection->prepare($update); $update_stmt->bind_param("ssssssss", $eventURL, $eventImage, $eventDesc, $eventLocat, $eventStart, $eventEnd, $like_event_key, $eventTitle); $update_stmt->execute(); $update_stmt->close(); }else{ echo "Rows: #" . $result->num_rows . "<br>"; // 预处理查询同eventKey前缀的记录数 $key_sql = "SELECT * FROM calendar WHERE event_key LIKE ?"; $key_stmt = $connection->prepare($key_sql); $key_stmt->bind_param("s", $like_event_key); $key_stmt->execute(); $key_result = $key_stmt->get_result(); $eventNum = $key_result->num_rows; $eventNum++; echo "Query 2 Rows: ##" . $eventNum . "<br>"; $key_stmt->close(); // 格式化eventNum if($eventNum < 10){ $eventNum = "00" . $eventNum; }elseif($eventNum < 100){ $eventNum = "0" . $eventNum; } $eventNum = $eventKey . $eventNum; echo "Event#: " . $eventNum . "<br>"; // 预处理执行插入 $insert = "INSERT INTO calendar (event_num, event, url, image, description, location, start_date, end_date, color) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; $insert_stmt = $connection->prepare($insert); $insert_stmt->bind_param("sssssssss", $eventNum, $eventTitle, $eventURL, $eventImage, $eventDesc, $eventLocat, $eventStart, $eventEnd, 'FFB819'); $insert_stmt->execute(); $insert_stmt->close(); } $stmt->close(); echo "==============================================================================<br>"; }
最后小提示
测试用的echo语句上线前记得注释或删除,避免泄露敏感数据;另外确保你的数据库用户权限最小化,只给必要的增删改查权限。
内容的提问来源于stack exchange,提问作者PrismaPixel Studios
相关产品推荐
相关产品推荐

