# Business Logic — JBSbatKKDelSavePrdKikData.countChkSvcKeiKaisenUcwkNo() [172 LOC]

| Field | Value |
|-------|-------|
| Fully Qualified Name | `eo.business.service.JBSbatKKDelSavePrdKikData` |
| Layer | Service (Data Integrity / Batch Deletion Guard) |
| Module | `service` (Package: `eo.business.service`) |

## 1. Role

### JBSbatKKDelSavePrdKikData.countChkSvcKeiKaisenUcwkNo()

This method enforces referential integrity during batch deletion of service contract line detail numbers (svc_kei_ucwk_no). Specifically, it validates whether a parent schema record can be safely deleted by checking that **every** parent record linked to a given parent key is also associated exclusively with keys marked for deletion. In business terms: before removing a set of child records, the method verifies that no remaining child record on the same parent depends on data that is **not** being deleted — preventing orphaned or partially-removed parent data.

The method implements a **count-comparison guard pattern**: it executes two separate SQL queries that both count distinct parent records associated with the same key, but differ in scope. Query 1 counts parent records linked to the specific subset of delete-candidate keys. Query 2 counts all parent records linked to the key regardless of deletion status. If the two counts are equal, it means every parent record is associated only with delete-candidate keys (safe to delete). If they differ, some parent record is tied to a non-delete-candidate key (deletion must be blocked).

It operates as a **shared utility** called exclusively by `delPsbChkSvcKeiKaisenUcwkNo()` from within the batch deletion workflow for service contract line items. The method is private and does not branch by service type — it is a generic integrity check parameterized by table name, key columns, and candidate key lists.

**Design pattern:** Gate/Guard with SQL count comparison. The method delegates database access to `JBSbatSQLAccess`, building dynamic SQL via `StringBuffer`, and follows a prepare-execute-fetch-close resource lifecycle.

## 2. Processing Pattern (Detailed Business Logic)

```mermaid
flowchart TD
    START(["countChkSvcKeiKaisenUcwkNo"]) --> INIT["Initialize: result=false, chkCount1=0, chkCount2=0, loopEnd=delKeyInfo.size()"]
    INIT --> CHECK_EMPTY{loopEnd != 0?}
    CHECK_EMPTY -->|No| SQL2_BUILD["Build SQL Query 2: COUNT DISTINCT all parent records linked to cntKey"]
    CHECK_EMPTY -->|Yes| SQL1_BUILD["Build SQL Query 1: COUNT DISTINCT parent records linked to delete-candidate keys"]
    SQL1_BUILD --> SQL1_EXEC["Execute SQL 1 via JBSbatSQLAccess"]
    SQL1_EXEC --> SQL1_FETCH["Fetch chkCount1 from ResultSet"]
    SQL1_FETCH --> SQL1_LOG["Debug log: TBL, strkey, chkCount1"]
    SQL1_LOG --> SQL1_CLOSE["Close ResultSet, PreparedStatement, db_CNT_TABLE"]
    SQL1_CLOSE --> SQL2_BUILD
    SQL2_BUILD["Build SQL Query 2: COUNT DISTINCT all parent records linked to cntKey"]
    SQL2_EXEC["Execute SQL 2 via JBSbatSQLAccess"]
    SQL2_EXEC --> SQL2_FETCH["Fetch chkCount2 from ResultSet"]
    SQL2_FETCH --> SQL2_LOG["Debug log: TBL, strkey, chkCount2"]
    SQL2_LOG --> SQL2_CLOSE["Close ResultSet, PreparedStatement, db_CNT_TABLE"]
    SQL2_CLOSE --> COMPARE{chkCount1 == chkCount2?}
    COMPARE -->|Yes| SET_RESULT["result = true (deletable)"]
    COMPARE -->|No| RETURN_RESULT["result = false (not deletable)"]
    SET_RESULT --> RETURN_RESULT
    RETURN_RESULT --> END(["return result"])
```

**Processing flow summary:**

