简体   繁体   中英

SQL Server 2008 R2: update one occurrence of a group's NULL value and delete the rest

I have a table of orders which has multiple rows of orders missing a Type and I'm struggling to get the queries right. I'm pretty new to SQL so please bear with me.

I've illustrated an example in the picture below. I need help creating the query that will take the table to the right and UPDATE it to look like the right table.

在此输入图像描述

The orders are sorted by group. Each group should have one instance of type OK ( IF A NULL OR OK ALREADY EXISTS ), and no instances of NULL. I would like to achieve this by updating one of the groups' orders with type NULL to have type OK and delete the rest of the respective group's NULL rows.

I've managed to get the rows that I want to keep by

  1. Create a temporary table where I insert the orders and replace NULL types with EMPTY
  2. From the temporary table, get the existing OK orders for groups that already have one OK order, else an EMPTY order that should be changed to OK.

I've done this with the following:

SELECT * FROM Orders

SELECT * 
INTO #modified 
FROM 
    (SELECT 
         Id, IdGroup, 
         CASE WHEN Type IS NULL 
              THEN 'EMPTY'  
              ELSE Type   
         END Type 
     FROM 
         Orders) AS XXX

SELECT MIN(x.Id) Id, x.IdGroup, x.Type 
FROM #modified x
JOIN 
    (SELECT 
         IdGroup, MIN (Type) AS min_Type 
     FROM #modified a 
     WHERE Type = 'OK' OR Type = 'EMPTY'
     GROUP BY IdGroup) y ON y.IdGroup = x.IdGroup AND y.min_Type = x.Type
GROUP BY x.IdGroup, x.Type

DROP TABLE #modified

The rest of the EMPTY orders should after this step be deleted, but I don't know how to proceed from here. Maybe this is a poor approach from the beginning and maybe it could be done even easier?

Well done for writing a question that shows some effort and clearly explains what you're after. That's a rare thing unfortunately!

This is how I would do it:

First backup the table (I like to put them into a different schema to keep things neat)

CREATE SCHEMA bak;

SELECT * INTO bak.Orders FROM dbo.Orders;

Now you can do a trial run on the bak table if you like.

Anyway...

Set all the NULL types to OK

UPDATE Orders SET Type = 'OK' WHERE Type IS NULL;

Now repeatedly delete redundant records. Find records with more than one OK and delete them:

DELETE Orders WHERE ID In
(
SELECT MIN(Id) Id
FROM Orders
WHERE Type = 'OK';
GROUP BY idGroup
HAVING COUNT(*) > 1
);

You'll need to run that one a few times until it affects zero records

Assuming there are no multiple OKs and each group has at least one Ok or NULL value, you can do:

select t.id, t.idGroup, t.Type
from lefttable t
where t.Type is not null and t.Type <> 'OK'
union all
select t.id, t.idGroup, 'OK'
from (select t.*, row_number() over (partition by idGroup order by coalesce(t.Type, 'ZZZ')) as seqnum
      from lefttable t
      where t.Type is null or t.Type = 'OK'
     ) t
where seqnum = 1;

Actually, this will work even if you do have multiple OKs, but it will keep only of of the rows.

The first subquery selects all rows that are not OK or NULL . The second chooses exactly one of those group and assign the type as OK.

If you want to keep any OK ones in preference to a NULL, this will work. It creates a temp table with everything we need to work on (OK and NULL), and numbers them starting from one with each group, ordered so you list OK records before null ones. Then it makes sure all the first records are OK, and deletes all the rest

Create table #work (Id int, RowNo int)

--Get a list of all the rows we need to work on, and number them for each group
--(order by type desc puts OK before nulls)
Insert into #work (Id, RowNo)
Select Id, ROW_NUMBER() over (partition by IdGroup order by type desc) as RowNo
From Orders O
where (type is null OR type = 'OK');

-- Make sure the one we keep is OK, not null
Update O set type = 'OK'
from #Work W
inner join Orders O on O.Id = W.Id
Where W.RowNo = 1 and O.type IS NULL;

--Delete the remaining ones (any rowno > 1)
Delete O
from #Work W
inner join Orders O on O.Id = W.Id
Where W.RowNo > 1;

drop table #work;

你不能只删除Type等于null的行吗?

DELETE FROM Orders WHERE Type IS NULL

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM