我想编写一个查询,它从表中删除重复项,其中Access列的值为1 - 5,但总是取最高数字,但如果它是5那么那应该是最低的,因为它们是如何设计数据库的。但是5没有访问权限。(在我看来,5应该是0。)
所以有一个ID列和一个Access列,如果有多个ID,则删除具有最低Access值的ID。但请记住将5视为0或最低。
所以我想的是:
Delete from [table]
Where [ID] > 1
AND [Access] = (CASE [Access]
WHEN Access = 1 THEN ____ <----'Do nothing')
...
WHEN Access = 5 THEN ____ <----'Do Delete')
这就是我挣扎的地方。我如何检查ID,并查看哪个Access最高,如果存在则删除所有最低的Access。请记住,如果它是5然后4实际上更高,那么删除5。
太混乱了!
答案 0 :(得分:2)
如果要删除首先拥有访问权限5并且其余部分已订购的每个ID的行,请执行以下操作:
with todelete as (
select t.*, row_number() over (partition by id
order by (case when access = 5 then -1 else access end)
) as seqnum
from table t
)
delete from todelete
where seqnum = 1;
如果您只想在id
:
with todelete as (
select t.*, row_number() over (partition by id
order by (case when access = 5 then -1 else access end)
) as seqnum,
count(*) over (partition by id) as cnt
from table t
)
delete from todelete
where seqnum = 1 and cnt > 1;
编辑:
如果您想根据优先规则删除除一行以外的所有内容:
with todelete as (
select t.*, row_number() over (partition by id
order by (case when access = 5 then -1 else access end)
) as seqnum,
count(*) over (partition by id) as cnt
from table t
)
delete from todelete
where seqnum < cnt;
答案 1 :(得分:2)
如果将模5应用于Access列,您将获得以下转换:
1 % 5 = 1
2 % 5 = 2
3 % 5 = 3
4 % 5 = 4
5 % 5 = 0
正如您所看到的,5会产生最低的结果,其他则保持不变 - 似乎是您的案例的正确权限排名。考虑到这一点,我可能会尝试以下方法:
DELETE FROM u
FROM dbo.UserTable AS u
LEFT JOIN (
SELECT ID, MAX(Access % 5) AS Access
FROM dbo.UserTable
GROUP BY ID
) AS keep
ON u.ID = keep.ID
AND u.Access % 5 = keep.Access
WHERE i.ID IS NULL
;
子查询返回一组ID,其中包含要保留的Access值。主查询将目标表反连接到该集合以确定要删除的行。
此方法在某种程度上特定于您的特定情况:在扩展Access
的当前有效值集后,它可能无法正常工作。作为替代方案,您可以像其他人所建议的那样使用CASE,这肯定会更灵活。但是,我实际上建议您在AccessRank
表中添加Access
列,以指示哪个权限高于或低于其他权限。
这会使您的DELETE查询更复杂,但每次引入新的Access
值时都不需要对其进行调整(您只需要在数据中定义正确的排名 ):
DELETE FROM u
FROM dbo.UserTable AS u
INNER JOIN dbo.Access AS a
ON u.Access = a.ID
LEFT JOIN (
SELECT u.ID, MAX(a.AccessRank) AS AccessRank
FROM dbo.UserTable AS u
INNER JOIN dbo.Access AS a
ON u.Access = a.ID
) AS keep
ON u.ID = keep.ID
AND a.AccessRank = keep.AccessRank
;
暗示AccessRank
仅包含唯一排名。
答案 2 :(得分:1)
示例访问表:
|id|access|
-----------
|1 | 1 |
|1 | 2 |
|1 | 5 |
|2 | 1 |
|2 | 3 |
运行以下查询:
DELETE a
FROM acc a
INNER JOIN
(SELECT row= ROW_NUMBER() OVER(PARTITION BY ID ORDER BY (CASE WHEN ACCESS=5 THEN 0 ELSE ACCESS END) DESC), * FROM acc) b
ON a.id = b.id AND a.access = b.access
WHERE b.row > 1
结果是:
|id|access|
|1 | 2 |
|2 | 3 |
答案 3 :(得分:-1)
这应该是最快且最便携的解决方案,因为它允许在Access
上使用索引并使用标准SQL。
MS SQL Server 2008架构设置:
CREATE TABLE Table1
([ID] int, [Access] int)
;
INSERT INTO Table1
([ID], [Access])
VALUES
(1, 5),
(1, 1),
(1, 2),
(2, 5),
(2, 1),
(2, 2),
(3, 5)
;
查询1 :
delete t
from Table1 t
inner join (
select ID, max(Access) as MaxAccess
from Table1
where Access <> 5
group by ID
) pm on t.Access <> pm.MaxAccess
and t.ID = pm.ID
select * from Table1
<强> Results 强>:
| ID | ACCESS |
|----|--------|
| 1 | 2 |
| 2 | 2 |
| 3 | 5 |