2016-06-20 3 views
0

현재 C#에서 손상된 데이터베이스를 쿼리하려고합니다. 최근에 소개 된 오류는 특정 방식으로 데이터를 입력 할 때 열의 값이 기본값 0으로 설정되어 사용자가 수행하는 작업이나 dba가 수행하는 작업을 제어 할 수 없기 때문에 문제가되는 오류입니다.여러 행 쿼리에 대한 열 선택

이 문제를 해결하기 위해 사용자에게 출력해야하는 데이터에 대한 다른 경로를 발견했습니다. 문제는 열이 0이 아닌 숫자로 표시 될 때 이전 방법을 지원하는 감독자의 요구 사항이 있다는 것입니다.

케이스 또는 if 명령을 사용하여이 작업을 수행하려고하지만 SQL을 사용하면 좋지 않으므로 어디서 잘못되거나 제대로 처리 할 것인지 100 % 확신하지 못합니다.

SqlCommand caseCmd = new SqlCommand(
    "SELECT H.CREATED, H.STATUSCODE, H.DETAILS, H.YEAR, H.MONTH, H.DAY, H.ITEMTEXT, TC.DOCLE, TC.ICPC, TC.ICD10, TERMCODE =" + 
    " CASE H.ITEMCODE WHEN 0" + 
    " THEN TN.TERMID" + 
    " ELSE H.ITEMCODE END" + 
    " FROM " + _databaseName + ".dbo.PASTHISTORY H" + 
    " INNER JOIN " + _drugDatabaseName + ".dbo.TERMNAMES TN ON TN.TERMNAME = H.ITEMTEXT" + 
    " INNER JOIN " + _drugDatabaseName + ".dbo.TERMCODES TC ON TC.TERMID = TERMCODE" + 
    " INNER JOIN " + _drugDatabaseName + ".dbo.CONDITIONS C ON C.TERMID = TERMCODE" + 
    " WHERE H.INTERNALID = @patientid" + 
    " AND H.RECORDSTATUS = 1" + 
    " AND ((H.CREATED >= @mindate) OR ((H.UPDATED IS NOT NULL) AND (H.UPDATED >= @mindate)))" + 
    " AND TC.RECORDSTATUS = 1", 
    Connection); 
caseCmd.Parameters.AddWithValue("@patientid", int.Parse(patientId)); 
caseCmd.Parameters.AddWithValue("@mindate", minEnteredDate); 
// Current error: 
// When using 'TC.TERMID = TERMCODE', I get the error 'The conversion of the varchar value 
// "3951000119103 " overflowed an int column'. 
// This is alleviated by using either TN.TERMID OR H.ITEMCODE 

SqlCommand ifCmd = new SqlCommand(
    "IF (H.ITEMCODE = 0)" + 
    " SELECT H.CREATED, H.STATUSCODE, H.DETAILS, H.YEAR, H.MONTH, H.DAY, H.ITEMTEXT, TC.DOCLE, TC.ICPC, TC.ICD10, TN.TERMID" + 
    " FROM " + _databaseName + ".dbo.PASTHISTORY H" + 
     " INNER JOIN " + _drugDatabaseName + ".dbo.TERMNAMES TN ON TN.TERMNAME = H.ITEMTEXT" + 
     " INNER JOIN " + _drugDatabaseName + ".dbo.TERMCODES TC ON TC.TERMID = TN.TERMID" + 
     " INNER JOIN " + _drugDatabaseName + ".dbo.CONDITIONS C ON C.TERMID = TN.TERMID" + 
    " WHERE H.INTERNALID = @patientid" + 
     " AND H.RECORDSTATUS = 1" + 
     " AND ((H.CREATED >= @mindate) OR ((H.UPDATED IS NOT NULL) AND (H.UPDATED >= @mindate)))" + 
     " AND TC.RECORDSTATUS = 1" + 
    " ELSE IF (H.ITEMCODE <> 0)" + 
    " SELECT H.CREATED, H.STATUSCODE, H.DETAILS, H.YEAR, H.MONTH, H.DAY, H.ITEMTEXT, H.ITEMCODE, TC.DOCLE, TC.ICPC, TC.ICD10" + 
    " FROM " + _databaseName + ".dbo.PASTHISTORY H" + 
     " INNER JOIN " + _drugDatabaseName + ".dbo.TERMCODES TC ON TC.TERMID = H.ITEMCODE" + 
     " INNER JOIN " + _drugDatabaseName + ".dbo.CONDITIONS C ON C.TERMID = H.ITEMCODE" + 
    " WHERE H.INTERNALID = @patientid" + 
     " AND H.RECORDSTATUS = 1" + 
     " AND ((H.CREATED >= @mindate) OR ((H.UPDATED IS NOT NULL) AND (H.UPDATED >= @mindate)))" + 
     " AND TC.RECORDSTATUS = 1", 
    Connection); 
