2017-09-21 39 views
11

Tôi muốn chèn hoặc replace_on_condition. Nếu điều kiện không hài lòng, không chèn hoặc thay thế. Điều này có thể không?Làm thế nào để có điều kiện INSERT HOẶC THAY THẾ một hàng trong SQLite?

Đối với dự án của tôi, tôi hiện có hai quy trình thu thập dữ liệu. Một là nhanh nhưng không bắt tất cả mọi thứ. Người kia chậm nhưng bắt tất cả mọi thứ. Với quy trình nhanh chóng, tôi nhận được dữ liệu gần như trong thời gian thực. Với một chậm, tôi nhận được dữ liệu bằng cách sử dụng một quá trình hàng loạt vào cuối ngày.

Vấn đề của tôi là: đôi khi quá trình nhanh sẽ "Hoàn thành" bản ghi (có nghĩa là nó không còn cần được cập nhật) TRƯỚC KHI quá trình chậm và sau đó trong ngày trong quá trình xử lý hàng loạt, bản ghi "Hoàn thành" sẽ được thay thế bằng bản ghi "Đang chờ xử lý" đã lỗi thời được tìm thấy trong dữ liệu hàng loạt của quá trình chậm.

Những gì tôi muốn là một tấm séc có điều kiện mà đi một cái gì đó giống như giả này:

If(record_is_not_complete or does_not_exist) 
{ INSERT or REPLACE; } 
Else 
{ do_nothing and move_to_the_next; } 

Nếu tôi bắt đầu với một tiêu chuẩn INSERT OR REPLACE dụ:

INSERT OR REPLACE INTO UserProgress (id, status, level) 
    VALUES (1, 'COMPLETE', 5); 

nào nên kết quả trong một hàng trong UserProgress bảng có mục [1, COMPLETE, 5].

Nếu sau đây xảy ra:

INSERT OR REPLACE INTO UserProgress (id, status, level) 
    VALUES (1, 'PENDING', 4); 

Tôi muốn cho nó để bỏ qua điều này, vì đã có một kỷ lục COMPLETE.

Tôi chắc chắn đây là câu hỏi trùng lặp. Nhưng nó thực sự? Có rất nhiều câu trả lời cho câu hỏi này tôi không chắc đó là cách tiếp cận tốt nhất. Hãy xem tất cả các ví dụ mà tôi đã tìm thấy:

Tôi có thể cố gắng thêm tuyên bố CASE, tôi đã được thông báo là tương đương với tuyên bố IF-THEN-ELSE. As done in this example.

Tôi có thể cố gắng sử dụng câu lệnh SELECT hoặc COALESCE trong VALUES. As done in this example.

Tôi thậm chí có thể thử sử dụng câu lệnh SELECT WHERE. As done in this example.

Tôi có thể cố gắng sử dụng câu lệnh LEFT JOIN. As done in this example.

Điều này thật tuyệt vời cho SQLite. Có vẻ như có nhiều cách để cùng một con mèo. Tôi là một người mới tôi bây giờ bối rối. Tôi không nên sử dụng cách tiếp cận nào.

Tôi đang tìm một giải pháp có thể được thực hiện trong một câu lệnh sql.

* CẬP NHẬT *

Tôi tìm thấy một giải pháp hai giao dịch. Tôi vẫn đang tìm kiếm một giải pháp giao dịch duy nhất.

này hoạt động, nhưng sử dụng hai giao dịch:

public void Create(IEnumerable<UserProgress> items) 
     { 
      var sbFields = new StringBuilder(); 
      sbFields.Append("ID,"); 
      sbFields.Append("STATUS,"); 
      sbFields.Append("LEVEL,"); 

      int numAppended = 3; 

      var sbParams = new StringBuilder(); 
      for (int i = 1; i <= numAppended; i++) 
      { 
       sbParams.Append("@param"); 
       sbParams.Append(i); 

       if (i < numAppended) 
       { 
        sbParams.Append(", "); 
       } 
      } 

      // attempting this solution: https://stackoverflow.com/questions/2251699/sqlite-insert-or-replace-into-vs-update-where 

      // first insert the new stuff. 
      using (var command = new SQLiteCommand(Db)) 
      {    

       command.CommandText = "INSERT OR IGNORE INTO USERPROGRESS (" + sbFields + ") VALUES(" + sbParams + ")"; 

       command.CommandType = CommandType.Text; 

       using (var transaction = Db.BeginTransaction()) 
       { 
        foreach (var user in items) 
        { 
         command.Parameters.Add(new SQLiteParameter("@param1", user.Id)); 
         command.Parameters.Add(new SQLiteParameter("@param2", user.Status)); 
         command.Parameters.Add(new SQLiteParameter("@param3", user.Level)); 

         command.ExecuteNonQuery(); 
        } 

        transaction.Commit(); 
       } 
      } 

      using (var command = new SQLiteCommand(Db)) 
      { 
       string parameterized = ""; 

       for (int i = 1; i <= 3; i++) 
       { 
        parameterized += _columnNames[i - 1] + "=" + "@param" + i; 

        if (i != 3) 
         parameterized += ","; 
       } 

       command.CommandText = "UPDATE USERPROGRESS SET " + parameterized + " WHERE [email protected] AND STATUS !='COMPLETE'"; 

       command.CommandType = CommandType.Text; 

       using (var transaction = Db.BeginTransaction()) 
       { 
        foreach (var user in items) 
        { 
         command.Parameters.Add(new SQLiteParameter("@param1", user.Id)); 
         command.Parameters.Add(new SQLiteParameter("@param2", user.Status)); 
         command.Parameters.Add(new SQLiteParameter("@param3", user.Level)); 

         command.ExecuteNonQuery(); 
        } 

        transaction.Commit(); 
       } 
      } 
     } 
+1

Bạn có lẽ nên gọi 'command.Parameters.Clear(); 'trước đó cho-mỗi vòng lặp. – LarsTech

Trả lời

14

SQL

INSERT OR REPLACE INTO UserProgress (id, status, level) SELECTgiá trị id, 'giá trị tình trạng',giá trị mức WHERE NOT EXISTS (SELECT * FROM UserProgress WHERE id =giá trị idAND status = 'COMPLETE');

(nơi giá trị id, giá trị tình trạnggiá trị mức được chèn vào khi thích hợp)

Demo

http://www.sqlfiddle.com/#!5/a9b82d/1

Giải thích

Phần EXISTS được sử dụng để tìm hiểu xem có một hàng hiện có trong bảng với cùng id mà giá trị của tình trạng này là 'COMPLETE'. Nếu điều kiện này phù hợp, không có gì được thực hiện (do WHERE NOT). Nếu không, hàng có số id được chỉ định là INSERTed nếu không có hoặc UPDATEd với các giá trị được chỉ định nếu có (do INSERT OR REPLACE).

+0

Điều đó làm việc tuyệt vời cho thử nghiệm nhỏ của tôi với mười hàng hoặc hơn. Bạn có biết nếu tôi sẽ có bất kỳ vấn đề hiệu suất với một số lượng lớn các hàng? – sapbucket

+1

Tôi không thấy hiệu suất thực sự có thể được cải thiện như thế nào vì tất cả những gì đang được thực hiện trong mệnh đề WHERE là tìm kiếm hàng bằng khóa chính của nó, điều này là cần thiết để thực hiện việc chèn/cập nhật. (Không phải là một chuyên gia về SQLite nhưng sẽ mong đợi cơ sở dữ liệu để tối ưu hóa để tra cứu hàng chỉ được thực hiện một lần cho mỗi truy vấn). Bởi tất cả các phương tiện giữ tiền thưởng mở trong trường hợp các phương pháp khác có thể được gợi ý rằng bạn có thể so sánh với. –

2

Có ba hình thức báo cáo IF: IF-THEN, IF-THEN-ELSE và IF-THEN-ELSIF.

Cú pháp của việc sử dụng Nếu tuyên bố trong SQLite là:

IF expr THEN statement-list 
[ELSIF expr THEN statement-list ]* 
[ELSE statement-list] 
END IF 

Liên Kết: https://www.sqliteconcepts.org/pl_if.html

Các vấn đề liên quan