T SQL cte delete where group by 大于1

T SQL Cte delete where group by is greater than 1

我正在使用 SQL Server 2016。我有以下 table:

SKU     Mkt   Week   Cost   Code
ABC     05     1      10     100
ABC     05     2      12     100

DEF     05     3      20     100
DEF     05     3      25     125

XYZ     08     1      10     100
XYZ     08     2      12     100
XZY     08     2      14     125

这是期望的结果:

SKU     Mkt   Week   Cost   Code
ABC     05     1      10     100
ABC     05     2      12     100

DEF     05     3      25     125

XYZ     08     1      10     100
XZY     08     2      14     125

所以如果SKU\Mkt\Week\Cost存在不止一次,我想保留code = 125的记录并删除co​​de为100的行。

我正在使用以下 Cte:

  ;WITH CTE AS
(
    SELECT  *,
            RN = ROW_NUMBER() OVER( PARTITION BY SKU, Mkt, Week
                                    ORDER BY SKU, Mkt, Week)
    FROM [table]
    WHERE code = 100
)
DELETE FROM CTE
WHERE RN > 1

然而,Cte 并没有删除任何东西——我错过了什么?

根据您提供的查询和示例数据,您需要注意这部分cte内部查询:

WHERE code = 100

应用此过滤器后,您将获得以下数据:

SKU     Mkt   Week   Cost   Code
ABC     05     1      10     100
ABC     05     2      12     100

DEF     05     3      20     100

这将得到 1 作为 Row_Number() 的输出!,所以 运行 以下查询不会影响任何行:

DELETE FROM CTE
WHERE RN > 1

要获得所需的结果,您需要删除 CTE 内部查询中的 WHERE 部分。

;WITH CTE AS
(
    SELECT  *,
      RN = ROW_NUMBER() OVER( PARTITION BY SKU, Mkt, Week
             ORDER BY SKU, Mkt, Week, Cost DESC) --Code/Cost DESC <==== Note this too
    FROM [table]
    --WHERE code = 100  <========== HERE, I've commented it
)
DELETE FROM CTE
WHERE RN > 1

您还需要将 Cost DESCCode Desc 添加到 Row_Number()Order By 部分。

排名函数将在 select 语句中计算,这意味着 where 子句 WHERE code = 100 在 ROW_NUMBER() 之前计算,因此它已经删除了代码为 125 的行. 也使用按代码排序,然后在从 CTE

中删除时应用 code=100 检查
 ;WITH CTE AS
    (
        SELECT  *,
                RN = ROW_NUMBER() OVER( PARTITION BY SKU, Mkt, Week
                                        ORDER BY SKU, Mkt, Week,Code DESC)
        FROM tt1
    )

    DELETE FROM CTE
    WHERE RN > 1
AND CODE = 100

尝试以下查询以获得所需的结果 -

示例数据和查询

  Declare  @Table table
 (SKU varchar(20), Mkt int, [Week] int, Cost int, Code int)

  Insert into @Table
  values
  ( 'ABC',     05   ,  1,      10   ,  100),
  ( 'ABC' ,    05  ,   2 ,     12  ,   100),
  ('DEF'     ,05    , 3    ,  20    , 100),
  ('DEF'     ,05    , 3      ,25    , 125),
  ('XYZ'     , 08  ,   1      ,10  ,   100),
  ('XYZ'    ,  08  ,   2      ,12  ,   100),
  ('XYZ'     , 08,     2      ,14,     125)

;WITH CTE AS
(
    SELECT  *,
    RN = ROW_NUMBER() OVER( PARTITION BY SKU, Mkt, Week
                      ORDER BY SKU, Mkt, Week, code desc)
    FROM @Table
)
delete from Cte where RN > 1

您的 CTE 语句仅考虑代码 = 100 的行。如果删除它,则 CTE 将根据 table 中的所有行进行排名。使用它,首先找出具有多行的组合。然后在这些组合中,找出code=100的行,删除。

create table #e1
(
SKU varchar(50)
,Mkt varchar(50)
,_Week int
,Cost int
,_code int
)

insert into #e1(SKU, Mkt, _Week, Cost, _code)
select 'ABC',     '05',     1,      10,     100 UNION
SELECT 'ABC',     '05',     2,      12,     100 union
SELECT 'DEF',     '05',     3,      20,     100 UNION
SELECT 'DEF',     '05',     3,      25,     125 UNION
SELECT 'XYZ',     '08',     1,      10,     100 UNION
SELECT 'XYZ',     '08',     2,      12,     100 UNION
SELECT 'XZY',     '08',     2,      14,     125 


delete s
from
#e1 s
JOIN
(
    SELECT  SKU, Mkt, _Week 
    FROM #e1
    group by 
    SKU, Mkt, _Week 
    having count(1) > 1
) m
ON
s.SKU = m.sku and s.mkt = m.mkt and s._Week = m._Week
WHERE s._code = 100
Create table #tab1 (SKU varchar(50),Mkt varchar(50),[Week] varchar(50),Cost varchar(50),Code varchar(50))

insert into #tab1
select 'ABC','05','1','10','100'
union
select 'ABC','05','2','12','100'    
union
select 'DEF','05','3','20','100'   
union
select 'DEF','05','3','25','125'  
union
select 'XYZ','08','1','10','100'    
union
select 'XYZ','08','2','12','100'   
union
select 'XYZ','08','2','14','125'  



delete t from #tab1 t
inner join (select t1.SKU,t1.Mkt,t1.[Week],t1.Cost as Cost,t1.Code  as Code,ROW_NUMBER()over(partition by t1.SKU,t1.Mkt,t1.[Week] order by t1.Cost desc,t1.Code desc ) as rno
from #tab1 t1
) c on c.SKU = t.SKU and c.Mkt = t.Mkt and c.Cost = t.Cost and c.[Week] = t.[Week] and  c.Code = t.Code
 where c.rno = 2

select * 来自#tab1

输出:

SKU Mkt Week    Cost    Code
ABC 05  1         10    100
ABC 05  2         12    100
DEF 05  3         25    125
XYZ 08  1         10    100
XYZ 08  2         14    125

除了移动 Where 语句外,我相信您还希望第二个 cte 处理您正在识别的记录...在下面,您的第一个 cte 识别重复记录,而第二个 cte 隔离它们,以便您可以针对这些 SKU 执行删除

Table

Create Table #tbl
(
SKU VarChar(10),
Mkt VarChar(10),
Week Int,
Cost Int,
Code Int
)
Insert Into #tbl Values
('ABC','05',1,10,100),
('ABC','05',2,12,100),
('DEF','05',3,20,100),
('DEF','05',3,25,125),
('XYZ','08',1,10,100),
('XYZ','08',2,12,100),
('XYZ','08',2,14,125)

查询

  ;WITH CTE AS
(
    SELECT  *,
            RN = ROW_NUMBER() OVER( PARTITION BY SKU, Mkt, Week
                                    ORDER BY SKU, Mkt, Week)
    FROM #tbl
    --WHERE code = 100
)       
, cte1 As
(
     Select sku from cte where rn > 1
)
DELETE c FROM CTE c inner join cte1 c1 On c.SKU = c1.SKU
WHERE c.Code = 100

Select * 来自#tbl

结果(您的 'desired result' 示例删除了一周不重复的 XYZ 记录?)

SKU Mkt Week    Cost    Code
ABC 05  1       10      100
ABC 05  2       12      100
DEF 05  3       25      125
XYZ 08  1       10      100
XYZ 08  2       12      100
XZY 08  2       14      125