2012-01-24 5 views
3

Я вставляю около 500 000 объектов в базу данных, где многие из них одинаковы (имеют одно и то же представление первичного ключа в базе данных), но другие поля могут быть разными, поэтому я использую подход «update» - если никакие строки не пострадали - вставьте ». Проблема в том, что иногда у объекта есть какое-то поле, установленное в null (нечитаемое из файла) и уже находится в базе данных с некоторым значением, поэтому я обновляю его до null = удаляет его.) Как реализовать сценарий, который вы бы обновили только по полям которые не являются нулевыми?Команда обновления Sql с дополнительными параметрами?

Вот простой пример того, как я делаю это сейчас:

private const string UpdateKun = "UPDATE pde.Kun SET [email protected] WHERE [email protected]"; 
private const string InsertKun = "INSERT INTO pde.Kun ([Licence], [Jmeno], [VykonnostniStupen]) VALUES (@Licence, @Jmeno, @VykonnostniStupen)"; 

var cmd = new SqlCommand(UpdateKun, conn, tran); 
cmd.Parameters.AddWithValue("@Licence", kun.Licence); 
cmd.Parameters.AddWithValue("@Jmeno", kun.Jmeno); 
RepairNulls(cmd.Parameters); 
if (cmd.ExecuteNonQuery() > 0) return; 

cmd = new SqlCommand(InsertKun, conn, tran); 
cmd.Parameters.AddWithValue("@Licence", kun.Licence); 
cmd.Parameters.AddWithValue("@Jmeno", kun.Jmeno); 
cmd.Parameters.AddWithValue("@VykonnostniStupen", 0); 
RepairNulls(cmd.Parameters); 
cmd.ExecuteNonQuery(); 


private void RepairNulls(SqlParameterCollection col) 
    { 
     foreach (SqlParameter param in col.Cast<SqlParameter>().Where(param => param.Value == null)) 
     { 
      param.Value = DBNull.Value; 
     } 
    } 
+0

Некоторые продукты SQL имеют функции, как вы описали с помощью одного оператора: 'INSERT ... Если DUPLICATE UPDATE ...' –

+0

@ypercube с момента его а 'SqlCommand' - его SQL Server. Тогда это будет MERGE до тех пор, пока он не достигнет 2005 года или выше –

+0

Да, я не совсем в sql, но я бы предположил, что он должен иметь такую ​​функциональность :) Я использую Sql server 2008, express edition, я буду искать синтаксис MERGE, спасибо – MSkuta

ответ

2

Изменение Обновление:

UPDATE pde.Kun 
SET [email protected] 
WHERE [email protected] 
    AND @Jmeno IS NOT NULL 

Если у вас есть более одного столбца для обновления:

UPDATE pde.Kun 
SET Jmeno = COALESCE(@Jmeno, Jmeno) 
    , ColumnB = COALESCE(@ColumnB, ColumnB) 
WHERE [email protected] 
+0

Хорошая идея , кажется, что решение даже подумало, что я немного боюсь производительности, потому что это был просто пример объекта, обычно объекты, которые я вставляю, имеют, как 20 полей, и все могут быть нулевыми в базе данных, кроме первичного ключа. – MSkuta

+0

Использование функций 'COALESCE()' не будет проблемой производительности, я думаю. Использование 500K-обновлений и 500K вложений для вставки строк 500K может быть. –

+0

В зависимости от вашей СУБД (SQL-Server? Какая версия?), У вас могут быть лучшие варианты вставки/обновления строк, поочередно. –

0

Не обновляйте базу данных только для проверки наличия строки

SELECT COUNT(*) FROM pde.Kun WHERE [email protected] 

и просто проверить, если возвращаемое значение больше 0, то

+0

Или используйте Если EXISTS –

+0

Ну в ситуации, когда вы хотите вставить строку, и если строка уже выходит, то обновите ее, при моем подходе вы сохраните один вызов sql (попробуйте обновить, если это не повлияет любая строка вставляет его, это максимум 2 вызова, обычно только 1, потому что в моем случае есть большое повторение, и обновление выполнено), если я буду использовать подсчет количества, чтобы найти, существует ли он, мне пришлось бы делать все 2 вызова, найти если он существует, то обновите или вставьте – MSkuta

+0

Но вы не обновляете строки с одинаковыми данными. Оператор select намного лучше, так как он использует индекс таблицы, чтобы узнать, существует ли эта строка. [Подобный вопрос здесь] (http://stackoverflow.com/questions/6696063/select-vs-update-performance-with-index) должен помочь – Kypros