viw 게시된 글

TypeScript 4.x + React 17 + ag-Grid 환경에서 Scenario, Process (Target, No Start, Success, Failed, Error), Comparison (Target, Success, Failed) 항목을 2단 헤더 구조로 구성한 예제를 아래에 제공합니다.

아래 예제는 다음을 포함합니다:

ag-Grid 2단(header group) 구조 설정

React 17, TypeScript 환경

Scenario, Process, Comparison 3개의 그룹 컬럼

// App.tsx
import React from "react";
import { AgGridReact } from "ag-grid-react";
import "ag-grid-community/styles/ag-grid.css";
import "ag-grid-community/styles/ag-theme-alpine.css";
import { ColDef, ColGroupDef } from "ag-grid-community";

const App: React.FC = () => {
const columnDefs: (ColDef | ColGroupDef)[] = [

{
  headerName: "Scenario",
  children: [
    { headerName: "Scenario", field: "scenario", width: 150 }
  ],
},
{
  headerName: "Process",
  children: [
    { headerName: "Target", field: "processTarget", width: 120 },
    { headerName: "No Start", field: "processNoStart", width: 120 },
    { headerName: "Success", field: "processSuccess", width: 120 },
    { headerName: "Failed", field: "processFailed", width: 120 },
    { headerName: "Error", field: "processError", width: 120 },
  ],
},
{
  headerName: "Comparison",
  children: [
    { headerName: "Target", field: "comparisonTarget", width: 120 },
    { headerName: "Success", field: "comparisonSuccess", width: 120 },
    { headerName: "Failed", field: "comparisonFailed", width: 120 },
  ],
},

];

const rowData = [

{
  scenario: "Scenario A",
  processTarget: 100,
  processNoStart: 10,
  processSuccess: 80,
  processFailed: 5,
  processError: 5,
  comparisonTarget: 100,
  comparisonSuccess: 75,
  comparisonFailed: 25,
},
{
  scenario: "Scenario B",
  processTarget: 200,
  processNoStart: 20,
  processSuccess: 160,
  processFailed: 10,
  processError: 10,
  comparisonTarget: 200,
  comparisonSuccess: 150,
  comparisonFailed: 50,
},

];

return (

<div className="ag-theme-alpine" style={{ height: 400, width: "100%" }}>
  <AgGridReact
    columnDefs={columnDefs}
    rowData={rowData}
    domLayout="autoHeight"
  />
</div>

);
};

export default App;

MariaDB에서 SELECT 절에서 중복된 결과를 제거하려면 DISTINCT 키워드를 사용합니다.

기본 문법

SELECT DISTINCT column1, column2, ...
FROM table_name;

예시

예제 테이블: students

idnamemajor
1AliceCS
2BobMath
3AliceCS
4DavePhysics
SELECT DISTINCT name, major FROM students;

결과:

namemajor
AliceCS
BobMath
DavePhysics
DISTINCT는 지정한 열의 전체 조합이 중복일 때만 제거합니다.

단일 컬럼 중복 제거

SELECT DISTINCT name FROM students;

이 경우 name 값이 동일하면 한 번만 나타납니다.

참고사항

  • DISTINCTGROUP BY와도 유사한 결과를 낼 수 있지만, GROUP BY는 집계 함수와 함께 자주 사용됩니다.
  • DISTINCTORDER BY와 함께 사용해도 됩니다:

    SELECT DISTINCT name FROM students ORDER BY name;

원하는 컬럼 조합이나 예제가 있다면 알려주시면 구체적으로 도와드릴 수 있어요.

react17, typescript, ag-grid 환경에서 this.apiSet.api.forEachNode((node) => { 하여 그리드의 항목 중 activityNo:string; 항목(숫자가 입력 또는 빈값) 중 가장 큰 값을 구하고 그리드 목록 중 activityNo 빈값이 있으면 가장 큰 값에서 +1씩 증가하며 세팅하는 예제 만들어 주세요

// ActivityGrid.tsx
import React, { useRef, useCallback } from 'react';
import { AgGridReact } from 'ag-grid-react';
import { AgGridReact as AgGridReactType } from 'ag-grid-react/lib/agGridReact';
import { ColDef } from 'ag-grid-community';

import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';

interface RowDataType {
id: number;
activityNo: string;
name: string;
}

const initialRowData: RowDataType[] = [
{ id: 1, activityNo: '3', name: 'Task A' },
{ id: 2, activityNo: '', name: 'Task B' },
{ id: 3, activityNo: '10', name: 'Task C' },
{ id: 4, activityNo: '', name: 'Task D' },
{ id: 5, activityNo: '2', name: 'Task E' },
];

const columnDefs: ColDef[] = [
{ field: 'id' },
{ field: 'activityNo' },
{ field: 'name' },
];

const ActivityGrid = () => {
const gridRef = useRef<AgGridReactType>(null);

const fillActivityNumbers = useCallback(() => {

const api = gridRef.current?.api;
if (!api) return;

const nodes: RowDataType[] = [];
api.forEachNode(node => {
  if (node.data) {
    nodes.push(node.data);
  }
});

// 1. 최대 숫자 추출
const activityNumbers = nodes
  .map(row => parseInt(row.activityNo))
  .filter(num => !isNaN(num));

let max = activityNumbers.length > 0 ? Math.max(...activityNumbers) : 0;

// 2. 빈 값 채우기
nodes.forEach(row => {
  if (!row.activityNo || row.activityNo.trim() === '') {
    max += 1;
    row.activityNo = String(max);
  }
});

// 3. 변경 사항 적용
api.setRowData([...nodes]);

}, []);

return (

<div>
  <button onClick={fillActivityNumbers}>Fill Empty Activity Numbers</button>
  <div className="ag-theme-alpine" style={{ height: 300, width: 600 }}>
    <AgGridReact
      ref={gridRef}
      rowData={initialRowData}
      columnDefs={columnDefs}
      domLayout="autoHeight"
    />
  </div>
</div>

);
};

export default ActivityGrid;

mariadb에서 from_dt는 DATE 형입니다. React 화면에서 '2025-06-02T01:59:30.885Z' 전달되어 실행 결과 Incorrect data value 오류가 발생하였습니다. 해결 방법 알려주세요

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeParseException;
import java.time.format.DateTimeFormatter;

public class DateParser {

private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

/**
 * ISO 8601 문자열을 "yyyy-MM-dd" 형식 문자열로 변환
 * - 유효하지 않은 경우 null 반환
 */
public static String parseToDateString(String isoString) {
    if (isoString == null || isoString.trim().isEmpty()) {
        return null;
    }

    try {
        Instant instant = Instant.parse(isoString);
        LocalDate localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate();
        return localDate.format(DATE_FORMATTER);
    } catch (DateTimeParseException e) {
        return null;
    }
}

}

아오이 츠카사, Tsukasa Aoi, 葵つかさ

아오이 츠카사 닮은 아름다운 동아시아 여성, 고운 피부와 큰 아몬드 모양의 눈, 부드러운 분홍색 입술, 섬세하고 우아한 얼굴, 온화한 눈,
부드러운 자연 채광과 함께 영화적이고 고요하며 시적인 분위기입니다.

A beautiful East Asian woman looking back over her shoulder in a snowy outdoor setting. She has a delicate and elegant face with fair skin, large almond-shaped eyes, soft pink lips, and a slightly melancholic expression. Her medium-length dark brown hair is softly swept across her face by the wind. She is wearing a dark winter coat. Gentle snowfall surrounds her, and the background is a blurred forest with muted winter colors. The atmosphere is cinematic, serene, and poetic, with soft natural lighting."