ifCmd.Parameters.AddWithValue("@patientid", int.Parse(patientId)); 
ifCmd.Parameters.AddWithValue("@mindate", minEnteredDate); 
// Current error: 
// Getting two lines both saying 'The multi-part identifier "H.ITEMCODE" could not be bound.' 
// I trust this is because of the IF and ELSE IF statements. 
// Starting to think IF isn't the answer for me. 

// Use either 
SqlDataReader rdr = caseCmd.ExecuteReader(); 
// or 
// SqlDataReader rdr = ifCmd.ExecuteReader(); 

이 심지어 원격으로 가능 아니면 그냥 둘 다 대안을 두 개의 SQL 명령을하고 그들 모두를 검색에 표시되어야합니다 다음은 현재 상태의 명령입니까?

+0

처음에는 C# 코드에서 SQL 문을 만드는 것을 중단하는 것이 좋습니다. 저장 프로 시저를 사용하는 경우 더 좋을 것입니다. –

+0

이 쿼리가 실행되는 SQL Server입니까? –

+0

어쨌든 (감사합니다) 질문에 답변 한 것처럼 보입니다. SQL Server에서 절대적으로 실행됩니다. – Crimthann

답변

0

는 명확하게하기 위해 전 C# 문자열에서 SQL을 가져다 CTE를 사용했다. 기본적으로, 먼저 데이터를 패치 한 후 조회를 위해 사용할 수 있습니다 :

WITH PatchedHistory AS (
    SELECT 
     H.CREATED, H.STATUSCODE, H.DETAILS, H.YEAR, H.MONTH, H.DAY, H.ITEMTEXT 
     , COALESCE(TN.TERMID, H.ITEMCODE) AS ITEMCODE --< TERMID with ITEMCODE fall-back 
    FROM _databaseName.dbo.PASTHISTORY H 
    LEFT JOIN _drugDatabaseName.dbo.TERMNAMES TN 
     ON H.ITEMCODE = 0        --< Lookup only if ITEMCODE is 0 
     AND TN.TERMNAME = H.ITEMTEXT 
    WHERE H.INTERNALID = @patientid     --< Apply most of the filtering here 
     AND H.RECORDSTATUS = 1 
     AND ((H.CREATED >= @mindate)     --< Suspicious condition 
     OR ((H.UPDATED IS NOT NULL) AND (H.UPDATED >= @mindate)) 
     ) 
) 
SELECT H.CREATED, H.STATUSCODE, H.DETAILS, H.YEAR, H.MONTH, H.DAY, H.ITEMTEXT, H.ITEMCODE 
    , TC.DOCLE, TC.ICPC, TC.ICD10      --< Add the rest of the data 
FROM PatchedHistory H 
    INNER JOIN _drugDatabaseName.dbo.TERMCODES TC 
     ON TC.TERMID = H.ITEMCODE      --< Join on the "patched" ITEMCODE 
    INNER JOIN _drugDatabaseName.dbo.CONDITIONS C 
     ON C.TERMID = H.ITEMCODE      --< Join on the "patched" ITEMCODE 
WHERE TC.RECORDSTATUS = 1 

는 또한이 상태가 의심스러운

:

 AND ((H.CREATED >= @mindate) 
     OR ((H.UPDATED IS NOT NULL) AND (H.UPDATED >= @mindate)) 
     ) 

하는 것은 기술적으로는

 AND ((H.CREATED >= @mindate) OR (H.UPDATED >= @mindate)) 

에 해당이 의도와 같이 보입니다.

 AND COALESCE(H.UPDATED, H.CREATED) >= @mindate 
+0

당신은 진짜 MVP입니다. 그 모든 것을 밖으로 시도하고 나는 내가 필요한 것을 정확히 얻고 있습니다. 업데이트 된 조건에 대한 조언을 구했습니다. 필자는 현재 프랑켄 슈타인 닝 (Frankenstein)이라는 오래된 쿼리를 사용하고 있기 때문에 두 번 훑어 보지도 않았다. 지금보기에 훨씬 좋네요. 또한, 내가 고맙다고 여기는 명확성 때문에 두 번째 쿼리에서 위의 긴 열차 대신 H. *로가는 것이 더 쉬울 것이라고 생각합니다. – Crimthann

+0

감사합니다. 예, 'H. *'는 정상적으로 작동합니다. '* '를 사용하는 대신에 모든 필드를 열거하면 뷰 또는 테이블 반환 함수'with schemabinding'으로 변환 할 때 쿼리를 좀더 읽기 쉽도록 만들 수 있습니다. 그러나이 특별한 경우에는 변경 사항을 최저한의. –