1. **Initialization** — Set `result = false`, counters to 0, and compute `loopEnd` from `delKeyInfo.size()`.
2. **Delete-candidate key count (Query 1)** — If `delKeyInfo` is non-empty, build and execute a UNION ALL query counting distinct parent records where the string key column (`strkey`) equals `cntKey` AND the search key column (`searchKey`) is in the `delKeyInfo` list. The query also scans `KK_T_SVKEI_GRP_SETE` (service contract group settings) for the same key, restricted to `SVKEI_GRP_SBT_CD = '01'` (single usage location) and `MK_FLG = '0'`.
3. **All-key count (Query 2)** — Always executed. Builds a similar UNION ALL query but without the `delKeyInfo` IN-list filter, counting all distinct parent records where `strkey = cntKey`.
4. **Comparison** — If both counts are equal (`chkCount1 == chkCount2`), set `result = true` (deletable). Otherwise, `result` remains `false` (not deletable).

**Key distinction between Query 1 and Query 2:**
- Query 1 filters by `searchKey IN (delKeyInfo values)` — only parent records linked to delete-candidate keys.
- Query 2 does NOT filter by `delKeyInfo` — all parent records linked to the key.
- Equal counts ⇒ every parent record is exclusively tied to delete-candidate keys ⇒ safe to delete.
- Unequal counts ⇒ some parent records are tied to non-delete-candidate keys ⇒ must NOT delete.

## 3. Parameter Analysis

| No | Parameter Name | Type | Business Description |
|----|---------------|------|---------------------|
| 1 | `TBL` | `String` | **Parent schema name** — the database table containing the parent records to check for deletion safety. The value is dynamically substituted into the SQL FROM clause. Examples: `KK_T_KAISEN_TG_SVKEI` (service contract line detail). |
| 2 | `searchKey` | `String` | **Search key column name** — the column in the parent table that holds the parent schema value (e.g., svc_kei_ucwk_no). This column is what the COUNT DISTINCT operates on. |
| 3 | `strkey` | `String` | **String key column name** — the column in the parent table that references/links to a key value (e.g., svc_kei_no). The WHERE clause filters rows where this column equals `cntKey`. |
| 4 | `cntKey` | `String` | **Key value** — the specific value of the `strkey` column to search for. This represents the parent key (e.g., a service contract line number) whose related records are being evaluated for deletion. |
| 5 | `delKeyInfo` | `ArrayList<String>` | **Delete candidate key list** — the set of parent schema values (e.g., svc_kei_ucwk_no values) that are marked for deletion. Query 1 uses this list to count only parent records linked to these specific keys. |

**Instance fields read:**

| Field | Type | Business Description |
|-------|------|---------------------|
| `commonItem` | (unspecified) | Common item context object passed to `JBSbatSQLAccess` constructor for database connectivity configuration. |
| `db_CNT_TABLE` | `JBSbatSQLAccess` | Database access object reused for executing the count queries. Re-initialized before each query. |
| `logPrint` | (debug logger, via `super`) | Debug logging handle accessed through the parent class hierarchy. Used to emit SQL and count results to the debug log. |

## 4. CRUD Operations / Called Services

