таким образом, чтобы задействовать максимум()
У меня есть столбцы DateTime, total, material и Mix.
Это оборудование запускает Mix A в течение x часов, а затем переключается на Mix B в течение x часов. Затем переключается обратно на Mix A.
Я хотел бы иметь запрос, который просто:
Select max(total), material, mix
from database
group by material, mix
Однако мне нужно было бы уловить тот факт, что Mix A был запущен дважды, и только 1 значение будет записано, и я не буду знать, сколько материала было использовано в том, который был пропущен.
Есть ли способ посмотреть на Max (total), тогда ищите нового Макса каждый раз, когда меняется смесь или материал? (не фактическая различная смесь / материал, но когда она фактически изменяется от смеси B к смеси A.
редактировать, чтобы показать, как выглядят данные
Timestamp Mix Material Tons
2017-02-08 07:49:25.000 MixA Mat1 30.05
2017-02-08 07:50:25.000 MixA Mat1 30.27
2017-02-08 07:51:25.000 MixA Mat1 30.50
2017-02-08 07:52:25.000 MixA Mat1 30.76
2017-02-08 07:53:25.000 MixA Mat1 31.01
2017-02-08 07:58:25.000 MixB Mat1 0.1
2017-02-08 07:59:25.000 MixB Mat1 0.8
2017-02-08 08:00:25.000 MixB Mat1 1.3
2017-02-08 08:01:25.000 MixB Mat1 2.0
2017-02-08 08:02:25.000 MixB Mat1 2.5
2017-02-08 08:10:25.000 MixA Mat1 0.1
2017-02-08 08:01:25.000 MixA Mat1 0.5
Итак, перед первой записью, показанной выше, машина работала некоторое время. Затем они поменяли миксы, побежали, затем переключились обратно и закончили производство на день.
Я пытаюсь найти наиболее эффективный способ найти количество используемого материала., потому что колонка тонн-это текущий итог, и я не могу просто суммировать его. MAX() было бы очень просто, однако я пропустил бы второй запуск Mix A.
2 ответа:
Для меня это выглядит как
gap-and-islands
.Примеры данных
Примечание, я добавил
Mat2
, чтобы показать, что нам нужно разбить по нему и зафиксировал метку времени последней записи.DECLARE @T TABLE(ts datetime2(0), Mix varchar(50), Material varchar(50), Tons float); INSERT INTO @T (ts, Mix, Material, Tons) VALUES ('2017-02-08 07:49:25', 'MixA', 'Mat1', 30.05), ('2017-02-08 07:50:25', 'MixA', 'Mat1', 30.27), ('2017-02-08 07:51:25', 'MixA', 'Mat1', 30.50), ('2017-02-08 07:52:25', 'MixA', 'Mat1', 30.76), ('2017-02-08 07:53:25', 'MixA', 'Mat1', 31.01), ('2017-02-08 07:58:25', 'MixB', 'Mat1', 0.1 ), ('2017-02-08 07:59:25', 'MixB', 'Mat1', 0.8 ), ('2017-02-08 08:00:25', 'MixB', 'Mat1', 1.3 ), ('2017-02-08 08:01:25', 'MixB', 'Mat1', 2.0 ), ('2017-02-08 08:02:25', 'MixB', 'Mat1', 2.5 ), ('2017-02-08 08:10:25', 'MixA', 'Mat1', 0.1 ), ('2017-02-08 08:11:25', 'MixA', 'Mat1', 0.5 ), ('2017-02-08 07:49:25', 'MixA', 'Mat2', 30.05), ('2017-02-08 07:50:25', 'MixA', 'Mat2', 30.27), ('2017-02-08 07:51:25', 'MixA', 'Mat2', 30.50), ('2017-02-08 07:52:25', 'MixA', 'Mat2', 30.76), ('2017-02-08 07:53:25', 'MixA', 'Mat2', 31.01), ('2017-02-08 07:58:25', 'MixB', 'Mat2', 0.1 ), ('2017-02-08 07:59:25', 'MixB', 'Mat2', 0.8 ), ('2017-02-08 08:00:25', 'MixB', 'Mat2', 1.3 ), ('2017-02-08 08:01:25', 'MixB', 'Mat2', 2.0 ), ('2017-02-08 08:02:25', 'MixB', 'Mat2', 2.5 ), ('2017-02-08 08:10:25', 'MixA', 'Mat2', 0.1 ), ('2017-02-08 08:11:25', 'MixA', 'Mat2', 0.5 );
Запрос
WITH CTE_rn AS ( SELECT ts ,Mix ,Material ,Tons ,ROW_NUMBER() OVER (PARTITION BY Material ORDER BY ts) AS rn1 ,ROW_NUMBER() OVER (PARTITION BY Material, Mix ORDER BY ts) AS rn2 FROM @T ) ,CTE_Groups AS ( SELECT ts ,Mix ,Material ,Tons ,rn1 ,rn2 ,rn1 - rn2 AS GroupNumber FROM CTE_rn ) SELECT Material ,Mix ,MAX(Tons) AS MaxTons ,MAX(ts) AS MaxTS FROM CTE_Groups GROUP BY Material ,GroupNumber ,Mix ORDER BY Material ,MaxTS ;
Результат
+----------+------+---------+---------------------+ | Material | Mix | MaxTons | MaxTS | +----------+------+---------+---------------------+ | Mat1 | MixA | 31.01 | 2017-02-08 07:53:25 | | Mat1 | MixB | 2.5 | 2017-02-08 08:02:25 | | Mat1 | MixA | 0.5 | 2017-02-08 08:11:25 | | Mat2 | MixA | 31.01 | 2017-02-08 07:53:25 | | Mat2 | MixB | 2.5 | 2017-02-08 08:02:25 | | Mat2 | MixA | 0.5 | 2017-02-08 08:11:25 | +----------+------+---------+---------------------+
Вы можете суммировать его далее, чтобы добавить
31.01
и0.5
дляMat1
, Если вам это нужно. Просто добавьте еще одинGROUP BY Material, Mix
. Вопрос не совсем ясен, каким должен быть результат.Как это работает
Выполнить запрос шаг за шагом, cte-за-cte, чтобы понять, как это работает.
"Пробелы и острова" - это классическая проблема. КогдаMix
изменяется, за " островом "следует"пробел".
CTE_rn
вычисляет два набора номеров строк. Разница между ними заключается в количестве группы (CTE_Groups
).WITH ... SELECT * FROM CTE_Groups ORDER BY Material, ts;
Производит
+---------------------+------+----------+-------+-----+-----+-------------+ | ts | Mix | Material | Tons | rn1 | rn2 | GroupNumber | +---------------------+------+----------+-------+-----+-----+-------------+ | 2017-02-08 07:49:25 | MixA | Mat1 | 30.05 | 1 | 1 | 0 | | 2017-02-08 07:50:25 | MixA | Mat1 | 30.27 | 2 | 2 | 0 | | 2017-02-08 07:51:25 | MixA | Mat1 | 30.5 | 3 | 3 | 0 | | 2017-02-08 07:52:25 | MixA | Mat1 | 30.76 | 4 | 4 | 0 | | 2017-02-08 07:53:25 | MixA | Mat1 | 31.01 | 5 | 5 | 0 | | 2017-02-08 07:58:25 | MixB | Mat1 | 0.1 | 6 | 1 | 5 | | 2017-02-08 07:59:25 | MixB | Mat1 | 0.8 | 7 | 2 | 5 | | 2017-02-08 08:00:25 | MixB | Mat1 | 1.3 | 8 | 3 | 5 | | 2017-02-08 08:01:25 | MixB | Mat1 | 2 | 9 | 4 | 5 | | 2017-02-08 08:02:25 | MixB | Mat1 | 2.5 | 10 | 5 | 5 | | 2017-02-08 08:10:25 | MixA | Mat1 | 0.1 | 11 | 6 | 5 | | 2017-02-08 08:11:25 | MixA | Mat1 | 0.5 | 12 | 7 | 5 | | 2017-02-08 07:49:25 | MixA | Mat2 | 30.05 | 1 | 1 | 0 | | 2017-02-08 07:50:25 | MixA | Mat2 | 30.27 | 2 | 2 | 0 | | 2017-02-08 07:51:25 | MixA | Mat2 | 30.5 | 3 | 3 | 0 | | 2017-02-08 07:52:25 | MixA | Mat2 | 30.76 | 4 | 4 | 0 | | 2017-02-08 07:53:25 | MixA | Mat2 | 31.01 | 5 | 5 | 0 | | 2017-02-08 07:58:25 | MixB | Mat2 | 0.1 | 6 | 1 | 5 | | 2017-02-08 07:59:25 | MixB | Mat2 | 0.8 | 7 | 2 | 5 | | 2017-02-08 08:00:25 | MixB | Mat2 | 1.3 | 8 | 3 | 5 | | 2017-02-08 08:01:25 | MixB | Mat2 | 2 | 9 | 4 | 5 | | 2017-02-08 08:02:25 | MixB | Mat2 | 2.5 | 10 | 5 | 5 | | 2017-02-08 08:10:25 | MixA | Mat2 | 0.1 | 11 | 6 | 5 | | 2017-02-08 08:11:25 | MixA | Mat2 | 0.5 | 12 | 7 | 5 | +---------------------+------+----------+-------+-----+-----+-------------+
Затем мы просто
GROUP BY Material, GroupNumber, Mix
, чтобы получить конечный результат.
Поместите это здесь, чтобы показать, что использовалось, чтобы у вас было представление о том, насколько вы помогли очистить это и оптимизировать его. Текущий способ сделать это:
SELECT D1.[Day], D1.[TimeStamp], D1.[Material], D1.Source, CASE WHEN D1.[RunTotal] - D2.[RunTotal] >= 0 THEN D1.[RunTotal] - D2.[RunTotal] ELSE 0 END AS [Tons] FROM (SELECT ROW_NUMBER() OVER (ORDER BY [TimeStamp]) rownum, [TimeStamp], cast([TimeStamp] AS date) [Day], MIN(CASE Equipment WHEN 'Bin1' THEN CAST([Run Total] AS decimal(18, 3)) END) AS [RunTotal], MIN(CASE Equipment WHEN 'Bin1' THEN Material END) AS [Material], 'Bin1' AS Source FROM Plant_Production.dbo.Data WHERE Equipment = 'Bin1' GROUP BY [Timestamp]) D1 LEFT OUTER JOIN (SELECT ROW_NUMBER() OVER (ORDER BY [TimeStamp]) rownum, [TimeStamp], cast([TimeStamp] AS date) [Day], MIN(CASE Equipment WHEN 'Bin1' THEN CAST([Run Total] AS decimal(18, 3)) END) AS [RunTotal], MIN(CASE Equipment WHEN 'Bin1' THEN [Material] END) AS [Material], 'Bin1' AS Source FROM Plant_Production.dbo.Data WHERE Equipment = 'Bin1' GROUP BY [TimeStamp]) D2 ON D1.RowNum - 1 = D2.RowNum AND D1.[Day] = D2.[Day]
Они делают это для каждого местоположения ячейки и суммируют все значения для диапазона дат. Способ, который вы предложили, кажется не только намного быстрее запроса, но и намного чище.