quyx@nextosd.com 4 ヶ月 前
コミット
7408813285

+ 111 - 0
yamada-common/src/main/java/jp/yamada/common/utils/poi/ExcelUtil.java

@@ -1978,4 +1978,115 @@ public class ExcelUtil<T> {
                 .collect(Collectors.joining(","));
     }
 
+    /**
+     * オブジェクトリストをCSVファイルとしてHTTPレスポンスに出力します(動的フィールドと列名に対応)。
+     * UTF-8 BOMを付与することで、Excel等のソフトウェアでの文字化けを防止します。
+     *
+     * @param response HTTPレスポンスオブジェクト
+     * @param list エクスポート対象のオブジェクトリスト
+     * @param fileName 出力ファイル名(拡張子不要)
+     * @param includeFields エクスポートするフィールド名のリスト(nullの場合は全ての@Excelフィールドを出力)
+     * @param renameMap フィールド名から表示名へのマッピング(nullの場合は@Excelのnameを使用)
+     * @param <T> オブジェクトの型
+     */
+    public static <T> void exportResultsCsv(
+            HttpServletResponse response,
+            List<T> list,
+            String fileName,
+            List<String> includeFields,
+            Map<String, String> renameMap
+    ) {
+        try (OutputStream out = response.getOutputStream()) {
+            // レスポンスヘッダー設定:バイナリファイルとしてダウンロードさせる
+            response.setContentType("application/octet-stream");
+            response.setHeader("Content-Disposition", "attachment; filename=" +
+                    URLEncoder.encode(fileName, "UTF-8") + ".csv");
+
+            // UTF-8 BOM(Byte Order Mark)を付与して文字化け防止
+            out.write(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF});
+
+            // UTF-8で文字を出力するライターを作成
+            OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
+
+            // ヘッダー行を出力(データがある場合のみ)
+            if (!list.isEmpty()) {
+                writer.write(createResultsCsvHeader(list.get(0), includeFields, renameMap) + "\n");
+            }
+
+            // データ行を順次出力
+            for (T obj : list) {
+                writer.write(createResultsCsvRow(obj, includeFields) + "\n");
+            }
+
+            // バッファ内容をフラッシュして出力を確定
+            writer.flush();
+        } catch (Exception e) {
+            // 例外発生時はカスタム例外をスロー
+            throw new ServiceException("CSVエクスポートに失敗しました", e);
+        }
+    }
+
+    /**
+     * CSVのヘッダー行を生成します(動的フィールドと列名に対応)。
+     * includeFieldsで指定されたフィールドのみを出力し、renameMapで列名を置換します。
+     */
+    private static <T> String createResultsCsvHeader(
+            T obj,
+            List<String> includeFields,
+            Map<String, String> renameMap
+    ) {
+        return Arrays.stream(obj.getClass().getDeclaredFields())
+                .filter(f -> {
+                    // 条件1:@Excelアノテーションが付与されている
+                    boolean hasExcelAnnotation = f.isAnnotationPresent(Excel.class);
+                    // 条件2:includeFieldsに含まれている(includeFieldsがnullの場合は全て許可)
+                    boolean isIncluded = includeFields == null || includeFields.contains(f.getName());
+                    return hasExcelAnnotation && isIncluded;
+                })
+                // @Excelのorder属性でソート(表示順を保持)
+                .sorted(Comparator.comparingInt(f -> f.getAnnotation(Excel.class).order()))
+                .map(f -> {
+                    String fieldName = f.getName();
+                    Excel excelAnno = f.getAnnotation(Excel.class);
+                    // renameMapに指定があればその名前を使用、なければ@Excelのnameを使用
+                    return renameMap != null && renameMap.containsKey(fieldName)
+                            ? renameMap.get(fieldName)
+                            : excelAnno.name();
+                })
+                .collect(Collectors.joining(","));
+    }
+
+    /**
+     * CSVのデータ行を生成します(動的フィールドに対応)。
+     * includeFieldsで指定されたフィールドのみを出力します。
+     */
+    private static <T> String createResultsCsvRow(T obj, List<String> includeFields) {
+        return Arrays.stream(obj.getClass().getDeclaredFields())
+                .filter(f -> {
+                    // ヘッダーと同じ条件でフィールドをフィルタリング
+                    boolean hasExcelAnnotation = f.isAnnotationPresent(Excel.class);
+                    boolean isIncluded = includeFields == null || includeFields.contains(f.getName());
+                    return hasExcelAnnotation && isIncluded;
+                })
+                // @Excelのorder属性でソート(ヘッダーと順序を一致させる)
+                .sorted(Comparator.comparingInt(f -> f.getAnnotation(Excel.class).order()))
+                .map(f -> {
+                    try {
+                        f.setAccessible(true); // privateフィールドの値を取得可能にする
+                        Object value = f.get(obj);
+
+                        if (value == null) {
+                            return ""; // nullの場合は空文字
+                        }
+                        if (value instanceof Date) {
+                            return DATE_FORMAT.format(value); // 日付型をフォーマット
+                        }
+                        return StringUtils.defaultIfEmpty(String.valueOf(value), "");
+                    } catch (Exception e) {
+                        return ""; // 値取得に失敗した場合は空文字
+                    }
+                })
+                .collect(Collectors.joining(","));
+    }
+
 }

