2014-07-15 3 views
1

В запросе SQL я что-то вычисляю. Этому исчислению нужна таблица (DurationsLog), которая не должна быть пустой (таблица должна содержать строки).Условно выбор столбца (странные результаты)

Так что я пытаюсь обработать случай, когда эта таблица пуста.

Итак, я попытался обработать его с помощью CASE в select, но он не работает (получил 0 строк, когда DurationsLog пуст).

Вот запрос:

SELECT 
    o.Maint, 
    CASE 
     WHEN EXISTS(SELECT * FROM DurationsLog) 
     THEN DATEADD(day, (p.CycleDuration - (c.TotalRotationCounter - o.LastActionCounter))/AVG(d.RotationDuration), GetDate()) 
     ELSE 'CALCUL IMPOSSIBLE' 
    END AS CalculProchaineDate 
FROM 
    dbo.Operations o 
INNER JOIN 
    dbo.Periods As p ON o.PeriodId = p.Id, 
    dbo.Counters c, 
    dbo.DurationsLog d 
WHERE 
    p.CycleDuration>0 
GROUP BY 
    o.Maint, p.CycleDuration, c.TotalRotationCounter, o.LastActionCounter 

NB: не DurationsLog уже не соединения с другой таблицей

NB-бис: Когда DurationsLog содержит строки, он работает нормально

NB 3: система SQL является Microsoft SQL Server 2008

Редактировать: S кажется, что я не очень хорошо объяснил свою проблему, я подробно расскажу об этом:

Таблица dbo.Operations содержит информацию об обслуживании. Его основным ключом является «Maint» и он содержит внешний ключ «PeriodId» на таблице dbo.Periods.

dbo.Periods таблица содержит Id в качестве первичного ключа и поля «CycleDuration», который я использую для исчисления

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

dbo.DurationsLog содержит первичный ключ, который является датой. Эта таблица хранит, сколько времени наша машина вращалась и производилась сегодня. Так эта таблица содержит один ряд/день

«CycleDuration» из Периодов магазинов, сколько времени (в часах) между двумя операциями (примером: нам нужно очистить й каждые 4000 часов, CycleDuration будет 4000)

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

Вот почему я рассчитываю: CycleDuration - (Счетчик последнего времени, когда я выполнял операцию)/Средняя продолжительность в день. При этом я могу оценить, когда будут выполняться следующие операции.

+1

[Плохие привычки пинать: использование старого стиля JOIN и] (http://sqlblog.com/blogs/aaron_bertrand/archive/ 2009/10/08/BAD-привычки к ножным, используя старый стиль-соединения.aspx) - используйте правильный ANSI - ** 92 ** Стандартный 'INNER JOIN' /' LEFT OUTER JOIN' синтаксис (и, безусловно, ** не смешивайте ** два стиля!) –

+0

@marc_s вы могли бы быть более конкретными, как бы вы переписывали соединения в этом запросе? Насколько я знаю, я использую INNER JOIN (таблицы Counters & DurationsLog не имеют объединений с другими таблицами) –

+1

Вы ** не ** используете правильную 'INNER JOIN' для таблиц' dbo.Counters c' и 'dbo .DurationsLog d' .... если у вас «нет соединений», то используйте «CROSS JOIN» или «FULL OUTER JOIN» для соответствия SQL-92. –

ответ

0

Причина заключается в том, когда у вас есть DurationsLog таблицы пусты, INNER JOIN будет всегда пустым Именно здесь:

INNER JOIN 
     dbo.Periods As p ON o.PeriodId = p.Id, 
     dbo.Counters c, 
     dbo.DurationsLog d 

у вас нет подключения условий между таблицами Counters, DurationsLog и остальной частью запроса.

Решение предвычислять необходимые значения вместо соединения таблиц сам себе:

declare @AvgDuration float; 
select 
    @AvgDuration = AVG(d.RotationDuration) 
from dbo.DurationsLog d; 

declare @TotalCounter int; 
select 
    @TotalCounter = c.TotalRotationCounter 
from dbo.Counters; 

SELECT 
    o.Maint, 
    CASE 
     WHEN @AvgDuration IS NOT NULL 
     THEN DATEADD(day, (p.CycleDuration - 
      (@TotalCounter - o.LastActionCounter)) 
      /@AvgDuration, GetDate()) 
     ELSE 'CALCUL IMPOSSIBLE' 
    END AS CalculProchaineDate 
FROM 
    dbo.Operations o 
INNER JOIN 
    dbo.Periods As p ON o.PeriodId = p.Id 
WHERE 
    p.CycleDuration>0 
GROUP BY 
    o.Maint, p.CycleDuration, o.LastActionCounter; 
+0

Спасибо за ваш ответ, но этот запрос дает мне синтаксическую ошибку. LEFT JOIN ожидает «ON t1.id = t2.id» или что-то вроде этого. Проблема в том, что между счетчиками и длительностью и любой другой таблицей нет никакой связи. То, что я храню, это те, которые я использую для расчета даты. DurationsLog содержит количество часов использования машины в течение этого дня, каждый день добавляется строка. Счетчики содержат одно и то же, за исключением того, что они хранят общее количество этих счетчиков. Затем я пытаюсь оценить, когда потребуется следующая Операция. –

+0

Итак, я делаю: (TimeBetweenTwoOperations - CounterOfLastTimeIDidThisOperation)/AverageUsePerDay, чтобы узнать, сколько дней мне нужно сделать снова эти же операции (операция обслуживания) –

+0

Ну, если есть теперь взаимозависимость между счетчиками, DurationsLog, то почему бы просто не просчитать необходимые значения? Я изменил свой ответ из-за такого подхода – xacinay

Смежные вопросы