2016-06-20 3 views
0

На данный момент я пытаюсь запросить сломанную базу данных в C#. Недавно введенная ошибка заключается в том, что когда данные вводятся определенным образом, значение в столбце по умолчанию равно 0, что для меня проблематично, так как я не могу контролировать, что делает пользователь или что делает dba.Выбор столбца для нескольких запросов строк

Чтобы обойти это, я нашел еще один путь к данным, которые мне нужны для вывода пользователю. Проблема в том, что у меня есть требование от моего супервизора поддержать старый метод в случае появления столбца в качестве ненулевого числа.

Я пытаюсь сделать это либо с помощью команды case, либо с помощью команды 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

As начало, я действительно рекомендую вам прекратить создание операторов SQL в коде C#, независимо от вашего случая, будет лучше, если вы используете хранимую процедуру. –

+0

Это SQL Server, на котором выполняется этот запрос? –

+0

Хотя кажется, что вы просто пошли и ответили на вопрос в любом случае (еще раз спасибо), он абсолютно запущен на SQL Server. – Crimthann

ответ

0

Для ясности я взял SQL из строки C# и использовал 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. Просто попробовал все, и я получаю именно то, что мне нужно. Принял ваш совет в обновленном состоянии. Должен признаться, что в настоящее время я просто Франкенштайнинг старого запроса, поэтому я даже не взглянул на него дважды. Намного приятнее смотреть сейчас. Кроме того, хотя я думаю, что это, возможно, было сделано ради моей ясности, за что я благодарю вас, во втором запросе было бы проще просто пойти с H. * вместо длинного поезда сверху? – Crimthann

+0

Спасибо. Да, 'H. *' будет работать нормально. Перечисление всех полей вместо использования '*' может сделать запрос более читабельным и окупаться при преобразовании в представление или табличную функцию 'with schemabinding', но в этом конкретном случае я просто пытался сохранить изменение в минимум. –