2010-06-01 2 views
1

아래의 코드는 SQL 문이 때 레코드가 삭제되는 것을 보여줍니다장점 데이터베이스에 사용되는 같은 문으로 기록을 삭제하려고 예외가 발생 where 절

select * from test where qty between 50 and 59 

하지만 SQL 문 :

Advantage.Data.Provider.AdsException: Error 5072: Action requires read-write access to the table 

당신이 안정적으로 승 기록을 삭제할 수 있습니다 방법 :

select * from test where partno like 'PART/005%' 

는 예외를 throw i where 절을 적용 했습니까?
참고 : 나는 이점 데이터베이스 v9.10.1.9을 사용하고, VS2008, 닷넷 프레임 워크 3.5 WINXP (32) 대신 라이브 커서의 정적 커서 결과 LIKE 비트

using System.IO; 
using Advantage.Data.Provider; 
using AdvantageClientEngine; 
using NUnit.Framework; 

namespace NetworkEidetics.Core.Tests.Dbf 
{ 
    [TestFixture] 
    public class AdvantageDatabaseTests 
    { 
    private const string DefaultConnectionString = @"data source={0};ServerType=local;TableType=ADS_CDX;LockMode=COMPATIBLE;TrimTrailingSpaces=TRUE;ShowDeleted=FALSE"; 
    private const string TestFilesDirectory = "./TestFiles"; 

    [SetUp] 
    public void Setup() 
    { 
     const string createSql = @"CREATE TABLE [{0}] (ITEM_NO char(4), PARTNO char(20), QTY numeric(6,0), QUOTE numeric(12,4)) "; 
     const string insertSql = @"INSERT INTO [{0}] (ITEM_NO, PARTNO, QTY, QUOTE) VALUES('{1}', '{2}', {3}, {4})"; 
     const string filename = "test.dbf"; 

     var connectionString = string.Format(DefaultConnectionString, TestFilesDirectory); 

     using (var connection = new AdsConnection(connectionString)) { 
     connection.Open(); 

     using (var transaction = connection.BeginTransaction()) { 
      using (var command = connection.CreateCommand()) { 
      command.CommandText = string.Format(createSql, filename); 
      command.Transaction = transaction; 
      command.ExecuteNonQuery(); 
      } 

      transaction.Commit(); 
     } 

     using (var transaction = connection.BeginTransaction()) { 
      for (var i = 0; i < 1000; ++i) { 
      using (var command = connection.CreateCommand()) { 
       var itemNo = string.Format("{0}", i); 
       var partNumber = string.Format("PART/{0:d4}", i); 
       var quantity = i; 
       var quote = i * 10; 

       command.CommandText = string.Format(insertSql, filename, itemNo, partNumber, quantity, quote); 
       command.Transaction = transaction; 
       command.ExecuteNonQuery(); 
      } 
      } 
      transaction.Commit(); 
     } 

     connection.Close(); 
     } 
    } 

    [TearDown] 
    public void TearDown() 
    { 
     File.Delete("./TestFiles/test.dbf"); 
    } 

    [Test] 
    public void CanDeleteRecord() 
    { 
     const string sqlStatement = @"select * from test"; 

     Assert.AreEqual(1000, GetRecordCount(sqlStatement)); 
     DeleteRecord(sqlStatement, 3); 
     Assert.AreEqual(999, GetRecordCount(sqlStatement)); 
    } 

    [Test] 
    public void CanDeleteRecordBetween() 
    { 
     const string sqlStatement = @"select * from test where qty between 50 and 59"; 

     Assert.AreEqual(10, GetRecordCount(sqlStatement)); 
     DeleteRecord(sqlStatement, 3); 
     Assert.AreEqual(9, GetRecordCount(sqlStatement)); 
    } 

    [Test] 
    public void CanDeleteRecordWithLike() 
    { 
     const string sqlStatement = @"select * from test where partno like 'PART/005%'"; 

     Assert.AreEqual(10, GetRecordCount(sqlStatement)); 
     DeleteRecord(sqlStatement, 3); 
     Assert.AreEqual(9, GetRecordCount(sqlStatement)); 
    } 

