검색 쿼리 질문입니다.

검색 쿼리 질문입니다.

QA

검색 쿼리 질문입니다.

본문

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 b.* FROM 
   (SELECT punish_id, max(punish_stack) AS stack 
    FROM g5_punish 
    GROUP BY punish_id 
    HAVING punish_stack = '2') AS a 
LEFT JOIN g5_punish AS b on a.punish_id = b.punish_id AND a.stack = b.stack


having 절이 에러가 나는 이유가 뭘까요;;

이럴땐 해당 테이블내에서 중복갯수를 구하는 쿼리를 이용하시면됩니다

 

select *,count(*) from 테이블명 group by id having count(*)=검색숫자

 

group by로 중복되는 id값들을 묶어주고 해당 id에 대한 테이블에서 스택갯수를 구합니다

 

그럼 count(*)에 몇번 신고가되었는지 집계가 될것이고 count(*)를 통해서 검색시 숫자를 집어넣어 카운트가 2개인것만 찾으면 되는겁니다

 

라고 생각하긴했는데

 

스택이 초기화될 경우도 있겠다 싶어 (기록은남고)

 

select * from 테이블명 where stack=검색시숫자 group by id

이런식으로 하시면 가장 최근 값만 남기고 합쳐지니 될것같습니다

 

초기화되는 경우가 아니면 위쪽이 좀더 정확하겠네요

아마 말씀 하신 쿼리르 작성 하신다면
id = a | reason = 광고홍보 | nick = gnu | stack = 2

id = b | reason = 광고홍보 | nick = kkk | stack = 2
와 같은 결과가 출력 될꺼에요  group by id로 묶인 kkk 값에 stack 이 2인 값이 있기 때문에 해당 내용에 관해서는 윗분이 적어주신 서브쿼리를 이용한 방법이 가장 괜찮아 보입니다.

2040835312_1525422238.5754.jpg테이블 이렇게 생겼습니다

 

답변을 작성하시기 전에 로그인 해주세요.
전체 0 | RSS
QA 내용 검색
  • 개별 목록 구성 제목 답변작성자조회작성일
  • 질문이 없습니다.

회원로그인

(주)에스아이알소프트 / 대표:홍석명 / (06211) 서울특별시 강남구 역삼동 707-34 한신인터밸리24 서관 1404호 / E-Mail: admin@sir.kr
사업자등록번호: 217-81-36347 / 통신판매업신고번호:2014-서울강남-02098호 / 개인정보보호책임자:김민섭(minsup@sir.kr)
© SIRSOFT