SQL Строка запроса работает в SQL Server Management Studio, но не в VB. net с SQLCommand.ExecuteReader - PullRequest
0 голосов
/ 22 февраля 2020

У меня есть страница ASPX с использованием кода VB. net, и он настроен на выполнение серии запросов SQL и заполнение SQLDataReader результатами. Каждый запрос SQL извлекается из указанного поля c в таблице в базе данных SQL. Этот код прекрасно работает буквально для каждого запроса, который я выполняю, кроме одного.

Код VB выглядит следующим образом.

Dim SQL_Template_Query As String
Dim cmd3 As SqlCommand = New SqlCommand
Dim r3 As SqlDataReader    

cmd3 = New SqlCommand(SQL_Template_Query)
cmd3.CommandTimeout = 1200 ' Extended to 1200 sec = 20 min
cmd3.CommandType = CommandType.Text
cmd3.Connection = Global_Objects.SQLLocalDB_Connection
Try
    r3 = Nothing
    r3 = cmd3.ExecuteReader() ' THIS LINE IS WHERE THE ERROR OCCURS
Catch
    Session("Main_Error_Code") = 1
    Session("Main_Error_Message") = "The SQL statement for the following address is invalid. Please examine the GCDB_Excel_Reports_Templates record, and correct." &
                    Chr(13) & "ID " & ti.ID & ", " & ti.Sheet_Name & ", " & ti.Cell_Address

    ' Write to error log
    cxlErrorsSheetLog.Cell("A" & cxlErrorsCurRow).Value = Session("Main_Error_Message")
    cxlErrors.SaveAs(cxlErrorsPath)
    cxlErrors = Nothing
    cxlDoc = Nothing
    Return
End Try

Как видите, у меня есть код для поймать ошибку, поэтому я точно знаю, где происходит ошибка, но я не уверен, почему. Ошибка возникает, когда

SQL_Template_Query = "DECLARE @Start_Year int; SET @ Start_Year = 2018; DECLARE @Reporting_Year int; SET @ Reporting_Year = 2021; объявить @First_Year int; установить @First_Year = (case (@ Reporting_Year-@Start_Year+1) <= 5 затем @Start_Year else @Reporting_Year - 4 конец); удалить таблицу, если существует #Reporting_Years; создать таблицу #Reporting_Years (Reporting_Year int); вставить в #Reporting_Years выбрать отдельный YEAR (Single_Date) из Single_Dates, где YEAR (Single_Date) между @ Reporting_Year-4 и @Reporting_Year; удалить таблицу, если существует #Has_ACT; создать таблицу #Has_ACT (Building_ID int, Start_Date datetime, End_Date datetime); вставить в #Has_ACT выбрать отдельный Building_ID, MIN (Start_Date), MAX (End_Date) ) из Tracking_Periods, где Utility_Type_ID между 16 и 19 и YEAR (Start_Date) <=@Reporting_Year и (YEAR (End_Date)> =@First_Year или End_Date is null) по Building_ID; выберите i1.Reporting_Year, SUM (случай, когда i2.Asset_Class подобен «Офис», затем GFA, иначе NULL конец) как Office_GFA, SUM (случай, когда i2 .Asset_Class, например «Retail», затем GFA else null end) как Retail_GFA, SUM (случай, когда i2.Asset_Class, например «Industrial», GFA else null end) как Industrial_GFA из #Reporting_Years i1, оставленное соединение (выберите z1.Reporting_Year, x.Building_ID, y.Building, y.Asset_Class, x.Start_Year, x.End_Year, y.Most_Recent_GFA_Year, случай, когда z1.Reporting_Year <= y.Most_Recent_GFA_Year затем (выберите GFA из Annual_GFA, где Building_ID = x.Building_ID и Reporting_YearingYID, и Reporting_Y (выберите GFA из Annual_GFA, где Building_ID = x.Building_ID и Reporting_Year = y.Most_Recent_GFA_Year) заканчиваются как GFA from (выберите Building_ID, случай, когда YEAR (Start_Date) <@ First_Year затем @First_Year else YEAR (Start_Date) заканчивается как Start_Year, case в качестве Start_Year, case имеет значение null, тогда @Reporting_Year, когда YEAR (End_Date)> @ Reporting_Year then @Reporting_Year else YEAR (End_Date) заканчивается как End_Year из #Has_ACT) x левое соединение (выберите a.Building_ID, a.Building, a.Asset_Class, MAX (a.Reporting_Year) ) как Most_Recent_GFA_Year от View_All_Buildings_Annual_GFA a внутреннее соединение View_All_Buildings b в a.Building_ID = b.Building_ID внутреннее соединение View_All_Building_Ownership_By_Year c в c .Building_ID = a.Building_ID и c. Reporting_Year=@Reporting_Year внутреннее объединение Building_Ovilding.D Override_Building_Count e для внутреннего соединения a.Building_ID = e.Building_ID и e.Report_ID = 5 #Has_ACT f для f.Building_ID = a.Building_ID, где b.Asset_Manager, например, «Anonymous» и b.Not_On_Program = 0 и b.Excing_From_ b.Tenant = 0 и d.Year_Removed имеет значение null и (e.Building_Count <> 0 или e.Building_Count is null) группируются по a.Building_ID, a.Building, a.Asset_Class) y на перекрестке x.Building_ID = y.Building_ID присоединитесь к #Reporting_Years z1, где z1.Reporting_Year между @First_Year и @Reporting_Year и z1.Reporting_Year> = x.Start_Year и z1.Reporting_Year <= x.End_Year и y.Building_ID не равен нулю) i2 на i1.Reporting_Year i1.Reporting_Year между группами @Start_Year и @Reporting_Year по i1.Reporting_Year, по i1.Reporting_Year; "</strong>

