将所有唯一数据保存在SQL中的一列中

时间:2016-10-05 12:31:22

标签: sql oracle

我有一个查询来检查表中的重复项: -

(SELECT assignment_name 
 FROM   (SELECT xx.supervisor_stg.*, 
                Row_number() 
                  over ( 
                    PARTITION BY assignment_name 
                    ORDER BY assignment_name) AS c 
         FROM   xx.supervisor_stg) 
 WHERE  c > 1) 

我想从这些数据中删除重复数据,但是如果有一个值,例如assignment_name' Smith'写入三次,然后应保留1个值,另外2个应删除。

当我使用以下查询时,我收到错误:

Delete From supervisor_stg
where asg_name <>(SELECT Asg_Name 
 FROM   (SELECT xx.supervisor_stg.*, 
                Row_number() 
                  over ( 
                    PARTITION BY assignment_name 
                    ORDER BY assignment_name) AS c 
         FROM   xx.supervisor_stg) 
 WHERE  c > 1) 


SQL Error: ORA-01427: single-row subquery returns more than one row
01427. 00000 -  "single-row subquery returns more than one row"
*Cause:    
*Action:

3 个答案:

答案 0 :(得分:2)

在Oracle中,您可以从子查询中删除,例如delete from (select * from emp where empno < 10)。嗯,这个例子很愚蠢,但你明白了。在你的情况下,这将是:

delete from
(
  select *
  from
  (
    select 
      s.*, 
      row_number() over (partition by assignment_name order by assignment_name) as rn
    from xx.supervisor_stg s
  )
  where rn > 1
);

虽然这个应该工作,但由于某种原因,Oracle可能会发生这种情况除外。 更新:我在Oracle 11.2中尝试了这一点,Oracle给了我ORA-01752:“如果没有一个保存密钥的表,则无法从视图中删除”。因此,尽管我们只从一个表中进行选择,但Oracle却以某种方式感到困惑。继续阅读并选择另一种解决方案: - )

另一种方法是删除不存在具有相同assignment_name和较低(或更高)rowid的另一个条目的每个记录。

delete from xx.supervisor_stg s
where not exists
(
  select *
  from xx.supervisor_stg other
  where other.assignment_name = s.assignment_name
  and other.rowid < s.rowid
);

您可以使用与NOT EXISTS不相关的子查询,而不是使用NOT IN的相关子查询,其中您拥有集合中的所有最小(或最大)rowid,并删除所有其他。

delete from xx.supervisor_stg
where rowid not in
(
  select min(rowid)
  from xx.supervisor_stg
  group by assignment_name
);

关于你自己的删除声明:

  • 您的子查询与主查询无关,因此您可以获得许多记录。出于这个原因,您必须将<>替换为NOT IN
  • <>WHERE c > 1结合使用是没有意义的,因为后者会为您提供删除记录而不是保留的记录。制作此IN(而非NOT IN)或制作WHERE c = 1
  • 但是:你只是在比较asg_name。但asg_name对于要删除的记录和要保留的记录是相同的。你必须使用区分记录的东西。 rowid是完美的。

你会得到:

Delete From supervisor_stg
Where rowid In
(
  SELECT rowid 
  FROM 
  (
    SELECT 
      xx.supervisor_stg.*, 
      Row_number() over (PARTITION BY assignment_name ORDER BY assignment_name) AS c 
    FROM xx.supervisor_stg
  ) 
  WHERE c > 1
);

过于复杂。如图所示,您可以使用简单聚合(min(rowid) / group by assignment_name)。您可以使用row_number()之类的窗口函数来避免像在第一次查询中那样读取表格两次。在您的查询中,您仍在阅读该表两次,一次查找要保留的记录,然后再次查找要删除的记录。

答案 1 :(得分:0)

;WITH numbered AS (
    SELECT ROW_NUMBER() OVER(PARTITION BY [dupe-column-list] ORDER BY [dupe-column-list]) AS _dupe_num 
    FROM [table-name] 
    WHERE 1=1 -- any where clause if required
)
DELETE FROM numbered WHERE _dupe_num > 1;

此查询将根据您在此处添加的[dupe-column-list]字段为您的表分配行号。您可以为这些记录提供订单。 delete语句将删除所有[dupe-column-list]出现的记录(第一次出现除外)。

编辑:刚才注意到这是神谕。不确定上述内容是否适合您。以上是MSSQL。

答案 2 :(得分:0)

在Oracle中,您可以使用rowid来实现此目的:

delete from xx.SUPERVISOR_STG
    where rowid <> (select min(s2.rowid)
                    from xx.SUPERVISOR_STG
                    where s2.assignment_name = SUPERVISOR_STG.assignment_name
                   );