+ 51 - 2
yamada-fcbi/src/main/java/jp/yamada/fcbi/controller/YmdfSurveyController.java

@@ -1,13 +1,12 @@
 package jp.yamada.fcbi.controller;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import jakarta.servlet.http.HttpServletResponse;
 import jp.yamada.common.utils.StringUtils;
-import jp.yamada.fcbi.domain.TBaseOrder;
-import jp.yamada.fcbi.mapper.YmdfFcApplicantMapper;
 import jp.yamada.fcbi.param.YmdfSurveyCustomerCsvParam;
 import jp.yamada.fcbi.param.YmdfSurveyCustomerDmParam;
 import jp.yamada.fcbi.param.YmdfSurveyParam;
@@ -126,6 +125,56 @@ public class YmdfSurveyController extends BaseController
     }
 
     /**
+     * 导出集計結果列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:survey:export')")
+    @Log(title = "集計結果列表", businessType = BusinessType.EXPORT)
+    @PostMapping("/exportResultsCsv")
+    public void exportResultsCsv(HttpServletResponse response, YmdfSurveySalesParam param) {
+        List<YmdfSurveySalesParam> list = ymdfSurveyService.selectYmdfResultsCsvList(param);
+        Integer salesFlag = param.getSalesFlag();
+
+        // エクスポートフィールド一覧
+        List<String> includeFields = new ArrayList<>();
+        Map<String, String> renameMap = new HashMap<>();
+
+        if (salesFlag == 1 || salesFlag == 2 || salesFlag == 3 || salesFlag == 4) {
+            // フィールドのエクスポート
+            includeFields.add("fcName");
+            includeFields.add("areaName");
+            includeFields.add("totalSales");
+            includeFields.add("storeCount");
+            includeFields.add("avgSales");
+            includeFields.add("prevRatio");
+            includeFields.add("salesShare");
+
+            if (salesFlag == 1 || salesFlag == 2) {
+                renameMap.put("prevRatio", "前月比");
+            } else {
+                renameMap.put("prevRatio", "前年度比");
+            }
+        }
+        else if (salesFlag == 5 || salesFlag == 6) {
+            // フィールドのエクスポート
+            includeFields.add("fcName");
+            includeFields.add("areaName");
+            includeFields.add("totalSales");
+            includeFields.add("storeName");
+            includeFields.add("avgTransation");
+            includeFields.add("prevRatio");
+            includeFields.add("salesShare");
+
+            if (salesFlag == 5) {
+                renameMap.put("prevRatio", "前月比");
+            } else {
+                renameMap.put("prevRatio", "前年度比");
+            }
+        }
+
+        ExcelUtil.exportResultsCsv(response, list, "集計結果列表数据", includeFields, renameMap);
+    }
+
+    /**
      * 导出店铺列表
      */
     @PreAuthorize("@ss.hasPermi('system:survey:export')")

