You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何去除SQL中string_agg()函数返回的重复值?

解决STRING_AGG返回重复日期值的问题

原存储过程代码

declare @unit  int
declare  @department int
declare @section int
declare @block int
declare @empId int
declare  @fromdate date
declare @todate date

if @unit = 0 set @unit = null
if @department = 0 set @department = null
if @section = 0 set @section = null
if @block = 0 set @block = null
if @empId = 0 set @empId = null
set @fromdate = '01/apr/2023'
set @todate = '20/apr/2023'

begin       
  SELECT       
      b2_department_info.department, b2_section_info.section,b2_block_info.block,b2_emp_basic.emp_cardno,b2_emp_basic.emp_name,      
      string_agg(day(b2_floor_production_list.prod_date),',') as ProdDate,b2_style_info.style,b2_process_info.process_name,
      sum(b2_floor_production_list.quantity) as Quantity,
      b2_company_info.company_name,b2_building_info.building_name, @fromdate as fromdate, @todate as todate
  FROM            
      b2_floor_production_list INNER JOIN
      b2_process_info ON b2_floor_production_list.process = b2_process_info.process_id INNER JOIN
      b2_style_info ON b2_process_info.style = b2_style_info.style_id INNER JOIN
      b2_emp_basic ON b2_floor_production_list.emp_id = b2_emp_basic.emp_id INNER JOIN
      b2_department_info ON b2_emp_basic.department = b2_department_info.deptId INNER JOIN
      b2_section_info ON b2_emp_basic.section = b2_section_info.section_id INNER JOIN
      b2_block_info ON b2_emp_basic.block = b2_block_info.blockId INNER JOIN
      b2_designation_info ON b2_emp_basic.designation = b2_designation_info.desigId INNER JOIN
      b2_building_info ON b2_emp_basic.unit = b2_building_info.building_id inner join
      b2_company_info on b2_building_info.company=b2_company_info.company_id                      
  where (b2_floor_production_list.prod_date >= CONVERT(date,@fromdate))
  and (b2_floor_production_list.prod_date <= CONVERT(date,@todate))
  and (b2_floor_production_list.emp_id = @empId or @empId is null)
  and (b2_building_info.building_id = @unit or @unit is null)
  and (b2_department_info.deptId = @department or @department is null)
  and (b2_floor_production_list.section = @section or @section is null)
  and (b2_block_info.blockId = @block or @block is null)
  group by b2_department_info.department, b2_section_info.section,b2_block_info.block,b2_emp_basic.emp_cardno,b2_emp_basic.emp_name,b2_style_info.style,b2_process_info.process_name,b2_company_info.company_name,b2_building_info.building_name
end

问题说明

执行上述存储过程时,ProdDate字段通过string_agg(day(b2_floor_production_list.prod_date),',')生成的日期存在重复值,尝试使用string_agg(distinct day(b2_floor_production_list.prod_date),',')去重但无效。

解决方案

方案1:先对生产记录按分组维度去重,再聚合

问题根源是b2_floor_production_list中存在同一员工、样式、工序、日期下的多条记录,直接聚合会导致日期重复。通过CTE先获取每个分组维度下的唯一日期和对应数量总和,再关联其他表查询:

declare @unit  int
declare  @department int
declare @section int
declare @block int
declare @empId int
declare  @fromdate date
declare @todate date

if @unit = 0 set @unit = null
if @department = 0 set @department = null
if @section = 0 set @section = null
if @block = 0 set @block = null
if @empId = 0 set @empId = null
set @fromdate = '01/apr/2023'
set @todate = '20/apr/2023'

begin       
  WITH ProductionSummary AS (
      SELECT 
          emp_id,
          process,
          section,
          prod_date,
          SUM(quantity) AS daily_quantity
      FROM b2_floor_production_list
      WHERE prod_date >= CONVERT(date,@fromdate)
        AND prod_date <= CONVERT(date,@todate)
        AND (emp_id = @empId OR @empId IS NULL)
        AND (section = @section OR @section IS NULL)
      GROUP BY emp_id, process, section, prod_date
  )
  SELECT       
      d.department, 
      s.section,
      bl.block,
      eb.emp_cardno,
      eb.emp_name,      
      STRING_AGG(day(ps.prod_date), ',') AS ProdDate,
      st.style,
      p.process_name,
      SUM(ps.daily_quantity) AS Quantity,
      c.company_name,
      b.building_name, 
      @fromdate AS fromdate, 
      @todate AS todate
  FROM ProductionSummary ps
  INNER JOIN b2_process_info p ON ps.process = p.process_id 
  INNER JOIN b2_style_info st ON p.style = st.style_id 
  INNER JOIN b2_emp_basic eb ON ps.emp_id = eb.emp_id 
  INNER JOIN b2_department_info d ON eb.department = d.deptId 
  INNER JOIN b2_section_info s ON eb.section = s.section_id 
  INNER JOIN b2_block_info bl ON eb.block = bl.blockId 
  INNER JOIN b2_designation_info dg ON eb.designation = dg.desigId 
  INNER JOIN b2_building_info b ON eb.unit = b.building_id 
  INNER JOIN b2_company_info c ON b.company = c.company_id                      
  WHERE (b.building_id = @unit OR @unit IS NULL)
    AND (d.deptId = @department OR @department IS NULL)
    AND (bl.blockId = @block OR @block IS NULL)
  GROUP BY d.department, s.section, bl.block, eb.emp_cardno, eb.emp_name, st.style, p.process_name, c.company_name, b.building_name
