T SQL Cte удалить, когда group by больше 1 - PullRequest
0 голосов
/ 26 июня 2019

Я использую SQL Server 2016. У меня есть таблица ниже:

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 \Стоимость существует более одного раза, я хочу сохранить запись, где код = 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 ]

1 голос
/ 26 июня 2019

Исходя из предоставленного вами запроса и данных примера, вы должны обратить внимание на этот раздел внутреннего запроса 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

Для достижения желаемого результата вам необходимо удалить WHEREраздел во внутреннем запросе CTE.

;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 или Code Desc в Row_Number() s Order By section.

0 голосов
/ 26 июня 2019

Наряду с перемещением вашего оператора 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
0 голосов
/ 26 июня 2019
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
0 голосов
/ 26 июня 2019

Ваш оператор 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
0 голосов
/ 26 июня 2019

Попробуйте запрос ниже, чтобы получить желаемый результат -

Пример данных и запрос

  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
0 голосов
/ 26 июня 2019

Функция ранжирования будет оценена в операторе выбора, что означает, что предложение where WHERE code = 100 вычисляется перед ROW_NUMBER (), и поэтому она уже удалила строки с кодом 125. Используйте также порядок по коду, а затем примените code=100 проверка при удалении из CTE

 ;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
...