+ 17 - 14
yamada-fcbi/src/main/java/jp/yamada/fcbi/param/YmdfSurveySalesParam.java

@@ -1,13 +1,10 @@
 package jp.yamada.fcbi.param;
 
 import jp.yamada.common.annotation.Excel;
-import jp.yamada.fcbi.domain.vo.QuestionInfoVo;
-import jp.yamada.fcbi.domain.vo.RegionInfoVo;
 import lombok.Data;
 
 import java.io.Serial;
 import java.io.Serializable;
-import java.util.Date;
 import java.util.List;
 
 /**
@@ -20,25 +17,40 @@ import java.util.List;
 public class YmdfSurveySalesParam implements Serializable {
     @Serial
     private static final long serialVersionUID = 1L;
-    /** FC名 */
+    /** FC */
+    @Excel(name = "FC")
     private String fcName;
 
-    /** 現エリア名 */
+    /** エリア */
+    @Excel(name = "エリア")
     private String areaName;
 
     /** 売上合計 */
+    @Excel(name = "売上合計")
     private String totalSales;
 
     /** 店舗数 */
+    @Excel(name = "店舗数")
     private String storeCount;
 
     /** 平均売上 */
+    @Excel(name = "平均売上")
     private String avgSales;
 
+    /** 店舗名 */
+    @Excel(name = "店舗名")
+    private String storeName;
+
+    /** 平均取引額 */
+    @Excel(name = "平均取引額")
+    private String avgTransation;
+
     /** 前月比 */
+    @Excel(name = "前月比")
     private String prevRatio;
 
     /** FC内売上シェア */
+    @Excel(name = "FC内売上シェア")
     private String salesShare;
 
     /** ブランドコード */
