2016-12-22 2 views
0

У меня есть запрос, который проверяет статус конкретного танка, однако у меня есть 50 танков, которые я бы хотел выполнить это для (FV101, FV102, FV103 и т.д.)SQL Выполнить запрос несколько раз изменяя переменную

Я мог объединить 50 запросов с измененным WHERE, но я подозреваю, что должен быть лучший способ.

Запрос очень прост:

DECLARE @tank varchar(5) 
SET @tank = 'FV101' 

SELECT 
    ROW_NUMBER() OVER (PARTITION BY [Item] ORDER BY [TankName]) [Row], 
    * 
    FROM 
(
SELECT TOP 1 
    @tank [TankName], 
    T1.[Item], 
    CASE WHEN AVG(CAST(T0.[pHValue] AS dec (10,5))) NOT BETWEEN MAX(T2. [pH_lower]) AND MAX(T2.[pH_upper]) THEN 'Red' ELSE 'Black' END [Spec] 
FROM 
    t005_pci_data T0 INNER JOIN t001_fvbatch T1 ON T1.[FVBatch] = T0. [FVBatch] LEFT JOIN t024_specifications T2 ON T2.[BeerBrand] = T1.[BeerBrand]  AND [Type] = 'Finished Product' 
WHERE 
    T0.[FVBatch] = (SELECT TOP 1 T0.[FVBatch] FROM t005_pci_data T0 INNER  JOIN t001_fvbatch T1 ON T1.[FVBatch] = T0.[FVBatch] WHERE T1.[TankName] =  'FV101' ORDER BY T0.[DateTime] DESC) AND 
    EXISTS (SELECT [FVBatch] FROM t005_pci_data WHERE [TankName] = @tank AND [DateTime] >= DATEADD(day,-2,GETDATE())) 
GROUP BY 
    T1.[Item],T0.[DateTime] 
ORDER BY 
    T0.[DateTime] DESC 
) a 

Есть ли способ, чтобы передать список значений для этого запроса для того, чтобы использовать вместо повторения запроса вручную несколько раз?


EDIT согласно предложению iamdave в

схемы (упрощенный), как показано ниже:

enter image description here

Цель состоит в том, чтобы перечислить все, что в настоящее время в каждом баке и проверить, если значение рН находится в допустимых пределах.

Желаемая выход (до FV105) будет:

enter image description here

В этом примере нет ничего в танках FV101 или FV104, в соответствии с решением следующего кода в WHERE

EXISTS (SELECT [FVBatch] FROM t005_pci_data WHERE [TankName] = @tank AND [DateTime] >= DATEADD(day,-2,GETDATE())) 

Конечным результатом является создание таблицы в MSSRS, которая показывает, какой элемент находится в каждом резервуаре, и соответствует ли он спецификациям или нет.


ДАЛЕЕ EDIT с данными выборки по запросу (Не очень творческий Я боюсь)

declare @t1 table(FVBatch int, TankName nvarchar(5), Item nvarchar(20)); 
declare @t2 table(Item nvarchar(20), ph_lower decimal(10,2), ph_upper decimal(10,2)); 
declare @t3 table(FVBatch int, pHValue decimal(10,2), DateValue datetime); 

insert into @t1 values 
(3160001,'FV101','Stout') 
,(3160002,'FV102','Stout') 
,(3160003,'FV103','Stout') 
,(3160004,'FV104','Pale Ale') 
,(3160005,'FV105','Pale Ale') 
,(3160070,'FST04','IPA'); 

insert into @t2 values 
('Pale Ale',3.5,5.5) 
,('Stout',2,3.5); 

