티스토리 뷰
오류: SQLSTATE[HY093]: Invalid parameter number 해결하기
Coding Life 2025. 3. 23. 21:59오류의 원인은 :search 파라미터를 동일한 이름으로 여러 번 사용했기 때문입니다. PHP 7.3에서는 바인딩할 때 1:1 매칭이 필요하므로, 동일한 이름의 파라미터를 여러 번 사용할 수 없습니다. 해결 방법은 각 컬럼마다 고유한 파라미터 이름을 생성해서 사용하는 것입니다.
아래는 고유 파라미터 이름을 사용하도록 수정한 코드 예제입니다.

<?php
$header = isset($_REQUEST['header']) ? $_REQUEST['header'] : '';
$model_name = $_REQUEST['model_name'] ?? '';
if ($header === 'header')
require_once($_SERVER['DOCUMENT_ROOT'] . '/myheader.php');
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
$mode = isset($_REQUEST["mode"]) ? $_REQUEST["mode"] : '';
// 기존 데이터가 있으면 기본 선택할 값
$selectedModel = isset($row['model_name']) ? $row['model_name'] : '';
// 대분류 선택값
$selectedMajor = isset($row['major_category']) ? $row['major_category'] : '';
$tablename = 'bottombar';
$today = date("Y-m-d"); // 현재일자 변수지정
$currentDate = date("Y-m-d");
// fromdate 또는 todate가 빈 문자열이거나 null인 경우
if (!isset($fromdate) || $fromdate === "" || $fromdate === null ||
!isset($todate) || $todate === "" || $todate === null) {
$fromdate = date("Y-m-d", strtotime("2024-01-01"));
$todate = $currentDate; // 현재 날짜
$Transtodate = $todate;
} else {
// fromdate와 todate가 모두 설정된 경우
$Transtodate = $todate;
}
$orderby = " ORDER BY reg_date DESC ";
$SettingDate = " reg_date ";
// 기본 조건 (is_deleted가 NULL인 경우)
$conditions = ["is_deleted IS NULL"];
$bindParams = [];
// 날짜 범위 필터 추가
$conditions[] = "$SettingDate BETWEEN :fromdate AND :todate";
$bindParams[":fromdate"] = $fromdate;
$bindParams[":todate"] = $todate;
// model_name 필터 추가
if (!empty($model_name)) {
$conditions[] = "model_name = :model_name";
$bindParams[":model_name"] = $model_name;
}
// 테이블 컬럼 목록을 이용한 검색 조건 추가
if (!empty($search)) {
$columnQuery = $pdo->query("SHOW COLUMNS FROM {$DB}.{$tablename}");
$columns = $columnQuery->fetchAll(PDO::FETCH_COLUMN);
$searchConditions = [];
foreach ($columns as $index => $column) {
// 각 컬럼마다 고유한 파라미터 이름 생성
$paramName = ":search" . $index;
$searchConditions[] = "$column LIKE $paramName";
$bindParams[$paramName] = "%{$search}%";
}
if (!empty($searchConditions)) {
$conditions[] = "(" . implode(" OR ", $searchConditions) . ")";
}
}
// 최종 WHERE 조건 조립
$sqlWhere = implode(" AND ", $conditions);
$sql = "SELECT * FROM {$DB}.{$tablename} WHERE {$sqlWhere} {$orderby}";
print $sql;
print_r($bindParams);
// 실행 및 데이터 가져오기
try {
$stmh = $pdo->prepare($sql);
$stmh->execute($bindParams);
$total_row = $stmh->rowCount();
} catch (PDOException $e) {
echo "오류: " . $e->getMessage();
}
?>
주요 변경 사항:
- 고유 파라미터 생성:
foreach 반복문 내에서 $index 값을 이용해 :search0, :search1, …와 같이 고유한 파라미터 이름을 생성하고, 각 컬럼에 대해 개별적으로 바인딩합니다. - SQL 조립:
최종 WHERE 조건은 각 조건을 AND로 결합하고, 검색 조건은 괄호로 묶어 OR로 연결합니다.
이렇게 수정하면, PHP 7.3 환경에서 1:1 매칭을 충족하면서 동일한 검색어를 여러 컬럼에 대해 검사할 수 있습니다.
PHP 7.3에서 발생하는 "SQLSTATE[HY093]: Invalid parameter number" 오류 해결하기
PHP PDO를 이용해 SQL 쿼리를 작성할 때 "SQLSTATE[HY093]: Invalid parameter number" 오류가 발생하는 경우가 있습니다. 최근 프로젝트에서 검색어를 여러 컬럼에 적용하려고 작성한 코드를 수정하던 중 이 오류가 발생했는데, 그 원인과 해결 방법에 대해 자세히 설명해보고자 합니다.
오류 메시지에 나오는 "Invalid parameter number"는 SQL 쿼리 내에 사용한 바인딩 파라미터의 수와 실제로 바인딩한 값의 수가 일치하지 않을 때 발생합니다. 예를 들어, 검색어를 적용하기 위해 여러 컬럼에 동일한 파라미터인 :search를 사용하게 되면, PDO는 이 파라미터를 한 번만 바인딩하는 것으로 처리합니다. 하지만 쿼리에는 같은 이름의 플레이스홀더가 여러 개 존재하기 때문에, 실제로는 파라미터 개수와 쿼리 내의 플레이스홀더 개수가 맞지 않아 오류가 발생하는 것입니다.
PHP 7.3 버전에서는 바인딩 방식이 1:1 매칭을 철저하게 요구합니다. 이전 버전에서는 동일한 이름의 파라미터를 중복 사용해도 내부적으로 같은 값을 대입할 수 있었지만, PHP 7.3에서는 이를 허용하지 않습니다. 이 때문에 하나의 :search 파라미터를 여러 곳에 사용하면 PDO가 어떤 플레이스홀더에 어떤 값을 바인딩해야 하는지 혼란스러워하게 되어 오류가 발생하게 됩니다.
해결 방법은 간단합니다. 각 컬럼마다 고유한 파라미터 이름을 만들어서 사용하면 됩니다. 예를 들어, 컬럼이 10개라면 :search0, :search1, ... :search9와 같이 고유의 파라미터 이름을 부여하고, 각각 동일한 검색어를 바인딩합니다. 이렇게 하면 각 플레이스홀더가 개별적으로 처리되므로 PDO는 올바르게 값을 매칭할 수 있게 됩니다.
아래는 실제 코드에서 이 문제를 해결한 예제입니다.
코드에서는 먼저 SHOW COLUMNS 쿼리를 이용해 테이블의 컬럼 목록을 가져옵니다. 이후 검색어가 입력된 경우, 각 컬럼마다 고유 파라미터를 생성하여 조건을 추가합니다. 바인딩 파라미터 배열에 고유 파라미터와 해당 검색어 값(와일드카드 포함)을 추가하는 방식으로 쿼리를 구성합니다.
$conditions = ["is_deleted IS NULL"];
$bindParams = [];
// 날짜 범위 필터 추가
$conditions[] = "reg_date BETWEEN :fromdate AND :todate";
$bindParams[":fromdate"] = $fromdate;
$bindParams[":todate"] = $todate];
// model_name 필터 추가
if (!empty($model_name)) {
$conditions[] = "model_name = :model_name";
$bindParams[":model_name"] = $model_name;
}
// 테이블 컬럼 목록을 이용한 검색 조건 추가
if (!empty($search)) {
$columnQuery = $pdo->query("SHOW COLUMNS FROM {$DB}.{$tablename}");
$columns = $columnQuery->fetchAll(PDO::FETCH_COLUMN);
$searchConditions = [];
foreach ($columns as $index => $column) {
// 각 컬럼마다 고유한 파라미터 이름 생성
$paramName = ":search" . $index;
$searchConditions[] = "$column LIKE $paramName";
$bindParams[$paramName] = "%{$search}%";
}
if (!empty($searchConditions)) {
$conditions[] = "(" . implode(" OR ", $searchConditions) . ")";
}
}
이처럼 각 컬럼마다 고유한 파라미터를 만들면, 동일한 검색어를 적용하더라도 PDO는 각 플레이스홀더를 개별적으로 인식할 수 있습니다. 쿼리 작성 시 중요한 점은 SQL 내의 조건절과 바인딩 배열의 파라미터 이름이 정확히 일치해야 한다는 것입니다. 이 방식은 특히 PHP 7.3에서 더욱 엄격하게 적용되므로, 코드를 작성할 때 신경 써야 합니다.
또한, 위와 같은 방법은 SQL 인젝션 공격을 예방하는 보안상의 장점도 있습니다. 모든 외부 입력 값은 반드시 바인딩을 통해 처리하고, 직접 쿼리 문자열에 포함시키지 않는 것이 좋습니다. PDO의 바인딩 기능을 적절히 활용하면 쿼리의 가독성을 높이고, 데이터베이스와의 안정적인 통신을 보장할 수 있습니다.
이 글에서는 PHP 7.3에서 자주 발생하는 "SQLSTATE[HY093]: Invalid parameter number" 오류의 원인과 해결 방법에 대해 알아보았습니다. 동일한 파라미터 이름의 중복 사용 문제와 이를 고유한 파라미터 이름으로 해결하는 방법을 구체적인 코드 예제와 함께 살펴보았습니다. PHP로 웹 애플리케이션을 개발할 때, 특히 PDO를 이용한 쿼리 작성 시 이와 같은 세세한 부분에 주의를 기울이면 디버깅 시간을 크게 줄일 수 있습니다.
실제 프로젝트에 적용해보면, 여러 조건을 동적으로 조합하는 상황에서 바인딩 파라미터의 이름을 신경 쓰는 것이 얼마나 중요한지 알 수 있습니다. 동일한 검색어를 여러 컬럼에 적용해야 할 때, 위와 같이 각 컬럼마다 고유 파라미터를 생성해 사용하면 PDO에서 발생하는 바인딩 관련 오류를 효과적으로 해결할 수 있습니다.
PHP 7.3의 엄격한 바인딩 정책을 숙지하고, 코드를 작성하는 습관은 장기적으로 안정적이고 확장성 있는 애플리케이션 개발에 큰 도움이 됩니다. 다양한 검색 조건과 필터링 기능을 구현하는 데 있어 이러한 방법을 적용해보면, 복잡한 조건문을 보다 쉽게 관리할 수 있을 것입니다.
'IT tech Coding > mysql' 카테고리의 다른 글
DELETE와 TRUNCATE의 차이점, 언제 어떤 걸 써야 할까? (0) | 2025.02.23 |
---|---|
PHP MySQL 검색 기능: 테이블 전체 컬럼에서 자동으로 검색하는 방법 (0) | 2025.02.16 |
PHP에서 Prepared Statement로 검색 결과가 나오지 않을 때 확인해야 할 점들 (0) | 2025.01.20 |
테이블 PRIMARY KEY와 AUTO_INCREMENT: 데이터베이스 오류 해결하기 (0) | 2025.01.12 |
PHP와 MySQL로 JSON 변환 및 저장하기: 기존 테이블 데이터 재구성 (0) | 2024.12.25 |
- Total
- Today
- Yesterday
- 엑셀입력보호
- 엑셀보호
- #데이터베이스설계
- #데이터무결성
- 코딩튜토리얼
- #tuigrid #자바스크립트그리드 #행삽입 #행삭제 #웹개발팁 #프론트엔드개발 #javascriptgrid #데이터테이블 #ui개선 #그리드커스터마이징
- #계층형데이터
- json파일편하게보는법
- General error: 2031
- 효율적코딩방법
- 엑셀셀보호
- json파일형태보기
- coalesce는 한국어로 "코얼레스크" 또는 "코얼리스"
- 구글드라이브API
- 오토핫키가이드
- 1. #웹개발 2. #로트번호 3. #성적서보기 4. #ajax 5. #jquery 6. #php 7. #프론트엔드 8. #백엔드 9. #부트스트랩 10. #웹기능구현
- #트리구조
- #textarea #자동높이조절 #ux개선 #웹개발 #프론트엔드 #자바스크립트 #html팁 #웹디자인 #uiux #코딩팁
- #카테고리트리
- #동적ui
- isset을 적용해야 하는 이유
- 웹제작강의안2주차
- 티스토리챌린지
- Bootstrap 5
- ajax오류메시지
- #웹개발
- 캐드자동작도
- 도면자동생성
- 오블완
- #php에러해결 #php경고메시지 #nonwellformednumeric #php초보자팁 #웹개발에러 #프로그래밍디버깅 #php정규식 #코드디버깅팁 #웹개발문제해결 #php숫자형변환
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |