T SQL Cte删除,其中group by大于1

时间:2019-06-26 10:20:54

标签: sql sql-server tsql common-table-expression

我正在使用SQL Server2016。我具有下表:

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存在多次,我想保留代码= 125的记录并删除代码为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不会删除任何内容-我缺少什么?

6 个答案:

答案 0 :(得分:1)

根据您提供的查询和示例数据,您需要注意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 DESC的{​​{1}}部分中添加Code DescRow_Number()

答案 1 :(得分:0)

排名函数将在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

答案 2 :(得分:0)

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

示例数据和查询

  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

答案 3 :(得分:0)

在移动Where语句的同时,我相信您还希望第二个CTE处理要标识的记录...在下面的操作中,第一个CTE标识重复的记录,而第二个CTE则将它们隔离,以便您可以执行根据这些SKU删除

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

选择*来自#tbl

结果(您的“所需结果”示例已删除未重复一周的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

答案 4 :(得分:-1)

您的CTE语句仅考虑代码= 100的行。如果删除它,则CTE将基于表中的所有行进行排名。使用此方法,首先找出具有多个行的组合。然后,在这些组合中,标识代码= 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

答案 5 :(得分:-1)

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

从#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