insert into @t3 values 
(3160001,4 ,'20161209') 
,(3160001,4 ,'20161210') 
,(3160001,4 ,'20161212') 
,(3160002,4 ,'20161218') 
,(3160002,4 ,'20161220') 
,(3160002,4 ,'20161222') 
,(3160003,4 ,'20161218') 
,(3160003,4 ,'20161220') 
,(3160003,4 ,'20161222') 
,(3160004,4 ,'20161209') 
,(3160004,4 ,'20161210') 
,(3160004,4 ,'20161212') 
,(3160005,4 ,'20161218') 
,(3160005,4 ,'20161220') 
,(3160005,4 ,'20161222') 
,(3160070,4.26,'20161218') 
,(3160070,4.26,'20161216') 
,(3160070,4.24,'20161215') 
,(3160070,4.24,'20161214') 
,(3160070,4.26,'20161213') 
,(3160070,4.2 ,'20161212') 
,(3160070,4.21,'20161211') 
,(3160070,4.12,'20161209') 
,(3160070,4.09,'20161208') 
,(3160070,4.1 ,'20161207'); 
+0

Ваш запрос выглядит слишком сложным, чтобы начать с, вы можете разместить ваш схема данных и желаемый результат? Вероятно, есть лучший способ сделать это, чем просто редактировать текущий запрос. – iamdave

+0