### Pre-computed evidence from code analysis graph:

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| R | `JBSbatSQLAccess` (constructor) | - | `TBL` (dynamic parent table) | Opens a database access connection to the parent schema table for SELECT operations. |
| R | `JBSbatSQLAccess.createStatement` | - | `TBL` (dynamic parent table) | Prepares a Statement object for executing the dynamically built SQL count query. |
| R | `PreparedStatement.executeQuery` | - | `TBL` (dynamic parent table) | Executes the UNION ALL SELECT query against the parent table and `KK_T_SVKEI_GRP_SETE`. Returns distinct record count. |
| R | `JBSbatSQLAccess` (constructor, Query 2) | - | `TBL` (dynamic parent table) | Re-opens database access connection for the second count query. |
| R | `JBSbatSQLAccess.createStatement` | - | `TBL` (dynamic parent table) | Prepares a Statement object for the second dynamically built SQL count query. |
| R | `PreparedStatement.executeQuery` | - | `TBL` (dynamic parent table) | Executes the second UNION ALL SELECT query without the delete-candidate filter. |
| - | `JACBatCommon.printDebugLog` | JACBatCommon | - | Logs the built SQL Query 1 (including delKeyInfo filter) to the debug log. |
| - | `JACBatCommon.printDebugLog` | JACBatCommon | - | Logs the built SQL Query 2 (without delKeyInfo filter) to the debug log. |
| - | `JACBatCommon.printDebugLog` | JACBatCommon | - | Logs Query 1 result: table name, strkey column, and chkCount1 value. |
| - | `JACBatCommon.printDebugLog` | JACBatCommon | - | Logs Query 2 result: table name, strkey column, and chkCount2 value. |
| - | `JACbatDataBnktUtil.close` | JACbatDataBnkt | - | Closes ResultSet `rs1` after reading chkCount1. |
| - | `JACbatDataBnktUtil.close` | JACbatDataBnkt | - | Closes ResultSet `rs2` after reading chkCount2. |
| - | `JACbatDataBnktUtil.close` | JACbatDataBnkt | - | Closes PreparedStatement `pstatmt1`. |
| - | `JACbatDataBnktUtil.close` | JACbatDataBnkt | - | Closes PreparedStatement `pstatmt2`. |
| - | `JACbatParamUtil.close` | JACbatParam | - | Closes `db_CNT_TABLE` after Query 1 execution. |
| - | `JACbatParamUtil.close` | JACbatParam | - | Closes `db_CNT_TABLE` after Query 2 execution. |

**CRUD classification:**
- All database interactions are **Read (R)** operations — this method only counts records; it never inserts, updates, or deletes any data.
- The two tables queried are: the dynamic parent table (`TBL` parameter) and `KK_T_SVKEI_GRP_SETE` (service contract group settings master table).
- No SC Codes are directly invoked as service components — the method uses raw SQL access through `JBSbatSQLAccess`.

## 5. Dependency Trace

| # | Caller (Screen/Batch) | Call Chain (Full Path to this Method) | Terminal (SC / CRUD / Entity) |
|---|----------------------|--------------------------------------|-------------------------------|
| 1 | Class: `delPsbChkSvcKeiKaisenUcwkNo()` | `delPsbChkSvcKeiKaisenUcwkNo()` -> `countChkSvcKeiKaisenUcwkNo(TBL, searchKey, strkey, cntKey, src_key_info)` | `executeQuery [R] KK_T_KAISEN_TG_SVKEI`, `executeQuery [R] KK_T_SVKEI_GRP_SETE` |

**Call chain detail:**
The caller `delPsbChkSvcKeiKaisenUcwkNo()` is the batch deletion pre-check method for service contract line detail numbers. It iterates over parent schema records retrieved from `KK_T_KK_M_KJNIFDEL_TGSCM` (delete-target schema master), and for each parent schema, calls `countChkSvcKeiKaisenUcwkNo()` to verify deletion safety. If the method returns `true` for all parent keys associated with a service contract line, the key is added to the safe-to-delete list.

No external screen or batch entry points were found within 8 hops. This is a private utility method used exclusively within the deletion workflow.

## 6. Per-Branch Detail Blocks

**Block 1** — [LOCAL VARIABLE DECLARATIONS] (L7410)

| # | Type | Code |
|---|------|------|
| 1 | SET | `result = false;` // Default to not deletable |
| 2 | SET | `chkCount1 = 0;` // Count of parent records linked to delete-candidate keys |
| 3 | SET | `chkCount2 = 0;` // Count of all parent records linked to cntKey |
| 4 | SET | `loopEnd = delKeyInfo.size();` // Number of delete candidate keys |

**Block 2** — [IF] `(loopEnd != 0)` (L7413)

> Execute Query 1: Count distinct parent records where the search key is in the delete-candidate key list. This query is only built and executed when `delKeyInfo` contains at least one element.

