从SQL Server表中删除重复的行

时间:2014-07-17 06:53:36

标签: sql sql-server

有人使用架构部署了一个SQL表

ConfigOptions
    name VARCHAR(50)
    value VARCHAR(50)

以及保存选项的以下逻辑:

int i = ExecuteNonQuery("UPDATE ConfigOptions SET value=@value WHERE name=@name");
if(i==0) i = ExecuteNonQuery("INSERT INTO ConfigOptions (name,value) (@name,@value)"); 

我们现在看到这个表格上堆满了重复项,我们想要改变它。

据我所知,逻辑是:只要UPDATE影响零行,就会插入另一行。如果我没有弄错的话,这可能是由以下原因引起的:

  • @name名称的行不存在或
  • 该行存在,但已包含值@value

因此,所有具有相同名称的行应该是完全重复的。如果现在,某些事情是完全错误的(并且行为可能未定义)。

现在我必须解决重复问题,所以我想在name上添加PK。在我这样做之前,我必须删除所有具有重复名称的行,只保留其中一行。

在安装程序中(只允许安装程序更改架构),我手边只有SQL查询,因此无法使用C#逻辑执行此操作:

Dictionary<string, int> dic = new Dictionary<string, int>();
SqlDataReader sdr = ExecuteReader("SELECT name,COUNT(value) FROM ConfigOptions GROUP BY name HAVING COUNT(value)>1");
while (sdr.Read()) dic.Add(sdr.GetString(0), sdr.GetInt32(1));
sdr.Close();
foreach (var kv in dic) {
    AddParameter("@name", System.Data.SqlDbType.VarChar, 50, kv.Key);
    ExecuteNonQuery("DELETE TOP " + (kv.Value - 1) + " FROM ConfigOptions WHERE name=@name");
}
ExecuteNonQuery("ALTER TABLE program_options ADD PRIMARY KEY (name)");

有没有办法把它放到SQL逻辑中?

1 个答案:

答案 0 :(得分:1)

使用%%physloc%%,该行的phys(ical)loc(ation)应该可以做到这一点:

DELETE FROM ConfigOptions 
WHERE %%physloc%% NOT IN (
    SELECT MIN(%%physloc%%) 
    FROM ConfigOptions 
    GROUP BY name);

完成此清理后,您可以将主键添加到表中。

注意:这将为每个name只留一行。如果value列在具有相同name的两个记录中不同,您将丢失最新记录。如果您想更改此设置,请使用GROUP BY name, value