SQL Server 2008 R2:更新一次组的 NULL 值并删除其余的
SQL Server 2008 R2: update one occurrence of a group's NULL value and delete the rest
我有一个 table 订单,其中多行订单缺少 Type
,我正在努力使查询正确。我是 SQL 的新手,所以请多多包涵。
我在下面的图片中说明了一个例子。我需要帮助创建将 table 带到右边的查询,并 UPDATE 它看起来像右边的 table.
订单按组排序。每个组应该有一个类型OK的实例(IF NULL OR OK ALREADY EXISTS),并且no NULL 的实例。我想通过将其中一个组的 NULL 类型订单更新为 OK 类型并删除相应组的其余 NULL 行来实现这一点。
我已经设法在
之前获得了我想要保留的行
- 创建一个临时文件 table,我在其中插入订单并将 NULL 类型替换为 EMPTY
- 从临时 table 中,为已经有一个 OK 订单的组获取现有的 OK 订单,否则应将 EMPTY 订单更改为 OK。
我已经完成了以下操作:
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
其余的 EMPTY 订单应该在此步骤后删除,但我不知道如何从这里开始。也许这从一开始就是一个糟糕的方法,也许它可以做得更容易?
不能只删除 Type 为 null 的行吗?
DELETE FROM Orders WHERE Type IS NULL
做得好,写了一个问题,显示了一些努力并清楚地解释了你所追求的。不幸的是,这是一件罕见的事情!
我会这样做:
首先备份 table(我喜欢将它们放入不同的模式以保持整洁)
CREATE SCHEMA bak;
SELECT * INTO bak.Orders FROM dbo.Orders;
现在,如果您愿意,可以在面包 table 上进行试用 运行。
总之...
将所有 NULL 类型设置为 OK
UPDATE Orders SET Type = 'OK' WHERE Type IS NULL;
现在反复删除多余的记录。查找超过一条OK的记录并删除:
DELETE Orders WHERE ID In
(
SELECT MIN(Id) Id
FROM Orders
WHERE Type = 'OK';
GROUP BY idGroup
HAVING COUNT(*) > 1
);
您需要运行几次,直到它影响零条记录
假设没有多个OK并且每组至少有一个Ok或NULL
值,你可以这样做:
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;
实际上,即使您有多个 OK,这也会起作用,但它只会保留其中的行。
第一个子查询选择所有不是 OK
或 NULL
的行。第二个恰好选择其中一个组并将类型指定为 OK。
如果您想保留任何 OK 而不是 NULL,这将起作用。它创建了一个临时文件 table,其中包含我们需要处理的所有内容(OK 和 NULL),并从每组的 1 开始对它们进行编号,并进行排序,以便您在空记录之前列出 OK 记录。然后它确保所有第一条记录都正常,并删除所有其余的
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;
我有一个 table 订单,其中多行订单缺少 Type
,我正在努力使查询正确。我是 SQL 的新手,所以请多多包涵。
我在下面的图片中说明了一个例子。我需要帮助创建将 table 带到右边的查询,并 UPDATE 它看起来像右边的 table.
订单按组排序。每个组应该有一个类型OK的实例(IF NULL OR OK ALREADY EXISTS),并且no NULL 的实例。我想通过将其中一个组的 NULL 类型订单更新为 OK 类型并删除相应组的其余 NULL 行来实现这一点。
我已经设法在
之前获得了我想要保留的行- 创建一个临时文件 table,我在其中插入订单并将 NULL 类型替换为 EMPTY
- 从临时 table 中,为已经有一个 OK 订单的组获取现有的 OK 订单,否则应将 EMPTY 订单更改为 OK。
我已经完成了以下操作:
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
其余的 EMPTY 订单应该在此步骤后删除,但我不知道如何从这里开始。也许这从一开始就是一个糟糕的方法,也许它可以做得更容易?
不能只删除 Type 为 null 的行吗?
DELETE FROM Orders WHERE Type IS NULL
做得好,写了一个问题,显示了一些努力并清楚地解释了你所追求的。不幸的是,这是一件罕见的事情!
我会这样做:
首先备份 table(我喜欢将它们放入不同的模式以保持整洁)
CREATE SCHEMA bak;
SELECT * INTO bak.Orders FROM dbo.Orders;
现在,如果您愿意,可以在面包 table 上进行试用 运行。
总之...
将所有 NULL 类型设置为 OK
UPDATE Orders SET Type = 'OK' WHERE Type IS NULL;
现在反复删除多余的记录。查找超过一条OK的记录并删除:
DELETE Orders WHERE ID In
(
SELECT MIN(Id) Id
FROM Orders
WHERE Type = 'OK';
GROUP BY idGroup
HAVING COUNT(*) > 1
);
您需要运行几次,直到它影响零条记录
假设没有多个OK并且每组至少有一个Ok或NULL
值,你可以这样做:
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;
实际上,即使您有多个 OK,这也会起作用,但它只会保留其中的行。
第一个子查询选择所有不是 OK
或 NULL
的行。第二个恰好选择其中一个组并将类型指定为 OK。
如果您想保留任何 OK 而不是 NULL,这将起作用。它创建了一个临时文件 table,其中包含我们需要处理的所有内容(OK 和 NULL),并从每组的 1 开始对它们进行编号,并进行排序,以便您在空记录之前列出 OK 记录。然后它确保所有第一条记录都正常,并删除所有其余的
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;