| # | Type | Code |
|---|------|------|
| 1 | EXEC | `sqlBuff1.append("SELECT COUNT(DISTINCT " + searchKey + ") ... UNION ALL ...")` // Build Query 1: Counts parent records linked to delKeyInfo |
| 2 | EXEC | `for (int i = 1; i < loopEnd; i++)` // Append remaining delKeyInfo values to IN-list |
| 3 | SET | `sqlBuff1.append(" ,'\"" + delKeyInfo.get(i) + "\" '")` // Append each candidate key to IN-list |
| 4 | SET | Query includes filter: `searchKey IN (delKeyInfo values)` |
| 5 | SET | Query includes filter: `strkey = cntKey` |
| 6 | SET | Query includes filter: `searchKey IS NOT NULL` |
| 7 | SET | Query includes filter: `MK_FLG = '0'` (soft-delete flag) |
| 8 | SET | UNION ALL subquery from `KK_T_SVKEI_GRP_SETE` with filters: `SVKEI_GRP_SKBT_NO = cntKey`, `SVKEI_GRP_SBT_CD = '01'` (single usage location), `searchKey IS NOT NULL`, `MK_FLG = '0'` |
| 9 | CALL | `super.logPrint.printDebugLog("【削除対象スキーマに紐付き、かつ親スキーマで削除対象となる件数】" + sqlBuff1.toString())` // Debug: log Query 1 SQL (Javadoc: "Search for the number of records linked to the delete-candidate schema and that are also deletion targets in the parent schema") |
| 10 | CALL | `db_CNT_TABLE = new JBSbatSQLAccess(commonItem, TBL)` // Create DB access object for query |
| 11 | CALL | `pstatmt1 = db_CNT_TABLE.createStatement(sqlBuff1.toString())` // Prepare Statement |
| 12 | CALL | `rs1 = pstatmt1.executeQuery()` // Execute Query 1 |
| 13 | EXEC | `while (rs1.next()) { chkCount1 = rs1.getInt(1); }` // Read count from result |
| 14 | EXEC | `rs1.close()` // Close ResultSet |
| 15 | CALL | `super.logPrint.printDebugLog("TBL1:" + TBL + ":検索KEY1:" + strkey + ":検索件数1:" + chkCount1)` // Debug: log Query 1 result |
| 16 | EXEC | `pstatmt1.close()` // Close PreparedStatement |
| 17 | IF | `(db_CNT_TABLE != null)` (L7485) — Close DB access after Query 1 |
| 18 | EXEC | `db_CNT_TABLE.close()` |

**Block 3** — [UNCONDITIONAL] — Build and Execute Query 2 (L7490)

> Always executed regardless of delKeyInfo content. Counts ALL distinct parent records linked to cntKey (without the delete-candidate filter).

| # | Type | Code |
|---|------|------|
| 1 | EXEC | `sqlBuff2.append("SELECT COUNT(DISTINCT " + searchKey + ") ... UNION ALL ...")` // Build Query 2: Counts ALL parent records linked to cntKey |
| 2 | SET | Query includes filter: `strkey = cntKey` (NO delKeyInfo filter) |
| 3 | SET | Query includes filter: `searchKey IS NOT NULL` |
| 4 | SET | Query includes filter: `MK_FLG = '0'` |
| 5 | SET | UNION ALL subquery from `KK_T_SVKEI_GRP_SETE` with filters: `SVKEI_GRP_SKBT_NO = cntKey`, `SVKEI_GRP_SBT_CD = '01'`, `searchKey IS NOT NULL`, `MK_FLG = '0'` |
| 6 | CALL | `super.logPrint.printDebugLog("【削除対象スキーマに紐付く親スキーマの件数を検索】" + sqlBuff2.toString())` // Debug: log Query 2 SQL (Javadoc: "Search for the number of parent schemas linked to the delete-candidate schema") |
| 7 | CALL | `db_CNT_TABLE = new JBSbatSQLAccess(commonItem, TBL)` // Create DB access object |
| 8 | CALL | `pstatmt2 = db_CNT_TABLE.createStatement(sqlBuff2.toString())` // Prepare Statement |
| 9 | CALL | `rs2 = pstatmt2.executeQuery()` // Execute Query 2 |
| 10 | EXEC | `while (rs2.next()) { chkCount2 = rs2.getInt(1); }` // Read count from result |
| 11 | EXEC | `rs2.close()` // Close ResultSet |
| 12 | CALL | `super.logPrint.printDebugLog("TBL2:" + TBL + ":検索KEY2:" + strkey + ":検索件数2:" + chkCount2)` // Debug: log Query 2 result |
| 13 | EXEC | `pstatmt2.close()` // Close PreparedStatement |
| 14 | IF | `(db_CNT_TABLE != null)` (L7557) — Close DB access after Query 2 |
| 15 | EXEC | `db_CNT_TABLE.close()` |

**Block 4** — [IF] `(chkCount1 == chkCount2)` (L7561)

> Compare the two counts. The Javadoc states: "削除対象スキーマに紐付くレコードが親スキーマに存在しない場合" (When records linked to the delete-candidate schema do not exist in the parent schema — meaning all parent records are tied only to delete candidates).

| # | Type | Code |
|---|------|------|
| 1 | SET | `result = true` // All parent records are exclusively tied to delete-candidate keys — deletion is safe |

**Block 5** — [ELSE] — Implicit `chkCount1 != chkCount2` (L7561)

> Counts differ: some parent records are linked to keys NOT in the delete-candidate list.

| # | Type | Code |
|---|------|------|
| 1 | (implicit) | `result` remains `false` (initialized at L7411) — deletion is NOT safe |

**Block 6** — [RETURN] (L7565)

| # | Type | Code |
|---|------|------|
| 1 | RETURN | `return result;` // true = deletable, false = not deletable |

## 7. Glossary

| Term | Type | Business Meaning |
|------|------|------------------|
| `svc_kei_kaisen_ucwk_no` | Field | Service contract line detail work number — internal tracking ID for service contract line items. Also referenced as `svc_kei_ucwk_no` in related code. |
| `svc_kei_no` | Field | Service contract line number — the parent key that groups multiple line detail records. |
| `KK_T_KAISEN_TG_SVKEI` | Table | Service contract line detail table — the main parent table containing line detail records. This is the typical value for the `TBL` parameter. |
| `KK_T_SVKEI_GRP_SETE` | Table | Service contract group settings table — master table defining groups of service contract lines. Used to check if a parent record belongs to a group (`SVKEI_GRP_SBT_CD = '01'` = single usage location). |
| `SVKEI_GRP_SBT_CD` | Field | Service contract group sub-type code — classification code for service contract groups. `'01'` indicates a single usage location (同一利用場所). |
| `SVKEI_GRP_SKBT_NO` | Field | Service contract group sub-table number — the group identifier linking group settings to a specific parent key. |
| `MK_FLG` | Field | Maintenance flag — soft-delete indicator. `'0'` means active/valid records; `'1'` or other values indicate records excluded from processing. |
| `cntKey` | Parameter | Key value — the specific value of the strkey column to search for (e.g., a service contract line number). |
| `strkey` | Parameter | String key column — the column in the parent table that references the parent key (e.g., svc_kei_no). Used as the equality filter in WHERE clauses. |
| `searchKey` | Parameter | Search key column — the column whose distinct values are counted (e.g., svc_kei_ucwk_no). This is the parent schema identifier. |
| `delKeyInfo` | Parameter | Delete candidate key list — the set of parent schema values marked for deletion. Used to verify deletion safety. |
| `TBL` | Parameter | Parent table/schema name — the database table to query for parent records. Dynamically set per call. |
| `chkCount1` | Field | Count of parent records linked to delete-candidate keys only (Query 1 result). |
| `chkCount2` | Field | Count of ALL parent records linked to the key (Query 2 result). |
| `JBSbatSQLAccess` | Class | Service batch SQL access helper — provides database connectivity and statement preparation for batch service operations. |
| `delPsbChkSvcKeiKaisenUcwkNo` | Method | Deletion possible check for service contract line detail work number — the caller method that uses this method to determine which keys are safe to delete. |
| `delPsbChk` | Method | Deletion possible check (previous version) — replaced by `delPsbChkSvcKeiKaisenUcwkNo` in ANK-2480-00-00 update. |
| ANK-2480-00-00 | Change ticket | Development ticket that added this method as an enhanced version of the original deletion check. |
