sql:如何删除重复的行(内容相同,但序列不同)

时间:2016-07-22 05:17:35

标签: sql sql-server tsql

你看到SKU1有两行,但实际上这两行的内容是相同的,只是“b”和“c”的顺序有所不同。

如果我想删除第二张图片中显示的重复行怎么办?

在Oracle中有一个LEAST / GREATEST函数可以实现它,但我使用的是SQL Server,因此它不能按照以下帖子的说明工作:

How to remove duplicate rows in SQL

enter image description here

7 个答案:

答案 0 :(得分:1)

如果使用下面的步骤并获得相同的结果,请使用Max()和Min函数而不是最小和最大的oracle。

Create Table Transactions (Name varchar(255),Quantity1 int,Quantity2 int)
   Insert Into Transactions values
   ('SKU1',10,20),
      ('SKU1',20,10),
   ('SKU2',10,20),
   ('SKU2',10,20)

现在我使用下面的查询来找到答案的解决方案

    Select T1.Name,MAX(T1.Quantity1),MIN(T2.Quantity2) From Transactions   T1
    join Transactions T2
    on T1.Name=T2.Name
    group by T1.Name

请回复

答案 1 :(得分:1)

如果它只有2列,那么订单对于该组来说无关紧要?

然后您可以使用IIF(或CASE WHEN)来计算最大值和最小值 并在GROUP BY中使用这些计算值。

例如:

select Name, 
MAX(Val1) as Val1,
MIN(Val2) as Val2
from Table1
GROUP BY Name,
IIF(Val2 is null or Val1 < Val2, Val1, Val2),
IIF(Val1 is null or Val1 < Val2, Val2, Val1);

对于将给出结果的示例记录:

Name Val1 Val2
SKU1 20   10
SKU2 20   10

或者如果你想使用花哨的XML技巧:

select Name, max(Val1) as Val1, min(Val2) as Val2
from (
  select *, 
  cast(
    convert(XML, 
      concat('<n>',Val1,'</n><n>',Val2,'</n>')
    ).query('for $n in /n order by $n return string($n)'
  ) as varchar(6)) as SortedValues
  from Table1
) q
group by Name, SortedValues;

当涉及更多列时,最后一种方法可能更有用。

实际删除重复项?
这是一个使用表变量来演示的示例:

declare @Table1 TABLE (Id int, Name varchar(20), Val1 int, Val2 int);

Insert Into @Table1 values
(1,'SKU1',10,20),
(2,'SKU1',20,10),
(3,'SKU1',12,15),
(4,'SKU2',10,null),
(5,'SKU2',null,10),
(6,'SKU2',10,20);

delete from @Table1
where Id in (
    select Id
    from (
    select Id, 
    row_number() over (partition by Name, 
         IIF(Val2 is null or Val1 < Val2, Val1, Val2),
         IIF(Val1 is null or Val1 < Val2, Val2, Val1)
       order by Val1 desc, Val2 desc
    ) as rn
    from @Table1
    ) q
    where rn > 1
);

select * from @Table1;

答案 2 :(得分:1)

可以使用CASE表达式

模拟

greatest()

最大(b,c)与:

相同
case 
   when b > c then b
   else c
end

您可以将它与不同的一起使用以删除重复项:

select distinct 
          a, 
          case when b > c then b else c end as x
from the_table
order by a;

答案 3 :(得分:1)

试试%%physloc%%。它相当于oracle的RowId

  1. 找到它

    select *, %%physloc%% from [MyTable] where ...

  2. 删除您想要的内容

    delete from [MyTable] where %%physloc%% = 0xDEADBEEF -- (your address)

  3. 考虑添加唯一/主键以防止将来发生。

答案 4 :(得分:1)

SELECT * FROM abc where A='SKU1'and B=20 || A='SKU2'and B=10 

 a      b    c  
SKU1    20  10
SKU2    10  20

答案 5 :(得分:1)

根据您的问题,您不清楚是按列还是重复过滤重复项。让我描述两者,以确保完全解决您的问题。

示例1 中,您可以看到我们有重复的行:

duplicate rows example

要过滤它们,只需在查询中添加关键字 DISTINCT ,如下所示:

SELECT DISTINCT * FROM myTable;

它过滤重复的行并返回:

duplicate rows filter

因此,在这种情况下,您不需要leastgreatest函数。

示例2 中,您可以看到我们在列中有重复项:

duplicate columns example

此处,SELECT DISTINCT * from abc仍将返回所有4行。 如果我们只考虑过滤中的第一列,则可以通过以下查询来实现:

select distinct t.Col1,
    (select top 1 Col2 from myTable ts where t.Col1=ts.Col1) Col2,
    (select top 1 Col3 from myTable ts where t.Col1=ts.Col1) Col3
from myTable t

它将在每列中选择第一个匹配值,因此查询结果将为:

duplicate columns filter

示例1与此示例之间的区别在于,它仅消除Col1 myTable中值的重复出现,然后返回其他列的相关值 - 因此结果为{ {1}}和Col1不同。

注意:

  • 在这种情况下,您不能只加入表Col2,因为那时您将被迫列出select distinct中的列,这将返回您想要的更多行。不幸的是,T-SQL不提供像myTable这样的东西,即你不能直接指定一个不同的(单个)字段名。
  • 你可能会想到“为什么不使用GROUP BY?”这个问题的答案是here:对于GROUP BY,您必须指定所有与技术DISTINCT等效的列,或者您需要使用MIN或MAX之类的聚合函数,这些函数不会返回您想要的

具有相同结果的更高级的查询(您可能曾经见过!)具有相同的结果:

SELECT DISTINCT ON(fieldname)

此语句对子查询中Col1上每个值的出现进行编号,然后获取每个重复行中的第一个 - 这实际上是Col1的分组(但没有SELECT Col1, Col2, Col3 FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY Col1 ORDER BY Col1) AS RowNumber FROM myTable ) t WHERE RowNumber=1 的缺点)。

N.B。在上面的示例中,我假设一个表定义如下:

GROUP BY

对于上面的示例,我们不需要声明主键列。但一般来说,您需要数据库表中的主键才能有效地引用行。

如果要永久删除不需要的行,则应引入主键,因为这样可以删除不易显示的行,如下所示(即它是上面提到的高级查询的逆过滤器):

CREATE TABLE [dbo].[myTable](
    [Col1] [nvarchar](max) NULL,
    [Col2] [int] NULL,
    [Col3] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

这假设您添加了一个自动递增的整数主键DELETE FROM [dbo].[myTable] WHERE myPK NOT IN (SELECT myPK FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY Col1 ORDER BY Col1) AS RowNumber FROM [dbo].[myTable] ) t WHERE RowNumber=1 and myPK=t.myPK) (您可以通过使用设计器轻松地通过SQL Management Studio执行此操作)。

或者您可以执行以下查询将其添加到现有表中:

myPK

您可以找到更多示例here at MSDN.

答案 6 :(得分:1)

起初看起来有点复杂,但我们也可以使用PIVOT / UNPIVOT来获得结果

以下是查询

select * 
from 
    (
    select 
        *, 
        'quantity'+ cast(row_number() over (partition by name order by data) as nvarchar) cols  
    from
        (
            select 
                distinct name, data 
            from 
                (select * from transactions)s
            unpivot
            (
                data for cols in (quantity1,quantity2)
            )u
        )s
    )s
pivot
(
    max(data) for cols in (quantity1,quantity2)
)p