end

方案2:针对低版本SQL Server的去重处理

如果你的SQL Server版本低于2017(不支持STRING_AGG(DISTINCT...)),可以通过两个CTE分别处理唯一日期和数量总和,再关联查询:

declare @unit  int
declare  @department int
declare @section int
declare @block int
declare @empId int
declare  @fromdate date
declare @todate date

if @unit = 0 set @unit = null
if @department = 0 set @department = null
if @section = 0 set @section = null
if @block = 0 set @block = null
if @empId = 0 set @empId = null
set @fromdate = '01/apr/2023'
set @todate = '20/apr/2023'

begin       
  WITH UniqueProdDates AS (
      SELECT DISTINCT
          eb.emp_cardno,
          eb.emp_name,
          d.department,
          s.section,
          bl.block,
          st.style,
          p.process_name,
          c.company_name,
          b.building_name,
          day(fpl.prod_date) AS prod_day
      FROM b2_floor_production_list fpl
      INNER JOIN b2_process_info p ON fpl.process = p.process_id 
      INNER JOIN b2_style_info st ON p.style = st.style_id 
      INNER JOIN b2_emp_basic eb ON fpl.emp_id = eb.emp_id 
      INNER JOIN b2_department_info d ON eb.department = d.deptId 
      INNER JOIN b2_section_info s ON eb.section = s.section_id 
      INNER JOIN b2_block_info bl ON eb.block = bl.blockId 
      INNER JOIN b2_building_info b ON eb.unit = b.building_id 
      INNER JOIN b2_company_info c ON b.company = c.company_id                      
      WHERE fpl.prod_date >= CONVERT(date,@fromdate)
        AND fpl.prod_date <= CONVERT(date,@todate)
        AND (fpl.emp_id = @empId OR @empId IS NULL)
        AND (b.building_id = @unit OR @unit IS NULL)
        AND (d.deptId = @department OR @department IS NULL)
        AND (fpl.section = @section OR @section IS NULL)
        AND (bl.blockId = @block OR @block IS NULL)
  ),
  QuantitySummary AS (
      SELECT 
          eb.emp_cardno,
          eb.emp_name,
          d.department,
          s.section,
          bl.block,
          st.style,
          p.process_name,
          c.company_name,
          b.building_name,
          SUM(fpl.quantity) AS Quantity
      FROM b2_floor_production_list fpl
      INNER JOIN b2_process_info p ON fpl.process = p.process_id 
      INNER JOIN b2_style_info st ON p.style = st.style_id 
      INNER JOIN b2_emp_basic eb ON fpl.emp_id = eb.emp_id 
      INNER JOIN b2_department_info d ON eb.department = d.deptId 
      INNER JOIN b2_section_info s ON eb.section = s.section_id 
      INNER JOIN b2_block_info bl ON eb.block = bl.blockId 
      INNER JOIN b2_building_info b ON eb.unit = b.building_id 
      INNER JOIN b2_company_info c ON b.company = c.company_id                      
      WHERE fpl.prod_date >= CONVERT(date,@fromdate)
        AND fpl.prod_date <= CONVERT(date,@todate)
        AND (fpl.emp_id = @empId OR @empId IS NULL)
        AND (b.building_id = @unit OR @unit IS NULL)
        AND (d.deptId = @department OR @department IS NULL)
        AND (fpl.section = @section OR @section IS NULL)
        AND (bl.blockId = @block OR @block IS NULL)
      GROUP BY eb.emp_cardno, eb.emp_name, d.department, s.section, bl.block, st.style, p.process_name, c.company_name, b.building_name
  )
  SELECT 
      upd.department,
      upd.section,
      upd.block,
      upd.emp_cardno,
      upd.emp_name,
      STRING_AGG(upd.prod_day, ',') AS ProdDate,
      upd.style,
      upd.process_name,
      qs.Quantity,
      upd.company_name,
      upd.building_name,
      @fromdate AS fromdate,
      @todate AS todate
  FROM UniqueProdDates upd
  INNER JOIN QuantitySummary qs ON upd.emp_cardno = qs.emp_cardno 
                              AND upd.style = qs.style 
                              AND upd.process_name = qs.process_name
  GROUP BY upd.department, upd.section, upd.block, upd.emp_cardno, upd.emp_name, upd.style, upd.process_name, qs.Quantity, upd.company_name, upd.building_name
end

补充说明

若使用SQL Server 2017及以上版本,直接使用STRING_AGG(DISTINCT day(b2_floor_production_list.prod_date), ',')理论上有效;若仍无效,说明关联表导致了重复行,此时优先采用方案1,从主表数据层面去重,能彻底解决重复问题。

内容的提问来源于stack exchange,提问作者Nur Hossain Sujon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 13:07:00