Я предоставляю строку как есть, на тот случай, если кто-то захочет узнать, как ее анализирует VB. net. Более удобный для разработчиков анализ этого запроса выглядит следующим образом.

DECLARE @Start_Year int;
SET @Start_Year=2018;
DECLARE @Reporting_Year int;
SET @Reporting_Year=2021;

declare @First_Year int;
set @First_Year =  
(  
case   
when (@Reporting_Year-@Start_Year+1)<=5 then @Start_Year   
else @Reporting_Year - 4 end  
);       

drop table if exists #Reporting_Years;       

create table #Reporting_Years  
(
Reporting_Year int
);   

insert into #Reporting_Years 
select distinct YEAR(Single_Date) 
from Single_Dates where YEAR(Single_Date) 
between @Reporting_Year-4 and @Reporting_Year;   

drop table if exists #Has_ACT;   

create table #Has_ACT (Building_ID int,Start_Date datetime,End_Date datetime);   

insert into #Has_ACT  
select distinct Building_ID,MIN(Start_Date),MAX(End_Date)  from Tracking_Periods  
where Utility_Type_ID between 16 and 19 
and YEAR(Start_Date)<=@Reporting_Year  
and (YEAR(End_Date)>=@First_Year or End_Date is null)  
group by Building_ID;     