Если у вас есть код, который вы хотите выполнить много раз с разными входными значениями, то хранимую процедуру или, возможно, функцию (в вашем случае, возможно, табличную функцию, поскольку вы хотите вернуть несколько столбцов). Однако я также согласен с [John Cobby] (http://stackoverflow.com/users/6478307/john-cobby) - ваш код выглядит так, как будто он может воспользоваться рефактором. Например, почему вы используете 'ROW_NUMBER()', когда выбранный подзапрос возвращает только одну строку? – 3N1GM4

+0

Я отредактирую с предложениями iamdave, чтобы показать, почему коротко – coblenski

ответ

2

Как это сделать?

select row_number() over (partition by t1.Item order by t1.TankName) as RowNum 
     ,t1.TankName 
     ,t1.Item 
     ,case when avg(t3.pHValue) between t2.ph_lower and t2.ph_upper 
      then 'Black' 
      else 'Red' 
      end as Spec 
from @t1 t1 
    left join @t2 t2 
     on(t1.Item = t2.Item) 
    inner join(select FVBatch 
         ,pHValue 
         ,max(DateValue) as DateValue 
       from @t3 
       where DateValue >= cast(dateadd(d,-2,getdate()) as date) 
       group by FVBatch 
         ,pHValue 
       ) t3 
     on(t1.FVBatch = t3.FVBatch) 
group by t1.TankName 
     ,t1.Item 
     ,t2.ph_lower 
     ,t2.ph_upper 
order by t1.TankName 
     ,RowNum 

Используя тестовые данные, приведенный выше запрос возвращает:

RowNum TankName Item  Spec 
1  FV102  Stout  Red 
2  FV103  Stout  Red 
1  FV105  Pale Ale Black 

Редактировать на основе разговора

/* 
The full requirement is this: 
there could be multiple of each measurement taken on any one date, 
so I want to check that the average of these measurements per day is withing the range 
each batch goes through several stages 
if the stage isn't "bottle" or "can" then we look back 2 days 
if it is one of those then we look back 5 days instead 
*/ 
declare @t001_fvbatch table(FVBatch int 
          ,TankName nvarchar(5) 
          ,BeerBrand nvarchar(20) 
          ); 
declare @t024_specifications table(BeerBrand nvarchar(20) 
            ,pH_lower decimal(10,2) 
            ,pH_upper decimal(10,2) 
            ,OG_lower decimal(10,2) 
            ,OG_upper decimal(10,2) 
            ,PG_lower decimal(10,2) 
            ,PG_upper decimal(10,2) 
            ,EBCHaze decimal(10,2) 
            ,ABV_lower decimal(10,2) 
            ,ABV_upper decimal(10,2) 
            ,[Type] nvarchar(50) 
            ); 
declare @t005_pci_data table(FVBatch int 
          ,pHValue decimal(10,2) 
          ,Alcohol decimal(10,2) 
          ,OG decimal(10,2) 
          ,PG decimal(10,2) 
          ,EBCHaze decimal(10,2) 
          ,[DateTime] datetime 
          ,Stage nvarchar(20) 
          ,TankName nvarchar(20) 
          ); 
select b.FVBatch 
     ,b.TankName 
     ,b.BeerBrand 
     ,case when((d.Stage in('CAN','BOTTLE','BBT') 
         and avg(cast(d.EBCHaze as dec(10,5))) > 5 
        ) 
         or (avg(cast(d.Alcohol as dec(10,5))) not between max(s.ABV_lower) and max(s.ABV_upper) 
          or avg(cast(d.OG as dec(10,5))) not between max(s.OG_lower) and max(s.OG_upper) 
          or avg(cast(d.PG as dec(10,5))) not between max(s.PG_lower) and max(s.PG_upper) 
          or avg(cast(d.pHValue as dec(10,5))) not between max(s.pH_lower) and max(s.pH_upper) 
         ) 
        ) 
       then 'Red' 
       else 'Black' 
      end as Spec 

from @t001_fvbatch b -- Always start at the table with the most central piece of data. In this case, the specifications and measurements all relate to a single batch. 

    left join @t024_specifications s 
     on(b.BeerBrand = s.BeerBrand 
      and s.[Type] = 'Finished Product' 
      ) 

    inner join (select d2.FVBatch  -- This sub select returns the most recent DateTime value per each FVBatch and TankName combination. 
         ,d2.TankName 
         ,cast(max(d2.[DateTime]) as date) as MostRecentMeasurement -- Cast/convert to DATE type to remove the TIME element. This means 2016-12-22 12:00:00 and 2016-12-22 13:59:43 both become 2016-12-22. 
       from @t005_pci_data d2 
       where d2.[DateTime] >= cast(dateadd(d -- This case statement filters the DateTime values by a number of days based on the value in the Stage column. 
                ,case when d2.Stage in('can','bottle') 
                  then -5 
                  else -2 
                  end 
                ,getdate() 
                ) 
              as date) 
       group by d2.FVBatch 
         ,d2.TankName 
       ) dm 
     on(b.FVBatch = dm.FVBatch 
      and b.TankName = dm.TankName 
      ) 

    inner join @t005_pci_data d  -- We then join into the data table again to get all the measurements taken on the same day as the most recent. 
     on(b.FVBatch = d.FVBatch 
      and b.TankName = d.TankName 
      and d.[DateTime] >= dm.MostRecentMeasurement -- Filtering like this allows any indexes on your DateTime column to be used to speed execution time. (This is called sargability). 
      and d.[DateTime] < dateadd(d,1,dm.MostRecentMeasurement) -- We could use functions to convert the DateTime to a DATE data type to match the MostRecentMeasurement value, but this would then need to be calculated for every single measurement in the table, which is wasteful. 
      ) 

      -- Using INNER JOIN for the measurements means we are only return batches that have measurements that meet our filtering criteria. 
      -- If we wanted to return a batch even if there were no measurements matching, we would use LEFT JOIN instead. 

group by b.FVBatch 
     ,b.TankName 
     ,b.BeerBrand 
     ,d.Stage 
+0

«Полные требования»: бак считается активным, если в течение предыдущих 2 дней проводился тест pH. Я хотел бы перечислить все активные танки и то, что в настоящее время находится в каждом из этих танков. – coblenski

+1

@JohnCobby Я обновил свой ответ. Это должно показывать только строку для самой последней даты тестирования pH из-за 'max (DateValue)' в подселекторе 't3'. – iamdave

+0

Я прочитал код, и это имеет смысл для меня, спасибо. Не могли бы вы объяснить, почему он показывает TankName 'FST04', когда последний DateValue для этого резервуара «2016-12-14»? – coblenski