    public int GetRecordCount(string sqlStatement) 
    { 
     var connectionString = string.Format(DefaultConnectionString, TestFilesDirectory); 
     using (var connection = new AdsConnection(connectionString)) { 
     connection.Open(); 

     using (var command = connection.CreateCommand()) { 
      command.CommandText = sqlStatement; 
      var reader = command.ExecuteExtendedReader(); 
      return reader.GetRecordCount(AdsExtendedReader.FilterOption.RespectFilters); 
     } 
     } 
    } 

    public void DeleteRecord(string sqlStatement, int rowIndex) 
    { 
     var connectionString = string.Format(DefaultConnectionString, TestFilesDirectory); 
     using (var connection = new AdsConnection(connectionString)) { 
     connection.Open(); 

     using (var command = connection.CreateCommand()) { 
      command.CommandText = sqlStatement; 

      var reader = command.ExecuteExtendedReader(); 

      reader.GotoBOF(); 
      reader.Read(); 

      if (rowIndex != 0) { 
      ACE.AdsSkip(reader.AdsActiveHandle, rowIndex); 
      } 
      reader.DeleteRecord(); 
     } 

     connection.Close(); 
     } 
    } 
    } 
} 

답변

4

의미는 읽기입니다 - 전용 데이터 집합. 이 상황에서 행을 제거하려면 SQL DELETE 문을 사용하는 것이 좋습니다.

DELETE FROM test where partno LIKE 'PART/005%' 

나는 귀하의 테스트가 단지 테스트라고 가정합니다. 그들은 행을 찾아 제거하는 데 상당히 비효율적 인 메커니즘을 사용하고 있습니다. 더 키 필드가 없다는 것을 코멘트 후

업데이트 : 대신 LIKE의 왼쪽 스칼라를 사용하는 방법에 대한 (모든 경우에 작동하지 않을 수도 있지만 예를 들어 않습니다) 어떻게

.

select * from test where left(partno,8) = 'PART/005' 

그런 다음 직접이 라이브 결과 집합에 확장 데이터 독자의 삭제 기능을 사용할 수 있습니다 크기가 항상 같은 경우 당신은 또한 왼쪽에 인덱스를 추가 할 수 있습니다 (PARTNO, 8) 성능을 증가 (gotop 및 건너 뛰기 없음).

Alex의 ROWID 주석 이후의 업데이트 정적 커서에서도 기본 테이블에서 ROWID를 얻지 못했습니다. Alex의 의견은 당신의 문제에 대한 해결책입니다. 첫째 :

SELECT t.*, t.rowid FROM test t WHERE x LIKE 'PART/005%' 

다음 :

DELETE FROM test WHERE rowid = :thisid 
+0

문제는 응용 프로그램에서 나는 기본 키 열이없는 중복 행을 포함 할 수있는 테이블이 사용하고, 그래서는 SQL을 사용할 수 없다는 것입니다 DELETE 문. 비슷한 필터로 라이브 커서를 가져 오는 방법이 있습니까? – ChrisR

+0

테이블에 고유 식별자 필드를 추가 할 수 있습니까? 그렇지 않다면이 문제는 다시 일어날 것입니다. 고유 ID를 추가하고이를 자동 입력 필드에 입력하거나 무언가를 생성 할 수 있다면 다른 이름으로 복사 한 후 같은 것을 사용하여 레코드를 삭제하십시오. testid에서 testid를 선택하십시오 (testcopy에서 testid를 선택하십시오. 여기서 partno는 ' PART/005 %;); –

+0

LIKE 대신 LEFT 스칼라를 사용하는 것은 어떨까요 (어떤 경우에도 작동하지 않을 수도 있지만 예를 들어 작동 할 수도 있음). 크기가 항상 동일하면 성능을 높이기 위해 왼쪽 (partno, 8)에 색인을 추가 할 수도 있습니다. select * from test 여기서 'left (partno, 8) ='PART/005 ' 다음과 같이 사용할 수 있습니다. 확장 된 데이터 판독기의 삭제 기능을이 실시간 결과 집합에 직접 표시합니다 (건너 뛰기 및 건너 뛰기 없음). –