select i1.Reporting_Year,  
SUM(case when i2.Asset_Class like 'Office' then GFA else null end) as Office_GFA,  
SUM(case when i2.Asset_Class like 'Retail' then GFA else null end) as Retail_GFA,  
SUM(case when i2.Asset_Class like 'Industrial' then GFA else null end) as Industrial_GFA  
from #Reporting_Years i1  
left join
(
select z1.Reporting_Year,x.Building_ID,y.Building,y.Asset_Class,x.Start_Year,x.End_Year,y.Most_Recent_GFA_Year,  
case  when z1.Reporting_Year<=y.Most_Recent_GFA_Year   
then 
(select GFA from Annual_GFA where Building_ID=x.Building_ID and Reporting_Year=z1.Reporting_Year)  
else 
(select GFA from Annual_GFA where Building_ID=x.Building_ID and Reporting_Year=y.Most_Recent_GFA_Year)
end as GFA  
from   
(  
select Building_ID,  
case  
when YEAR(Start_Date)<@First_Year then @First_Year  
else YEAR(Start_Date) end as Start_Year,  
case  
when End_Date is null then @Reporting_Year  
when YEAR(End_Date)>@Reporting_Year then @Reporting_Year  
else YEAR(End_Date) end as End_Year from #Has_ACT) x  
left join   
(
select a.Building_ID,a.Building,a.Asset_Class,MAX(a.Reporting_Year) as Most_Recent_GFA_Year  
from View_All_Buildings_Annual_GFA a      
inner join View_All_Buildings b on a.Building_ID=b.Building_ID      
inner join View_All_Building_Ownership_By_Year c on c.Building_ID=a.Building_ID and c.Reporting_Year=@Reporting_Year      
inner join Building_Ownership d on a.Building_ID=d.Building_ID      
left join Override_Building_Count e on a.Building_ID=e.Building_ID and e.Report_ID=5      
inner join #Has_ACT f on f.Building_ID=a.Building_ID    
where b.Asset_Manager like 'Anonymous'      
and b.Not_On_Program=0 and b.Exclude_From_Reporting=0 and b.Tenant=0      
and d.Year_Removed is null    
and (e.Building_Count<>0 or e.Building_Count is null)  
group by a.Building_ID,a.Building,a.Asset_Class) y on x.Building_ID=y.Building_ID  
cross join #Reporting_Years z1 where z1.Reporting_Year between @First_Year and @Reporting_Year  
and z1.Reporting_Year>=x.Start_Year and z1.Reporting_Year<=x.End_Year  
and y.Building_ID is not null) i2 on i1.Reporting_Year=i2.Reporting_Year  
where i1.Reporting_Year between @Start_Year and @Reporting_Year  
group by i1.Reporting_Year  
order by i1.Reporting_Year;  

Когда я запускаю этот запрос в SQL Server Management Studio, символ за символом, он возвращает именно те результаты, которые я ожидаю.

enter image description here

Однако , когда код VB выполняется, он запускает код перехвата. Прочитав сообщения о похожих проблемах, я попытался изменить запрос, чтобы получить 0 вместо NULL, но проблема остается. Кроме того, другие запросы дают значения NULL, но отлично работают с кодом VB.

Буду признателен за любой совет. Я также хотел бы знать, есть ли способ получить SQLDataAdapter или SQLCommand для возврата ошибки. Это значительно упростит диагностику.

ОБНОВЛЕНИЕ: Если я закомментирую Try ... Catch ... End Try и разрешу Visual Studio сгенерировать ошибку, я получу следующее.

enter image description here

1 Ответ

0 голосов
/ 23 февраля 2020

Итак, похоже, что @AndrewMorton был на правильном пути, в отношении нескольких запросов SQL, использующих одно соединение. Я создал совершенно новый проект VB. net, добавил код для извлечения указанного c сохраненного SQL оператора, который вызывал проблему, а затем запустил его. Это работало без проблем. Зная, что в исходном проекте я заменил код для запуска конкретной SqlCommand на отдельном соединении, избавляясь от экземпляра соединения после каждого l oop.

Код теперь работает, как и ожидалось. До сих пор неясно, почему именно это конкретное заявление SQL стало причиной проблемы, но не другие. Тем не менее, несмотря на это, я буду переделывать весь код в этом проекте, чтобы удалить один объект подключения.

Ссылка, приведенная в другом комментарии @ AndrewMorton, https://ubitsoft.com/t-sql-beautilyzer/ также была полезной. На самом деле я искал способ независимой проверки SQL запросов без необходимости базовой базы данных.

...