@@ -59,17 +71,8 @@ public class YmdfSurveySalesParam implements Serializable {
     /** 上位エリア名を */
     private String parentAreaName;
 
-    /** 店舗名 */
-    private String storeName;
-
-    /** 平均取引額 */
-    private String avgTransation;
-
     private List<String> brandCodes;
 
-    private List<String> businessTypeCodes;
-
-    private List<RegionInfoVo> regions;
     private List<String> regionCodes;
 
     private String monthYear;

+ 8 - 0
yamada-fcbi/src/main/java/jp/yamada/fcbi/service/IYmdfSurveyService.java

@@ -59,6 +59,14 @@ public interface IYmdfSurveyService
     public List<YmdfSurveyCustomerCsvParam> selectYmdfCustomerCsvList(YmdfSurveyCustomerCsvParam ymdfSurveyCustomerCsvParam);
 
     /**
+     * 集計結果列表結果の取得
+     *
+     * @param ymdfSurveySalesParam 集計結果列表結果の取得
+     * @return 集計結果列表結果の取得
+     */
+    public List<YmdfSurveySalesParam> selectYmdfResultsCsvList(YmdfSurveySalesParam ymdfSurveySalesParam);
+
+    /**
      * 地域名列表結果の取得
      *
      * @param ymdfSurveyCustomerDmParam 地域名列表結果の取得

+ 37 - 0
yamada-fcbi/src/main/java/jp/yamada/fcbi/service/impl/YmdfSurveyServiceImpl.java

@@ -178,6 +178,43 @@ public class YmdfSurveyServiceImpl implements IYmdfSurveyService
     }
 
     /**
+     * 集計結果列表結果の取得
+     *
+     * @param param 集計結果列表結果の取得
+     * @return 集計結果列表結果の取得
+     */
+    @Override
+    public List<YmdfSurveySalesParam> selectYmdfResultsCsvList(YmdfSurveySalesParam param) {
+        YmdfSurvey ymdfSurvey = new YmdfSurvey();
+        BeanUtils.copyProperties(param, ymdfSurvey);
+        List<YmdfSurvey> surveyList;
+        Integer salesFlag = param.getSalesFlag();
+        if (salesFlag == 1) {
+            surveyList = ymdfSurveyMapper.selectMonthlyFcSalesByParentRegion(ymdfSurvey);
+        } else if (salesFlag == 2) {
+            surveyList = ymdfSurveyMapper.selectMonthlyFcSalesByCurrentRegion(ymdfSurvey);
+        } else if (salesFlag == 3) {
+            surveyList = ymdfSurveyMapper.selectAnnualFcSalesByParentRegion(ymdfSurvey);
+        } else if (salesFlag == 4) {
+            surveyList = ymdfSurveyMapper.selectAnnualFcSalesByCurrentRegion(ymdfSurvey);
+        } else if (salesFlag == 5) {
+            surveyList = ymdfSurveyMapper.selectMonthlyStoreSalesByRegion(ymdfSurvey);
+        } else if (salesFlag == 6) {
+            surveyList = ymdfSurveyMapper.selectAnnualStoreSalesByRegion(ymdfSurvey);
+        } else {
+            surveyList = new ArrayList<>();
+        }
+
+        return surveyList.stream()
+                .map(survey -> {
+                    YmdfSurveySalesParam csvParam = new YmdfSurveySalesParam();
+                    BeanUtils.copyProperties(survey, csvParam);
+                    return csvParam;
+                })
+                .collect(Collectors.toList());
+    }
+
+    /**
      * 地域名列表結果の取得
      *
      * @param param 地域名列表結果の取得

+ 47 - 0
yamada-fcbi/src/main/resources/mapper/fcbi/YmdfBasicRegionMapper.xml

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="jp.yamada.fcbi.mapper.YmdfSurveyMapper">
+    
+    <resultMap type="YmdfSurvey" id="YmdfBasicRegionResult">
+        <result property="sortOrder"    column="sort_order"    />
+        <result property="regionCode"    column="region_code"    />
+        <result property="regionName"    column="region_name"    />
+    </resultMap>
+
+    <select id="selectRegionTree" resultType="map">
+        SELECT
+            JSON_OBJECT(
+                    'regions', JSON_ARRAYAGG(
+                    JSON_OBJECT(
+                            'regionId', parent.region_id,
+                            'regionName', parent.region_name,
+                            'level', parent.level,
+                            'sortOrder', parent.sort_order,
+                            'children', (
+                                SELECT JSON_ARRAYAGG(
+                                               JSON_OBJECT(
+                                                       'regionId', child.region_id,
+                                                       'regionName', child.region_name,
+                                                       'regionCode', child.region_code,
+                                                       'level', child.level,
+                                                       'sortOrder', child.sort_order,
+                                                       'parentRegion', parent.region_name
+                                               )
+                                       )
+                                FROM ymdf_basic_region child
+                                WHERE child.parent_id = parent.region_id
+                                ORDER BY child.sort_order
+                            )
+                    )
+                               )
+            ) AS regions_tree
+        FROM
+            ymdf_basic_region parent
+        WHERE
+            parent.level = 1
+        ORDER BY
+            parent.sort_order
+    </select>
+</mapper>

+ 157 - 0
yamada-fcbi/src/main/resources/mapper/fcbi/YmdfCustomerMapper.xml

@@ -0,0 +1,157 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="jp.yamada.fcbi.mapper.YmdfSurveyMapper">
+    
+    <resultMap type="YmdfSurvey" id="YmdfCustomerResult">
+        <result property="customerId" column="customer_id"/>
+        <result property="customerName" column="customer_name"/>
+        <result property="customerNameKana" column="customer_name_kana"/>
+        <result property="postalCode"    column="postal_code"    />
+        <result property="prefecture"    column="prefecture"    />
+        <result property="cityTown"    column="city_town"    />
+        <result property="address1"    column="address1"    />
+        <result property="mobilePhone" column="mobile_phone"/>
+        <result property="email" column="email"/>
+        <result property="totalValidSpending" column="total_valid_spending"/>
+        <result property="dmAllowedFlag" column="dm_allowed_flag"/>
+        <result property="emailAllowedFlag" column="email_allowed_flag"/>
+        <result property="lastPurchaseMonth" column="last_purchase_month"/>
+        <result property="fcBrandCode" column="fc_brand_code"/>
+        <result property="fcBrandName" column="fc_brand_name"/>
+        <result property="businessTypeCode" column="business_type_code"/>
+        <result property="businessTypeName"    column="business_type_name"    />
+        <result property="regionCode"    column="region_code"    />
+        <result property="regionName"    column="region_name"    />
+        <result property="parentRegionName"    column="parent_region_name"    />
+        <result property="storeName" column="store_name"/>
+    </resultMap>
+
+    <select id="selectYmdfCustomerCsvList" parameterType="YmdfSurvey" resultMap="YmdfCustomerResult">
+        SELECT
+            DISTINCT c.customer_id,
+                     c.customer_name,
+                     c.customer_name_kana,
+                     c.postal_code,
+                     c.prefecture AS prefecture,
+                     c.city_town AS city_town,
+                     c.address1 AS address1,
+                     c.mobile_phone,
+                     c.email,
+                     -- FCブランド情報(コード→名称)
+                     s.brand_code AS fc_brand_code,
+                     fc_dict.dict_label AS fc_brand_name,  -- FCブランド名称(辞書テーブルより)
+                     -- 業種情報(コード→名称)
+                     s.business_type_code AS business_type_code,
+                     bt_dict.dict_label AS business_type_name,  -- 業種名称(辞書テーブルより)
+                     -- 地域情報(親地域含む)
+                     s.region_code AS region_code,
+                     region.region_name AS region_name,  -- 地域名称
+                     parent_region.region_name AS parent_region_name,  -- 親地域名称(例:「関東」に「東京」が含まれる)
+                     s.store_name AS store_name
+        FROM
+            ymdf_customer c
+-- 顧客-店舗関連テーブル
+                LEFT JOIN ymdf_customer_store cs
+                          ON c.customer_id = cs.customer_id
+                              AND cs.del_flag = 0
+-- 店舗テーブル(FC、業種、地域コード含む)
+                LEFT JOIN ymdf_fc_store s
+                          ON cs.fc_store_id = s.fc_store_id
+                              AND s.del_flag = 0
+-- 1. FCブランド辞書テーブル(コード→名称)
+                LEFT JOIN sys_dict_data fc_dict
+                          ON s.brand_code = fc_dict.dict_value
+                              AND fc_dict.dict_type = 'yamada_fc_brand'
+-- 2. 業種辞書テーブル(コード→名称)
+                LEFT JOIN sys_dict_data bt_dict
+                          ON s.business_type_code = bt_dict.dict_value
+                              AND bt_dict.dict_type = 'yamada_business_type'
+-- 3. 地域テーブル(コード→名称)
+                LEFT JOIN ymdf_basic_region region
+                          ON s.region_code = region.region_code
+-- 4. 親地域テーブル(上位地域地域を取得)
+                LEFT JOIN ymdf_basic_region parent_region
+                          ON region.parent_id = parent_region.region_id
+        WHERE
+          -- 複数選択条件(ブランド、業種、地域は複数の値ををサポート)
+            s.brand_code IN ('010', '020')  -- 複数選択ブランドコード
+          AND s.business_type_code IN ('010', '020')  -- 複数選択業種コード
+          AND s.region_code IN ('KYUSHU_KAGOSHIMA', 'KINKI_KEIHAN', 'SHIKOKU') -- 複数選択地域コード
+          -- 店舗名のあいまい検索(例:「東京」を含む店舗)
+          AND s.store_name LIKE '%L%'  -- 店舗名に「東京」を含む
+          -- 基本フィルタ
+          AND c.del_flag = 0  -- 削除済み顧客を除外
+    </select>
+
+    <select id="selectYmdfCustomerDmList" parameterType="YmdfSurvey" resultMap="YmdfCustomerResult">
+        SELECT
+            DISTINCT
+            c.customer_id,
+            c.customer_name,
+            c.customer_name_kana,
+            c.postal_code,
+            c.prefecture AS prefecture,
+            c.city_town AS city_town,
+            c.address1 AS address1,
+            c.mobile_phone,
+            c.email,
+            -- DM配信許可状況
+            c.dm_allowed_flag,
+            c.email_allowed_flag,
+            -- 購入実績情報
+            c.last_purchase_month AS last_purchase_month,
+            c.total_valid_spending AS total_valid_spending,
+            -- 店舗・地域関連情報
+            s.store_name AS store_name,
+            fc_dict.dict_label AS fc_brand_name,
+            bt_dict.dict_label AS business_type_name,
+            region.region_name AS region_name
+        FROM
+            ymdf_customer c
+-- 顧客-店舗関連
+                LEFT JOIN ymdf_customer_store cs
+                          ON c.customer_id = cs.customer_id
+                              AND cs.del_flag = 0
+-- 店舗情報
+                LEFT JOIN ymdf_fc_store s
+                          ON cs.fc_store_id = s.fc_store_id
+                              AND s.del_flag = 0
+-- FCブランド辞書
+                LEFT JOIN sys_dict_data fc_dict
+                          ON s.brand_code = fc_dict.dict_value
+                              AND fc_dict.dict_type = 'yamada_fc_brand'
+-- 業種辞書
+                LEFT JOIN sys_dict_data bt_dict
+                          ON s.business_type_code = bt_dict.dict_value
+                              AND bt_dict.dict_type = 'yamada_business_type'
+-- 地域情報
+                LEFT JOIN ymdf_basic_region region
+                          ON s.region_code = region.region_code
+-- 親地域情報
+                LEFT JOIN ymdf_basic_region parent_region
+                          ON region.parent_id = parent_region.region_id
+        WHERE
+          -- 基本条件:顧客が削除されていない
+            c.del_flag = 0
+          -- DM配信許可
+          AND c.dm_allowed_flag = 1
+          -- 動的に6ヶ月前の年月を計算(例:2024年7月の場合、202401~202407を対象)
+          AND c.last_purchase_month >=
+              CAST(DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 6 MONTH), '%Y%m') AS UNSIGNED)
+--   -- 累計金額基準(例:10,000円以上)
+          AND c.total_valid_spending >= 500
+          -- ブランド複数選択
+          AND s.brand_code IN ('010', '020')
+          -- 業種複数選択
+          AND s.business_type_code IN ('010', '020')
+          -- 地域複数選択
+          AND s.region_code IN ('KYUSHU_KAGOSHIMA', 'KINKI_KEIHAN', 'SHIKOKU')
+          -- 店舗名あいまい検索
+          AND s.store_name LIKE '%L%'  -- 店舗名に「東京」を含む
+        ORDER BY
+            c.total_valid_spending DESC,
+            c.last_purchase_month DESC
+    </select>
+</mapper>

+ 4 - 152
yamada-fcbi/src/main/resources/mapper/fcbi/YmdfSurveyMapper.xml

@@ -195,10 +195,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                             '[',
                             GROUP_CONCAT(
                                     JSON_OBJECT(
-                                            'option_id', o.id,
-                                            'option_text', o.option_text,
-                                            'sort_order', o.sort_order,
-                                            'is_answered', FIND_IN_SET(o.sort_order, REPLACE(a.option_id, '/', ',')) > 0
+                                            'optionId', o.id,
+                                            'optionText', o.option_text,
+                                            'sortOrder', o.sort_order,
+                                            'isAnswered', FIND_IN_SET(o.sort_order, REPLACE(a.option_id, '/', ',')) > 0
                                     )
                                         ORDER BY o.sort_order ASC
                     SEPARATOR ','
@@ -249,133 +249,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             q.sort_order ASC  -- 質問のソート順に並び替え
     </select>
 
-    <select id="selectYmdfCustomerCsvList" parameterType="YmdfSurvey" resultMap="YmdfSurveyResult">
-        SELECT
-            DISTINCT c.customer_id,
-                     c.customer_name,
-                     c.customer_name_kana,
-                     c.postal_code,
-                     c.prefecture AS prefecture,
-                     c.city_town AS city_town,
-                     c.address1 AS address1,
-                     c.mobile_phone,
-                     c.email,
-                     -- FCブランド情報(コード→名称)
-                     s.brand_code AS fc_brand_code,
-                     fc_dict.dict_label AS fc_brand_name,  -- FCブランド名称(辞書テーブルより)
-                     -- 業種情報(コード→名称)
-                     s.business_type_code AS business_type_code,
-                     bt_dict.dict_label AS business_type_name,  -- 業種名称(辞書テーブルより)
-                     -- 地域情報(親地域含む)
-                     s.region_code AS region_code,
-                     region.region_name AS region_name,  -- 地域名称
-                     parent_region.region_name AS parent_region_name,  -- 親地域名称(例:「関東」に「東京」が含まれる)
-                     s.store_name AS store_name
-        FROM
-            ymdf_customer c
-                LEFT JOIN ymdf_customer_store cs
-                          ON c.customer_id = cs.customer_id
-                              AND cs.del_flag = 0
-                LEFT JOIN ymdf_fc_store s
-                          ON cs.fc_store_id = s.fc_store_id
-                              AND s.del_flag = 0
-                LEFT JOIN sys_dict_data fc_dict
-                          ON s.brand_code = fc_dict.dict_value
-                              AND fc_dict.dict_type = 'yamada_fc_brand'
-                LEFT JOIN sys_dict_data bt_dict
-                          ON s.business_type_code = bt_dict.dict_value
-                              AND bt_dict.dict_type = 'yamada_business_type'
-                LEFT JOIN ymdf_basic_region region
-                          ON s.region_code = region.region_code
-                LEFT JOIN ymdf_basic_region parent_region
-                          ON region.parent_id = parent_region.region_id
-        WHERE
-          -- 複数選択条件(ブランド、業種、地域は複数の値ををサポート)
-            s.brand_code IN ('010', '020')  -- 複数選択ブランドコード
-          AND s.business_type_code IN ('010', '020')  -- 複数選択業種コード
-          AND s.region_code IN ('KYUSHU_KAGOSHIMA', 'KINKI_KEIHAN', 'SHIKOKU') -- 複数選択地域コード
-          -- 店舗名のあいまい検索(例:「東京」を含む店舗)
-          AND s.store_name LIKE '%L%'  -- 店舗名に「東京」を含む
-          -- 基本フィルタ
-          AND c.del_flag = 0  -- 削除済み顧客を除外
-    </select>
-
-    <select id="selectYmdfCustomerDmList" parameterType="YmdfSurvey" resultMap="YmdfSurveyResult">
-        SELECT
-            DISTINCT
-            c.customer_id,
-            c.customer_name,
-            c.customer_name_kana,
-            c.postal_code,
-            c.prefecture AS prefecture,
-            c.city_town AS city_town,
-            c.address1 AS address1,
-            c.mobile_phone,
-            c.email,
-            -- DM配信許可状況
-            c.dm_allowed_flag,
-            c.email_allowed_flag,
-            -- 購入実績情報
-            c.last_purchase_month AS last_purchase_month,
-            c.total_valid_spending AS total_valid_spending,
-            -- 店舗・地域関連情報
-            s.store_name AS store_name,
-            fc_dict.dict_label AS fc_brand_name,
-            bt_dict.dict_label AS business_type_name,
-            region.region_name AS region_name
-        FROM
-            ymdf_customer c
-                LEFT JOIN ymdf_customer_store cs
-                          ON c.customer_id = cs.customer_id
-                              AND cs.del_flag = 0
-                LEFT JOIN ymdf_fc_store s
-                          ON cs.fc_store_id = s.fc_store_id
-                              AND s.del_flag = 0
-                LEFT JOIN sys_dict_data fc_dict
-                          ON s.brand_code = fc_dict.dict_value
-                              AND fc_dict.dict_type = 'yamada_fc_brand'
-                LEFT JOIN sys_dict_data bt_dict
-                          ON s.business_type_code = bt_dict.dict_value
-                              AND bt_dict.dict_type = 'yamada_business_type'
-                LEFT JOIN ymdf_basic_region region
-                          ON s.region_code = region.region_code
-                LEFT JOIN ymdf_basic_region parent_region
-                          ON region.parent_id = parent_region.region_id
-        WHERE
-          -- 基本条件:顧客が削除されていない
-            c.del_flag = 0
-          -- DM配信許可
-          AND c.dm_allowed_flag = 1
-          -- 動的に6ヶ月前の年月を計算(例:2024年7月の場合、202401~202407を対象)
-          AND c.last_purchase_month >=
-              CAST(DATE_FORMAT(DATE_SUB(CURRENT_DATE(), INTERVAL 6 MONTH), '%Y%m') AS UNSIGNED)
-          AND c.total_valid_spending >= 500
-          -- ブランド複数選択
-          AND s.brand_code IN ('010', '020')
-          -- 業種複数選択
-          AND s.business_type_code IN ('010', '020')
-          -- 地域複数選択
-          AND s.region_code IN ('KYUSHU_KAGOSHIMA', 'KINKI_KEIHAN', 'SHIKOKU')
-          -- 店舗名あいまい検索
-          AND s.store_name LIKE '%L%'  -- 店舗名に「東京」を含む
-        ORDER BY
-            c.total_valid_spending DESC,
-            c.last_purchase_month DESC
-    </select>
-
     <select id="selectMonthlyFcSalesByCurrentRegion" parameterType="YmdfSurvey" resultMap="YmdfSurveyResult">
         -- 月度FC別売上集計(上位エリアでグループ化、売上シェア計算を修正)
         WITH
@@ -975,40 +848,6 @@ store_sales AS (
             </if>
         </where>
     </select>
-    <select id="selectRegionTree" resultType="map">
-        SELECT
-            JSON_OBJECT(
-                    'regions', JSON_ARRAYAGG(
-                    JSON_OBJECT(
-                            'region_id', parent.region_id,
-                            'region_name', parent.region_name,
-                            'level', parent.level,
-                            'sort_order', parent.sort_order,
-                            'children', (
-                                SELECT JSON_ARRAYAGG(
-                                               JSON_OBJECT(
-                                                       'region_id', child.region_id,
-                                                       'region_name', child.region_name,
-                                                       'region_code', child.region_code,
-                                                       'level', child.level,
-                                                       'sort_order', child.sort_order,
-                                                       'parent_region', parent.region_name
-                                               )
-                                       )
-                                FROM ymdf_basic_region child
-                                WHERE child.parent_id = parent.region_id
-                                ORDER BY child.sort_order
-                            )
-                    )
-                               )
-            ) AS regions_tree
-        FROM
-            ymdf_basic_region parent
-        WHERE
-            parent.level = 1
-        ORDER BY
-            parent.sort_order
-    </select>
     
     <select id="selectYmdfSurveyById" parameterType="String" resultMap="YmdfSurveyResult">
         <include refid="selectYmdfSurveyVo"/>