검색 쿼리 질문입니다.
본문
A 테이블에 (징계관련 테이블)
같은 mb_id 가 여러개 insert 가 가능한데요.
운영자가 회원을 징계하면 A테이블에 해당 내용이 쌓입니다.
이때 징계 횟수를 구분짓기 위해서
운영자가 a회원을 징계를 하면
1. A 테이블에 a회원의 징계 기록이 있는지 조회한다.
2. A 테이블에 a회원의 징계 기록이 있다면 insert 될 row에 stack 칼럼을 stack = stack +1 해준다.
이런 프로세스로 운영됩니다.
그래서
최초 A테이블의 자료를 보게되면
id = a | reason = 회원기만 | nick = gnu | stack = 1
id = a | reason = 광고홍보 | nick = gnu | stack = 2
이런 식으로 쌓이는데요.
이게 여러명이 될 경우에 검색에 조금 문제가 생겨버립니다.
id = a | reason = 회원기만 | nick = gnu | stack = 1
id = a | reason = 광고홍보 | nick = gnu | stack = 2
id = b | reason = 회원기만 | nick = kkk | stack = 1
id = b | reason = 광고홍보 | nick = kkk | stack = 2
id = b | reason = 광고홍보 | nick = kkk | stack = 3
만약 이렇게 쌓여있고
stack 이 2인 값을 검색 한다면
제가 원하는 값은
id = a | reason = 광고홍보 | nick = gnu | stack = 2
이렇게 하나만 나오게 하고 싶습니다..
근데 지금은
id = a | reason = 광고홍보 | nick = gnu | stack = 2
id = b | reason = 광고홍보 | nick = kkk | stack = 2
이렇게 b회원까지 나와버립니다.
b 회원은 stack이 3일때 나와야 하는데 말이죠;;
아래는 징계누적 페이지의 소스입니다.
<?php
$sub_menu = "860010";
include_once('./_common.php');
auth_check($auth[$sub_menu], 'w');
$g5['title'] = '징계';
include_once('./admin.head.php');
$colspan = 8;
$punish_table = 'g5_punish';
// 게시물 ////////////////////////////////////////////////////
$sop = strtolower($sop);
if ($sop != 'and' && $sop != 'or')
$sop = 'and';
$stx = trim($stx);
if ($sca || $stx) {
$sql_search = get_sql_admin_search($sca, $sfl, $stx, $sop);
// 가장 작은 번호를 얻어서 변수에 저장 (하단의 페이징에서 사용)
$sql = " select MIN(punish_no) as min_punish_id from {$punish_table} ";
$row = sql_fetch($sql);
$min_spt = (int)$row['min_punish_id'];
if (!$spt) $spt = $min_spt;
$sql_search .= " and (punish_no between {$spt} and ({$spt} + {$config['cf_search_part']})) ";
// 원글만 얻는다. (코멘트의 내용도 검색하기 위함)
// 라엘님 제안 코드로 대체 http://sir.kr/g5_bug/2922
// $sql = " SELECT COUNT(DISTINCT `wr_parent`) AS `cnt` FROM {$punish_table} WHERE {$sql_search} ";
$sql = " SELECT COUNT(*) AS `cnt` FROM {$punish_table} WHERE {$sql_search} ";
$row = sql_fetch($sql);
$total_count = $row['cnt'];
/*
$sql = " select distinct wr_parent from {$punish_table} where {$sql_search} ";
$result = sql_query($sql);
$total_count = sql_num_rows($result);
*/
} else {
$sql = " select count(distinct punish_id) as cnt from {$punish_table} where 1=1";
$row = sql_fetch($sql);
$sql_search = "";
$total_count = $row['cnt'];
}
$page_rows = 25;
$list_page_rows = 25;
if ($page < 1) { $page = 1; } // 페이지가 없으면 첫 페이지 (1 페이지)
// 년도 2자리
$today2 = G5_TIME_YMD;
$total_page = ceil($total_count / $page_rows); // 전체 페이지 계산
$from_record = ($page - 1) * $page_rows; // 시작 열을 구함
// 정렬에 사용하는 QUERY_STRING
$qstr2 = 'punish=punish_sum&sop='.$sop;
// 정렬
// 인덱스 필드가 아니면 정렬에 사용하지 않음
// if (!$sst || ($sst && !(strstr($sst, 'wr_id') || strstr($sst, "wr_datetime")))) {
// sst = 검색정렬필드
// sca = 카테고리
// sfl = 검색필드
// stx = 검색어
// sod = 검색오름, 내림차순
// sop = 검색 or, and 오퍼레이터
// spt = 검색 파트(구간)
if (!$sst) {
if ($board['bo_sort_field']) {
$sst = $board['bo_sort_field'];
} else {
$sst = " punish_no DESC"; // 징계횟수 많은순, 징계날짜 최신순
$sod = "";
}
} else {
// 게시물 리스트의 정렬 대상 필드가 아니라면 공백으로 (nasca 님 09.06.16)
// 리스트에서 다른 필드로 정렬을 하려면 아래의 코드에 해당 필드를 추가하세요.
// $sst = preg_match("/^(wr_subject|wr_datetime|wr_hit|wr_good|wr_nogood)$/i", $sst) ? $sst : "";
$sst = preg_match("/^(wr_datetime|wr_hit|wr_good|wr_nogood)$/i", $sst) ? $sst : "";
}
if(!$sst)
$sst = " punish_no DESC"; // 신고횟수
if ($sst) {
$sql_order = "ORDER BY {$sst} {$sod}";
// $sql_order = " GROUP BY punish_id ORDER BY {$sst} {$sod} "; 2018-05-03 누적징계횟수 group by
}
if ($sca || $stx) {
if ($sfl == "punish_stack") {
$sql_where_stack = " "; // 이부분에 where 절을 써서 구분지을수 있을지!?
}
$sql = " SELECT * FROM {$punish_table} WHERE {$sql_search} {$sql_where_stack} {$sql_order} limit {$from_record}, $page_rows";
} else {
/* 2018-05-03 누적징계횟수 group by */
$sql = " SELECT tt.*
FROM {$punish_table} tt
INNER JOIN
(SELECT punish_id, max(punish_stack) AS maxPunishStack
FROM {$punish_table}
GROUP BY punish_id) groupedtt
ON tt.punish_id = groupedtt.punish_id
AND tt.punish_stack = groupedtt.maxPunishStack
{$sql_order}
LIMIT {$from_record}, $page_rows
";
}
echo $sql;
if ($page_rows > 0) {
$result = sql_query($sql);
$i = 0;
$k = 0;
$list = array();
while ($row = sql_fetch_array($result)) {
$punish_list = array_push($list, $row);
$list_num = $total_count - ($page - 1) * $list_page_rows;
$list[$i]['num'] = $list_num - $k;
$delete_href ='./punish_delete.php?punish_no='.$row['punish_no'].'&token='.$token.'&page='.$page; // 2018-04-27 .urldecode($qstr) 삭제함.
$list[$i]['delete_href'] = $delete_href;
$i++;
$k++;
}
}
$write_pages = get_paging(25, $page, $total_page, $_SERVER['SCRIPT_NAME'] . '?' . $qstr . '&page=');
////////////////////////////////////////////////////
?>
<form name="fboardlist" id="fboardlist" action="./board_list_update.php" onsubmit="return fboardlist_submit(this);" method="post">
<input type="hidden" name="bo_table" value="<?php echo $bo_table ?>">
<input type="hidden" name="sfl" value="<?php echo $sfl ?>">
<input type="hidden" name="stx" value="<?php echo $stx ?>">
<input type="hidden" name="spt" value="<?php echo $spt ?>">
<input type="hidden" name="sca" value="<?php echo $sca ?>">
<input type="hidden" name="sst" value="<?php echo $sst ?>">
<input type="hidden" name="sod" value="<?php echo $sod ?>">
<input type="hidden" name="page" value="<?php echo $page ?>">
<input type="hidden" name="sw" value="">
<div class="tbl_head01 tbl_wrap total_punish_wrap">
<table>
<caption>누적 신고</caption>
<thead>
<tr>
<th scope="col" class="td_num">번호</th>
<th scope="col" class="td_id">아이디</th>
<th scope="col" class="td_nick">닉네임</th>
<th scope="col" class="td_kind">징계종류</th>
<th scope="col" class="td_memo">징계내용</th>
<th scope="col" class="td_datetime">징계기간(일자)</th>
<th scope="col" class="td_stack">누적징계횟수</th>
<th scope="col" class="td_note">메모</th>
<th scope="col" class="td_check">삭제</th>
</tr>
</thead>
<tbody>
<?php
$today = date("Y-m-d");
for ($i = 0; $i<count($list); $i++) {
$bg = 'bg' . ($i % 2);
?>
<tr class="<?php echo $bg; ?>">
<td scope="row" class="td_num">
<?php echo $list[$i]['num']; ?>
</td>
<td scope="row" class="td_id">
<?php echo $list[$i]['punish_id']; ?>
</td>
<td scope="row" class="td_nick">
<?php echo $list[$i]['punish_nick']; ?>
</td>
<td scope="row" class="td_kind">
<?php echo $list[$i]['punish_kind']; ?>
</td>
<td scope="row" class="td_memo">
<?php echo $list[$i]['punish_memo']; ?>
</td>
<td scope="row" class="td_datetime">
<?php
$year = date("Y"); // 이번년도
$start_year = substr($list[$i]['punish_start_datetime'],0,4); // 징계시작 년도만 ex) 2018
$end_year = substr($list[$i]['punish_end_datetime'],0,4); // 징계끝 년도만 ex) 2018
$punish_start_year_time = substr($list[$i]['punish_start_datetime'],2,9); // 2018.xx.xx로 변환
$punish_end_year_time = substr($list[$i]['punish_end_datetime'],2,9); // 2018.xx.xx로 변환
$punish_start_time = substr($list[$i]['punish_start_datetime'],5,5); // xx.xx (월일만)
$punish_end_time = substr($list[$i]['punish_end_datetime'],5,5); // xx.xx (월일만)
if ($list[$i]['punish_kind'] == "경고" && $year == $start_year && $year == $end_year) { // 경고이고 징계시작과 끝이 같은 년도라면
$punish_datetime = $punish_start_year_time."~".$punish_end_time;
} else {
$punish_datetime = $punish_start_year_time;
}
?>
<?php echo $punish_datetime; ?>
</td>
<td scope="row" class="td_stack">
<?php echo $list[$i]['punish_stack']; ?>
</td>
<td scope="row" class="td_note">
<?php echo $list[$i]['punish_note']; ?>
</td>
<td scope="row" class="td_check">
<!--
<input type="checkbox" value="<?php echo $list[$i]['punish_no'] ?>" name="chk_punish_<?php echo $list[$i]['punish_no'] ?>" id="chk_punish_<?php echo $list[$i]['punish_no'] ?>">
-->
<a href="<?php echo $list[$i]['delete_href'] ?>" onclick="del(this.href); return false;" id="btnDelete">삭제</a>
</td>
</tr>
<?php } ?>
<?php if($i == 0 ) { ?><tr><td colspan="8" style="text-align: center; line-height:50px">자료가 없습니다.</td></tr><?php } ?>
</tbody>
</table>
</div>
</form>
<?php echo $write_pages; ?>
<div class="btn_wrap">
<?php if ($stx) {?>
<a href="./punish_sum.php" target="_self" id="btnList">목록</a>
<?php } ?>
</div>
<fieldset class="punish_sum_search">
<form name="fsearch" id="fsearch" method="get">
<label for="sfl" class="sound_only">검색대상</label>
<select name="sfl" id="sfl">
<option value="punish_id"<?php echo get_selected($sfl, "punish_id"); ?>>회원아이디</option>
<option value="punish_nick"<?php echo get_selected($sfl, "punish_nick"); ?>>닉네임</option>
<option value="punish_kind"<?php echo get_selected($sfl, "punish_kind"); ?>>종류</option>
<option value="punish_memo"<?php echo get_selected($sfl, "punish_memo"); ?>>내용</option>
<option value="punish_start_datetime || punish_end_datetime"<?php echo get_selected($sfl, "punish_start_datetime || punish_end_datetime"); ?>>일자</option>
<option value="punish_stack"<?php echo get_selected($sfl, "punish_stack"); ?>>징계횟수</option>
</select>
<label for="stx" class="sound_only">검색어<strong class="sound_only"> 필수</strong></label>
<input type="text" name="stx" value="<?php echo $stx ?>" id="stx" required class="required frm_input">
<input type="submit" value="검색" class="btn_submit">
</form>
</fieldset>
<style>
.total_punish_wrap td{text-align: center}
.td_num{width: 50px}
.td_id{width: 120px}
.td_kind{width: 200px}
.td_nick{width: 120px}
.td_memo{width: 120px}
.td_datetime{width: 200px}
.td_stack{width: 60px}
.td_check{width: 60px}
.punish_sum_search {
margin: 0 0 10px;
padding: 0 20px;
text-align: center;
}
.punish_sum_search select,
.punish_sum_search .frm_input,
.punish_sum_search .btn_submit{
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
height: 30px;
line-height: 30px;
}
.punish_sum_search .btn_submit{
width: 80px;
}
#btnList{
display: inline-block;
width: 50px;
height: 30px;
line-height: 30px;
text-align: center;
background: #e2e2e2;
}
.btn_wrap{
margin: 0 0 10px;
padding: 0 20px;
text-align: right;
}
</style>
<?php
include_once('./admin.tail.php');
?>
!-->
답변 3
검색 조건이 확실하지가 않네요
stack = 2 인 사람을 검색한다면 2개가 나오는게 맞습니다.
검색 조건이 회원의 마지막 징계리스트를 구하는 것이라면
select b.* from
(select mb_id, max(stack) as stack from A_table group by mb_id) as a
left join A_table as b on a.mb_id = b.mb_id and a.stack = b.stack
이정도 되지 않을까요??? 에러나려나???
테이블자료가 없서서 실행해 보지는 못하네요ㅠㅠ
이것은 2가 마지막인 사람
select b.* from
(select mb_id, max(stack) as stack from A_table group by mb_id having stack = '2') as a
left join A_table as b on a.mb_id = b.mb_id and a.stack = b.stack
이럴땐 해당 테이블내에서 중복갯수를 구하는 쿼리를 이용하시면됩니다
select *,count(*) from 테이블명 group by id having count(*)=검색숫자
group by로 중복되는 id값들을 묶어주고 해당 id에 대한 테이블에서 스택갯수를 구합니다
그럼 count(*)에 몇번 신고가되었는지 집계가 될것이고 count(*)를 통해서 검색시 숫자를 집어넣어 카운트가 2개인것만 찾으면 되는겁니다
라고 생각하긴했는데
스택이 초기화될 경우도 있겠다 싶어 (기록은남고)
select * from 테이블명 where stack=검색시숫자 group by id
이런식으로 하시면 가장 최근 값만 남기고 합쳐지니 될것같습니다
초기화되는 경우가 아니면 위쪽이 좀더 정확하겠네요
테이블 이렇게 생겼습니다