From 40daa738f6d755514e2c954f34e433913274fa44 Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Mon, 5 Jan 2026 09:55:02 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=EB=9D=BC=EB=B2=A8=ED=95=A0=EB=8B=B9=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=97=90=20=EB=8F=84=EC=97=BD=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20=EB=9D=BC=EB=B2=A8=EB=9F=AC=20=EC=83=81=EC=84=B8?= =?UTF-8?q?=20=EC=A0=95=EB=B3=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../label/LabelAllocateApiController.java | 4 +- .../kamcoback/label/dto/LabelAllocateDto.java | 92 +++++++++++-------- .../label/service/LabelAllocateService.java | 5 +- .../core/LabelAllocateCoreService.java | 9 +- .../label/LabelAllocateRepositoryCustom.java | 9 +- .../label/LabelAllocateRepositoryImpl.java | 51 +++++++--- 6 files changed, 107 insertions(+), 63 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java index a95f0993..6869b636 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/LabelAllocateApiController.java @@ -150,8 +150,8 @@ public class LabelAllocateApiController { } @Operation( - summary = "작업현황 관리 > 상세 > 작업 이관 > 팝업 내 라벨러 상세 정보", - description = "작업현황 관리 > 상세 > 작업 이관 > 팝업 내 라벨러 상세 정보") + summary = "작업현황 관리 > 라벨러 상세 정보, 작업이관 팝업 내 라벨러 상세 정보 동일", + description = "작업현황 관리 > 라벨러 상세 정보, 작업이관 팝업 내 라벨러 상세 정보 동일") @GetMapping("/labeler-detail") public ApiResponseDto findLabelerDetail( @RequestParam(defaultValue = "01022223333") String userId, diff --git a/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java b/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java index eb7f2f9a..c0dd75a6 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/dto/LabelAllocateDto.java @@ -109,42 +109,42 @@ public class LabelAllocateDto { description = "라벨러 할당 목록", example = """ - [ - { - "userId": "123456", - "demand": 1000 - }, - { - "userId": "010222297501", - "demand": 400 - }, - { - "userId": "01022223333", - "demand": 440 - } - ] - """) + [ + { + "userId": "123456", + "demand": 1000 + }, + { + "userId": "010222297501", + "demand": 400 + }, + { + "userId": "01022223333", + "demand": 440 + } + ] + """) private List labelers; @Schema( description = "검수자 할당 목록", example = """ - [ - { - "inspectorUid": "K20251216001", - "userCount": 1000 - }, - { - "inspectorUid": "01022225555", - "userCount": 340 + [ + { + "inspectorUid": "K20251216001", + "userCount": 1000 }, - { - "inspectorUid": "K20251212001", - "userCount": 500 - } - ] - """) + { + "inspectorUid": "01022225555", + "userCount": 340 + }, + { + "inspectorUid": "K20251212001", + "userCount": 500 + } + ] + """) private List inspectors; } @@ -227,6 +227,9 @@ public class LabelAllocateDto { private Long completeCnt; private Long skipCnt; private Double percent; + private Integer ranking; + private ZonedDateTime createdDttm; + private String inspectorName; } @Getter @@ -244,17 +247,17 @@ public class LabelAllocateDto { description = "라벨러 할당 목록", example = """ - [ - { - "userId": "123456", - "demand": 10 - }, - { - "userId": "010222297501", - "demand": 5 - } - ] - """) + [ + { + "userId": "123456", + "demand": 10 + }, + { + "userId": "010222297501", + "demand": 5 + } + ] + """) private List labelers; @Schema(description = "비교년도", example = "2022") @@ -263,4 +266,13 @@ public class LabelAllocateDto { @Schema(description = "기준년도", example = "2024") private Integer targetYyyy; } + + @Getter + @Setter + @AllArgsConstructor + public static class AllocateInfoDto { + + private Long geoUid; + private String mapSheetNum; + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java b/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java index 80903df2..c919a5eb 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/service/LabelAllocateService.java @@ -3,6 +3,7 @@ package com.kamco.cd.kamcoback.label.service; import com.kamco.cd.kamcoback.config.api.ApiResponseDto; import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.AllocateInfoDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.TargetInspector; @@ -67,12 +68,12 @@ public class LabelAllocateService { ApiResponseCode.BAD_REQUEST, "총 잔여건수와 요청 값의 합계가 맞지 않습니다."); } - List allIds = + List allIds = labelAllocateCoreService.fetchNextIds(lastId, chargeCnt, compareYyyy, targetYyyy, stage); int index = 0; for (TargetUser target : targetUsers) { int end = index + target.getDemand(); - List sub = allIds.subList(index, end); + List sub = allIds.subList(index, end); labelAllocateCoreService.assignOwner(sub, target.getUserId(), compareYyyy, targetYyyy, stage); index = end; diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java index 56bca503..3e16eae5 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/LabelAllocateCoreService.java @@ -1,6 +1,7 @@ package com.kamco.cd.kamcoback.postgres.core; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.AllocateInfoDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList; @@ -20,13 +21,17 @@ public class LabelAllocateCoreService { private final LabelAllocateRepository labelAllocateRepository; - public List fetchNextIds( + public List fetchNextIds( Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) { return labelAllocateRepository.fetchNextIds(lastId, batchSize, compareYyyy, targetYyyy, stage); } public void assignOwner( - List ids, String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) { + List ids, + String userId, + Integer compareYyyy, + Integer targetYyyy, + Integer stage) { labelAllocateRepository.assignOwner(ids, userId, compareYyyy, targetYyyy, stage); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java index caf929c7..22988c98 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryCustom.java @@ -1,5 +1,6 @@ package com.kamco.cd.kamcoback.postgres.repository.label; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.AllocateInfoDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.UserList; @@ -12,11 +13,15 @@ import java.util.UUID; public interface LabelAllocateRepositoryCustom { - List fetchNextIds( + List fetchNextIds( Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage); void assignOwner( - List ids, String userId, Integer compareYyyy, Integer targetYyyy, Integer stage); + List ids, + String userId, + Integer compareYyyy, + Integer targetYyyy, + Integer stage); List findAssignedLabelerList( Integer compareYyyy, Integer targetYyyy, Integer stage); diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java index 6a68e9b3..9e52da12 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/label/LabelAllocateRepositoryImpl.java @@ -7,6 +7,7 @@ import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalEntity.mapShee import static com.kamco.cd.kamcoback.postgres.entity.QMemberEntity.memberEntity; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; +import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.AllocateInfoDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InspectState; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelState; @@ -17,6 +18,7 @@ import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerStatistics; import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity; import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataInferenceEntity; import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalEntity; +import com.kamco.cd.kamcoback.postgres.entity.QMemberEntity; import com.querydsl.core.types.Projections; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.CaseBuilder; @@ -49,11 +51,15 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @PersistenceContext private EntityManager em; @Override - public List fetchNextIds( + public List fetchNextIds( Long lastId, Long batchSize, Integer compareYyyy, Integer targetYyyy, Integer stage) { return queryFactory - .select(mapSheetAnalDataInferenceGeomEntity.geoUid) + .select( + Projections.constructor( + AllocateInfoDto.class, + mapSheetAnalDataInferenceGeomEntity.geoUid, + mapSheetAnalDataInferenceGeomEntity.mapSheetNum)) .from(mapSheetAnalDataInferenceGeomEntity) .where( lastId == null ? null : mapSheetAnalDataInferenceGeomEntity.geoUid.gt(lastId), @@ -68,7 +74,11 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto @Override public void assignOwner( - List ids, String userId, Integer compareYyyy, Integer targetYyyy, Integer stage) { + List ids, + String userId, + Integer compareYyyy, + Integer targetYyyy, + Integer stage) { // analUid로 분석 정보 조회 MapSheetAnalDataInferenceEntity analEntity = @@ -87,13 +97,16 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto } // data_geom 테이블에 label state 를 ASSIGNED 로 update + List geoUidList = + ids.stream().map(AllocateInfoDto::getGeoUid).filter(Objects::nonNull).toList(); + queryFactory .update(mapSheetAnalDataInferenceGeomEntity) .set(mapSheetAnalDataInferenceGeomEntity.labelState, LabelState.ASSIGNED.getId()) .set(mapSheetAnalDataInferenceGeomEntity.labelStateDttm, ZonedDateTime.now()) .set(mapSheetAnalDataInferenceGeomEntity.testState, InspectState.UNCONFIRM.getId()) .set(mapSheetAnalDataInferenceGeomEntity.testStateDttm, ZonedDateTime.now()) - .where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(ids)) + .where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(geoUidList)) .execute(); // 라벨러 할당 테이블에 insert @@ -105,13 +118,13 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto values (?, ?, ?, ?, ?, ?) """; - for (Long geoUid : ids) { + for (AllocateInfoDto info : ids) { em.createNativeQuery(sql) .setParameter(1, UUID.randomUUID()) - .setParameter(2, geoUid) + .setParameter(2, info.getGeoUid()) .setParameter(3, userId) .setParameter(4, LabelState.ASSIGNED.getId()) - .setParameter(5, "") + .setParameter(5, info.getMapSheetNum()) .setParameter(6, analEntity.getAnalUid()) .executeUpdate(); } @@ -572,24 +585,32 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto throw new EntityNotFoundException("MapSheetAnalEntity not found for analUid: "); } + QMemberEntity worker = QMemberEntity.memberEntity; + QMemberEntity inspector = new QMemberEntity("inspector"); + return queryFactory .select( Projections.constructor( LabelerDetail.class, - memberEntity.userRole, - memberEntity.name, - memberEntity.employeeNo, + worker.userRole, + worker.name, + worker.employeeNo, assignedCnt, skipCnt, completeCnt, - percent)) - .from(memberEntity) + percent, + Expressions.constant(0), // TODO: 순위, 꼭 해야할지? + labelingAssignmentEntity.createdDate.min(), + inspector.name.min())) + .from(worker) .innerJoin(labelingAssignmentEntity) .on( - memberEntity.employeeNo.eq(labelingAssignmentEntity.workerUid), + worker.employeeNo.eq(labelingAssignmentEntity.workerUid), labelingAssignmentEntity.analUid.eq(analEntity.getAnalUid())) - .where(memberEntity.employeeNo.eq(userId)) - .groupBy(memberEntity.userRole, memberEntity.name, memberEntity.employeeNo) + .leftJoin(inspector) + .on(labelingAssignmentEntity.inspectorUid.eq(inspector.employeeNo)) + .where(worker.employeeNo.eq(userId)) + .groupBy(worker.userRole, worker.name, worker.employeeNo) .fetchOne(); } } From 5eab38e1ea5807686cd46a037e4c5549ebf7fe99 Mon Sep 17 00:00:00 2001 From: teddy Date: Mon, 5 Jan 2026 10:04:57 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=ED=95=99=EC=8A=B5=EA=B4=80=EB=A6=AC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../label/LabelWorkerApiController.java | 48 ++++-- .../entity/MapSheetAnalInferenceEntity.java | 148 ++++++++++++++++++ 2 files changed, 180 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalInferenceEntity.java diff --git a/src/main/java/com/kamco/cd/kamcoback/label/LabelWorkerApiController.java b/src/main/java/com/kamco/cd/kamcoback/label/LabelWorkerApiController.java index 416f7738..5ca52652 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/LabelWorkerApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/LabelWorkerApiController.java @@ -4,20 +4,21 @@ import com.kamco.cd.kamcoback.code.dto.CommonCodeDto; import com.kamco.cd.kamcoback.config.api.ApiResponseDto; import com.kamco.cd.kamcoback.label.dto.LabelWorkDto; import com.kamco.cd.kamcoback.label.dto.LabelWorkDto.LabelWorkMng; +import com.kamco.cd.kamcoback.label.dto.LabelWorkDto.LabelWorkMngSearchReq; import com.kamco.cd.kamcoback.label.service.LabelWorkService; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @Slf4j @@ -31,20 +32,35 @@ public class LabelWorkerApiController { @Operation(summary = "라벨링작업 관리 > 목록 조회", description = "라벨링작업 관리 > 목록 조회") @ApiResponses( - value = { - @ApiResponse( - responseCode = "200", - description = "조회 성공", - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = CommonCodeDto.Basic.class))), - @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) - @PostMapping("/label-work-mng-list") + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = CommonCodeDto.Basic.class))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/label-work-mng-list") public ApiResponseDto> labelWorkMngList( - @RequestBody @Valid LabelWorkDto.LabelWorkMngSearchReq searchReq) { + @Schema(description = "변화탐지년도", example = "2024") + Integer detectYyyy, + @Schema(description = "시작일", example = "20260101") + String strtDttm, + @Schema(description = "종료일", example = "20261201") + String endDttm, + @Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0") + int page, + @Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20") + int size) { + LabelWorkDto.LabelWorkMngSearchReq searchReq = new LabelWorkMngSearchReq(); + searchReq.setDetectYyyy(detectYyyy); + searchReq.setStrtDttm(strtDttm); + searchReq.setEndDttm(endDttm); + searchReq.setPage(page); + searchReq.setSize(size); return ApiResponseDto.ok(labelWorkService.labelWorkMngList(searchReq)); } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalInferenceEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalInferenceEntity.java new file mode 100644 index 00000000..5a68209e --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalInferenceEntity.java @@ -0,0 +1,148 @@ +package com.kamco.cd.kamcoback.postgres.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; + +@Getter +@Setter +@Entity +@Table(name = "tb_map_sheet_anal_inference") +public class MapSheetAnalInferenceEntity { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tb_map_sheet_anal_inference_id_gen") + @SequenceGenerator(name = "tb_map_sheet_anal_inference_id_gen", sequenceName = "tb_map_sheet_anal_inference_uid", allocationSize = 1) + @Column(name = "anal_uid", nullable = false) + private Long id; + + @Column(name = "compare_yyyy") + private Integer compareYyyy; + + @Column(name = "target_yyyy") + private Integer targetYyyy; + + @Column(name = "model_uid") + private Long modelUid; + + @Size(max = 100) + @Column(name = "server_ids", length = 100) + private String serverIds; + + @Column(name = "anal_strt_dttm") + private ZonedDateTime analStrtDttm; + + @Column(name = "anal_end_dttm") + private ZonedDateTime analEndDttm; + + @Column(name = "anal_sec") + private Long analSec; + + @Size(max = 20) + @Column(name = "anal_state", length = 20) + private String analState; + + @Size(max = 20) + @Column(name = "gukyuin_used", length = 20) + private String gukyuinUsed; + + @Column(name = "accuracy") + private Double accuracy; + + @Size(max = 255) + @Column(name = "result_url") + private String resultUrl; + + @ColumnDefault("now()") + @Column(name = "created_dttm") + private ZonedDateTime createdDttm; + + @Column(name = "created_uid") + private Long createdUid; + + @ColumnDefault("now()") + @Column(name = "updated_dttm") + private ZonedDateTime updatedDttm; + + @Column(name = "updated_uid") + private Long updatedUid; + + @Size(max = 255) + @Column(name = "anal_title") + private String analTitle; + + @Column(name = "detecting_cnt") + private Long detectingCnt; + + @Column(name = "anal_pred_sec") + private Long analPredSec; + + @Column(name = "model_ver_uid") + private Long modelVerUid; + + @Column(name = "hyper_params") + @JdbcTypeCode(SqlTypes.JSON) + private Map hyperParams; + + @Column(name = "tranning_rate") + private List tranningRate; + + @Column(name = "validation_rate") + private List validationRate; + + @Column(name = "test_rate", length = Integer.MAX_VALUE) + private String testRate; + + @Size(max = 128) + @Column(name = "detecting_description", length = 128) + private String detectingDescription; + + @Size(max = 12) + @Column(name = "base_map_sheet_num", length = 12) + private String baseMapSheetNum; + + @ColumnDefault("gen_random_uuid()") + @Column(name = "uuid") + private UUID uuid; + + @Size(max = 50) + @Column(name = "model_m1_ver", length = 50) + private String modelM1Ver; + + @Size(max = 50) + @Column(name = "model_m2_ver", length = 50) + private String modelM2Ver; + + @Size(max = 50) + @Column(name = "model_m3_ver", length = 50) + private String modelM3Ver; + + @Size(max = 20) + @Column(name = "anal_target_type", length = 20) + private String analTargetType; + + @Column(name = "gukyuin_apply_dttm") + private ZonedDateTime gukyuinApplyDttm; + + @Size(max = 20) + @Column(name = "detection_data_option", length = 20) + private String detectionDataOption; + + @Column(name = "stage") + private Integer stage; + +} From 4cea4bb2ed5c03fd0187d1ba9a15e17e0533c0ea Mon Sep 17 00:00:00 2001 From: teddy Date: Mon, 5 Jan 2026 10:17:01 +0900 Subject: [PATCH 3/5] =?UTF-8?q?=ED=95=99=EC=8A=B5=EA=B4=80=EB=A6=AC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InferenceResultRepositoryImpl.java | 148 +++++++++--------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java index a1d7afb6..0fc5874a 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java @@ -17,15 +17,20 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC private final JPAQueryFactory queryFactory; - @PersistenceContext private final EntityManager em; + @PersistenceContext + private final EntityManager em; - /** tb_map_sheet_anal_data_inference */ + /** + * tb_map_sheet_anal_data_inference + */ private final QMapSheetAnalDataInferenceEntity inferenceEntity = - QMapSheetAnalDataInferenceEntity.mapSheetAnalDataInferenceEntity; + QMapSheetAnalDataInferenceEntity.mapSheetAnalDataInferenceEntity; - /** tb_map_sheet_anal_data_inference_geom */ + /** + * tb_map_sheet_anal_data_inference_geom + */ private final QMapSheetAnalDataInferenceGeomEntity inferenceGeomEntity = - QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity; + QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity; // =============================== // Upsert (Native only) @@ -34,33 +39,28 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC @Override public int upsertGroupsFromMapSheetAnal() { String sql = - """ - INSERT INTO tb_map_sheet_anal_inference ( - compare_yyyy, - target_yyyy, - anal_map_sheet, - stage, - anal_title - ) - SELECT - r.input1 AS compare_yyyy, - r.input2 AS target_yyyy, - r.map_id AS anal_map_sheet, - r.stage, - CONCAT(r.stage ,'_', r.input1 ,'_', r.input2 ,'_', r.map_id) as anal_title - FROM inference_results r - GROUP BY r.stage, r.input1, r.input2, r.map_id - ON CONFLICT (compare_yyyy, target_yyyy, anal_map_sheet, stage) - DO UPDATE SET - updated_dttm = now() + """ + + INSERT INTO tb_map_sheet_anal_inference ( + compare_yyyy, + target_yyyy, + stage, + anal_title + ) + SELECT + r.input1 AS compare_yyyy, + r.input2 AS target_yyyy, + r.stage, + CONCAT(r.stage ,'_', r.input1 ,'_', r.input2) AS anal_title + FROM inference_results r + GROUP BY r.stage, r.input1, r.input2; """; return em.createNativeQuery(sql).executeUpdate(); } /** - * inference_results 테이블을 기준으로 분석 데이터 단위(stage, compare_yyyy, target_yyyy, map_sheet_num)를 - * 생성/갱신한다. + * inference_results 테이블을 기준으로 분석 데이터 단위(stage, compare_yyyy, target_yyyy, map_sheet_num)를 생성/갱신한다. * *

- 최초 생성 시 file_created_yn = false - detecting_cnt는 inference_results 건수 기준 * @@ -70,7 +70,7 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC public int upsertGroupsFromInferenceResults() { String sql = - """ + """ INSERT INTO tb_map_sheet_anal_data_inference ( stage, compare_yyyy, @@ -113,7 +113,7 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC public int upsertGeomsFromInferenceResults() { String sql = - """ + """ INSERT INTO tb_map_sheet_anal_data_inference_geom ( uuid, stage, cd_prob, compare_yyyy, target_yyyy, map_sheet_num, class_before_cd, class_before_prob, class_after_cd, class_after_prob, @@ -188,12 +188,12 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC @Override public List findPendingDataUids(int limit) { return queryFactory - .select(inferenceEntity.id) - .from(inferenceEntity) - .where(inferenceEntity.fileCreatedYn.isFalse().or(inferenceEntity.fileCreatedYn.isNull())) - .orderBy(inferenceEntity.id.asc()) - .limit(limit) - .fetch(); + .select(inferenceEntity.id) + .from(inferenceEntity) + .where(inferenceEntity.fileCreatedYn.isFalse().or(inferenceEntity.fileCreatedYn.isNull())) + .orderBy(inferenceEntity.id.asc()) + .limit(limit) + .fetch(); } // =============================== @@ -212,13 +212,13 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC ZonedDateTime now = ZonedDateTime.now(); return (int) - queryFactory - .update(inferenceEntity) - .set(inferenceEntity.fileCreatedYn, false) - .set(inferenceEntity.fileCreatedDttm, (ZonedDateTime) null) - .set(inferenceEntity.updatedDttm, now) - .where(inferenceEntity.id.eq(dataUid)) - .execute(); + queryFactory + .update(inferenceEntity) + .set(inferenceEntity.fileCreatedYn, false) + .set(inferenceEntity.fileCreatedDttm, (ZonedDateTime) null) + .set(inferenceEntity.updatedDttm, now) + .where(inferenceEntity.id.eq(dataUid)) + .execute(); } /** @@ -231,13 +231,13 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC ZonedDateTime now = ZonedDateTime.now(); return (int) - queryFactory - .update(inferenceEntity) - .set(inferenceEntity.fileCreatedYn, true) - .set(inferenceEntity.fileCreatedDttm, now) - .set(inferenceEntity.updatedDttm, now) - .where(inferenceEntity.id.eq(dataUid)) - .execute(); + queryFactory + .update(inferenceEntity) + .set(inferenceEntity.fileCreatedYn, true) + .set(inferenceEntity.fileCreatedDttm, now) + .set(inferenceEntity.updatedDttm, now) + .where(inferenceEntity.id.eq(dataUid)) + .execute(); } /** @@ -250,13 +250,13 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC ZonedDateTime now = ZonedDateTime.now(); return (int) - queryFactory - .update(inferenceGeomEntity) - .set(inferenceGeomEntity.fileCreatedYn, false) - .set(inferenceGeomEntity.fileCreatedDttm, (ZonedDateTime) null) - .set(inferenceGeomEntity.updatedDttm, now) - .where(inferenceGeomEntity.dataUid.eq(dataUid)) - .execute(); + queryFactory + .update(inferenceGeomEntity) + .set(inferenceGeomEntity.fileCreatedYn, false) + .set(inferenceGeomEntity.fileCreatedDttm, (ZonedDateTime) null) + .set(inferenceGeomEntity.updatedDttm, now) + .where(inferenceGeomEntity.dataUid.eq(dataUid)) + .execute(); } /** @@ -274,13 +274,13 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC ZonedDateTime now = ZonedDateTime.now(); return (int) - queryFactory - .update(inferenceGeomEntity) - .set(inferenceGeomEntity.fileCreatedYn, true) - .set(inferenceGeomEntity.fileCreatedDttm, now) - .set(inferenceGeomEntity.updatedDttm, now) - .where(inferenceGeomEntity.geoUid.in(geoUids)) - .execute(); + queryFactory + .update(inferenceGeomEntity) + .set(inferenceGeomEntity.fileCreatedYn, true) + .set(inferenceGeomEntity.fileCreatedDttm, now) + .set(inferenceGeomEntity.updatedDttm, now) + .where(inferenceGeomEntity.geoUid.in(geoUids)) + .execute(); } // =============================== @@ -294,18 +294,18 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC */ @Override public List findGeomEntitiesByDataUid( - Long dataUid, int limit) { + Long dataUid, int limit) { return queryFactory - .selectFrom(inferenceGeomEntity) - .where( - inferenceGeomEntity.dataUid.eq(dataUid), - inferenceGeomEntity.geom.isNotNull(), - inferenceGeomEntity - .fileCreatedYn - .isFalse() - .or(inferenceGeomEntity.fileCreatedYn.isNull())) - .orderBy(inferenceGeomEntity.geoUid.asc()) - .limit(limit) - .fetch(); + .selectFrom(inferenceGeomEntity) + .where( + inferenceGeomEntity.dataUid.eq(dataUid), + inferenceGeomEntity.geom.isNotNull(), + inferenceGeomEntity + .fileCreatedYn + .isFalse() + .or(inferenceGeomEntity.fileCreatedYn.isNull())) + .orderBy(inferenceGeomEntity.geoUid.asc()) + .limit(limit) + .fetch(); } } From 829cb510e3ab429ecacbbe6218a23bad04180b16 Mon Sep 17 00:00:00 2001 From: teddy Date: Mon, 5 Jan 2026 10:17:24 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=20spotless=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../label/LabelWorkerApiController.java | 39 +++--- .../entity/MapSheetAnalInferenceEntity.java | 10 +- .../InferenceResultRepositoryImpl.java | 116 +++++++++--------- 3 files changed, 81 insertions(+), 84 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/label/LabelWorkerApiController.java b/src/main/java/com/kamco/cd/kamcoback/label/LabelWorkerApiController.java index 5ca52652..17d8844e 100644 --- a/src/main/java/com/kamco/cd/kamcoback/label/LabelWorkerApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/label/LabelWorkerApiController.java @@ -32,29 +32,26 @@ public class LabelWorkerApiController { @Operation(summary = "라벨링작업 관리 > 목록 조회", description = "라벨링작업 관리 > 목록 조회") @ApiResponses( - value = { - @ApiResponse( - responseCode = "200", - description = "조회 성공", - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = CommonCodeDto.Basic.class))), - @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = CommonCodeDto.Basic.class))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) @GetMapping("/label-work-mng-list") public ApiResponseDto> labelWorkMngList( - @Schema(description = "변화탐지년도", example = "2024") - Integer detectYyyy, - @Schema(description = "시작일", example = "20260101") - String strtDttm, - @Schema(description = "종료일", example = "20261201") - String endDttm, - @Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0") - int page, - @Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20") - int size) { + @Schema(description = "변화탐지년도", example = "2024") Integer detectYyyy, + @Schema(description = "시작일", example = "20260101") String strtDttm, + @Schema(description = "종료일", example = "20261201") String endDttm, + @Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0") + int page, + @Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20") + int size) { LabelWorkDto.LabelWorkMngSearchReq searchReq = new LabelWorkMngSearchReq(); searchReq.setDetectYyyy(detectYyyy); searchReq.setStrtDttm(strtDttm); diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalInferenceEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalInferenceEntity.java index 5a68209e..195721e1 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalInferenceEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetAnalInferenceEntity.java @@ -25,8 +25,13 @@ import org.hibernate.type.SqlTypes; public class MapSheetAnalInferenceEntity { @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tb_map_sheet_anal_inference_id_gen") - @SequenceGenerator(name = "tb_map_sheet_anal_inference_id_gen", sequenceName = "tb_map_sheet_anal_inference_uid", allocationSize = 1) + @GeneratedValue( + strategy = GenerationType.SEQUENCE, + generator = "tb_map_sheet_anal_inference_id_gen") + @SequenceGenerator( + name = "tb_map_sheet_anal_inference_id_gen", + sequenceName = "tb_map_sheet_anal_inference_uid", + allocationSize = 1) @Column(name = "anal_uid", nullable = false) private Long id; @@ -144,5 +149,4 @@ public class MapSheetAnalInferenceEntity { @Column(name = "stage") private Integer stage; - } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java index 0fc5874a..5c94e12f 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java @@ -17,20 +17,15 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC private final JPAQueryFactory queryFactory; - @PersistenceContext - private final EntityManager em; + @PersistenceContext private final EntityManager em; - /** - * tb_map_sheet_anal_data_inference - */ + /** tb_map_sheet_anal_data_inference */ private final QMapSheetAnalDataInferenceEntity inferenceEntity = - QMapSheetAnalDataInferenceEntity.mapSheetAnalDataInferenceEntity; + QMapSheetAnalDataInferenceEntity.mapSheetAnalDataInferenceEntity; - /** - * tb_map_sheet_anal_data_inference_geom - */ + /** tb_map_sheet_anal_data_inference_geom */ private final QMapSheetAnalDataInferenceGeomEntity inferenceGeomEntity = - QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity; + QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity; // =============================== // Upsert (Native only) @@ -39,7 +34,7 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC @Override public int upsertGroupsFromMapSheetAnal() { String sql = - """ + """ INSERT INTO tb_map_sheet_anal_inference ( compare_yyyy, @@ -60,7 +55,8 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC } /** - * inference_results 테이블을 기준으로 분석 데이터 단위(stage, compare_yyyy, target_yyyy, map_sheet_num)를 생성/갱신한다. + * inference_results 테이블을 기준으로 분석 데이터 단위(stage, compare_yyyy, target_yyyy, map_sheet_num)를 + * 생성/갱신한다. * *

- 최초 생성 시 file_created_yn = false - detecting_cnt는 inference_results 건수 기준 * @@ -70,7 +66,7 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC public int upsertGroupsFromInferenceResults() { String sql = - """ + """ INSERT INTO tb_map_sheet_anal_data_inference ( stage, compare_yyyy, @@ -113,7 +109,7 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC public int upsertGeomsFromInferenceResults() { String sql = - """ + """ INSERT INTO tb_map_sheet_anal_data_inference_geom ( uuid, stage, cd_prob, compare_yyyy, target_yyyy, map_sheet_num, class_before_cd, class_before_prob, class_after_cd, class_after_prob, @@ -188,12 +184,12 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC @Override public List findPendingDataUids(int limit) { return queryFactory - .select(inferenceEntity.id) - .from(inferenceEntity) - .where(inferenceEntity.fileCreatedYn.isFalse().or(inferenceEntity.fileCreatedYn.isNull())) - .orderBy(inferenceEntity.id.asc()) - .limit(limit) - .fetch(); + .select(inferenceEntity.id) + .from(inferenceEntity) + .where(inferenceEntity.fileCreatedYn.isFalse().or(inferenceEntity.fileCreatedYn.isNull())) + .orderBy(inferenceEntity.id.asc()) + .limit(limit) + .fetch(); } // =============================== @@ -212,13 +208,13 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC ZonedDateTime now = ZonedDateTime.now(); return (int) - queryFactory - .update(inferenceEntity) - .set(inferenceEntity.fileCreatedYn, false) - .set(inferenceEntity.fileCreatedDttm, (ZonedDateTime) null) - .set(inferenceEntity.updatedDttm, now) - .where(inferenceEntity.id.eq(dataUid)) - .execute(); + queryFactory + .update(inferenceEntity) + .set(inferenceEntity.fileCreatedYn, false) + .set(inferenceEntity.fileCreatedDttm, (ZonedDateTime) null) + .set(inferenceEntity.updatedDttm, now) + .where(inferenceEntity.id.eq(dataUid)) + .execute(); } /** @@ -231,13 +227,13 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC ZonedDateTime now = ZonedDateTime.now(); return (int) - queryFactory - .update(inferenceEntity) - .set(inferenceEntity.fileCreatedYn, true) - .set(inferenceEntity.fileCreatedDttm, now) - .set(inferenceEntity.updatedDttm, now) - .where(inferenceEntity.id.eq(dataUid)) - .execute(); + queryFactory + .update(inferenceEntity) + .set(inferenceEntity.fileCreatedYn, true) + .set(inferenceEntity.fileCreatedDttm, now) + .set(inferenceEntity.updatedDttm, now) + .where(inferenceEntity.id.eq(dataUid)) + .execute(); } /** @@ -250,13 +246,13 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC ZonedDateTime now = ZonedDateTime.now(); return (int) - queryFactory - .update(inferenceGeomEntity) - .set(inferenceGeomEntity.fileCreatedYn, false) - .set(inferenceGeomEntity.fileCreatedDttm, (ZonedDateTime) null) - .set(inferenceGeomEntity.updatedDttm, now) - .where(inferenceGeomEntity.dataUid.eq(dataUid)) - .execute(); + queryFactory + .update(inferenceGeomEntity) + .set(inferenceGeomEntity.fileCreatedYn, false) + .set(inferenceGeomEntity.fileCreatedDttm, (ZonedDateTime) null) + .set(inferenceGeomEntity.updatedDttm, now) + .where(inferenceGeomEntity.dataUid.eq(dataUid)) + .execute(); } /** @@ -274,13 +270,13 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC ZonedDateTime now = ZonedDateTime.now(); return (int) - queryFactory - .update(inferenceGeomEntity) - .set(inferenceGeomEntity.fileCreatedYn, true) - .set(inferenceGeomEntity.fileCreatedDttm, now) - .set(inferenceGeomEntity.updatedDttm, now) - .where(inferenceGeomEntity.geoUid.in(geoUids)) - .execute(); + queryFactory + .update(inferenceGeomEntity) + .set(inferenceGeomEntity.fileCreatedYn, true) + .set(inferenceGeomEntity.fileCreatedDttm, now) + .set(inferenceGeomEntity.updatedDttm, now) + .where(inferenceGeomEntity.geoUid.in(geoUids)) + .execute(); } // =============================== @@ -294,18 +290,18 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC */ @Override public List findGeomEntitiesByDataUid( - Long dataUid, int limit) { + Long dataUid, int limit) { return queryFactory - .selectFrom(inferenceGeomEntity) - .where( - inferenceGeomEntity.dataUid.eq(dataUid), - inferenceGeomEntity.geom.isNotNull(), - inferenceGeomEntity - .fileCreatedYn - .isFalse() - .or(inferenceGeomEntity.fileCreatedYn.isNull())) - .orderBy(inferenceGeomEntity.geoUid.asc()) - .limit(limit) - .fetch(); + .selectFrom(inferenceGeomEntity) + .where( + inferenceGeomEntity.dataUid.eq(dataUid), + inferenceGeomEntity.geom.isNotNull(), + inferenceGeomEntity + .fileCreatedYn + .isFalse() + .or(inferenceGeomEntity.fileCreatedYn.isNull())) + .orderBy(inferenceGeomEntity.geoUid.asc()) + .limit(limit) + .fetch(); } } From 6a77d0f4474cfa13febe127a36f51eef7e5e0408 Mon Sep 17 00:00:00 2001 From: teddy Date: Mon, 5 Jan 2026 10:17:52 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=20spotless=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InferenceResultRepositoryImpl.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java index 5c94e12f..1876e53c 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java @@ -35,20 +35,19 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC public int upsertGroupsFromMapSheetAnal() { String sql = """ - - INSERT INTO tb_map_sheet_anal_inference ( - compare_yyyy, - target_yyyy, - stage, - anal_title - ) - SELECT - r.input1 AS compare_yyyy, - r.input2 AS target_yyyy, - r.stage, - CONCAT(r.stage ,'_', r.input1 ,'_', r.input2) AS anal_title - FROM inference_results r - GROUP BY r.stage, r.input1, r.input2; + INSERT INTO tb_map_sheet_anal_inference ( + compare_yyyy, + target_yyyy, + stage, + anal_title + ) + SELECT + r.input1 AS compare_yyyy, + r.input2 AS target_yyyy, + r.stage, + CONCAT(r.stage ,'_', r.input1 ,'_', r.input2) AS anal_title + FROM inference_results r + GROUP BY r.stage, r.input1, r.input2; """; return em.createNativeQuery(sql).executeUpdate();