Для IE http://support.microsoft.com/kb/980077
должно быть что-то подобное для И следующие
p.s., Вы не можете установить это для клиентов!
p.s.2. можно заменить это звезды передними изображениями (абсолютный в случае необходимости) в css (медиа = "печать").
с помощью аналитики вы можете создать запрос, который будет выполнять один проход данных (с большим набором данных это будет наиболее эффективным):
SELECT machineid, MIN(start_time), MAX(end_time)
FROM (SELECT machineid, start_time, end_time,
SUM(gap) over(PARTITION BY machineid
ORDER BY start_time) contiguous_faults
FROM (SELECT machineid, start_time,
coalesce(end_time, DATE '9999-12-31') end_time,
CASE
WHEN start_time > MAX(coalesce(end_time,
DATE '9999-12-31'))
over(PARTITION BY machineid
ORDER BY start_time
ROWS BETWEEN UNBOUNDED PRECEDING
AND 1 preceding)
THEN 1
END gap
FROM faults))
GROUP BY machineid, contiguous_faults
ORDER BY 1, 2
Этот запрос начинается с определения, строка смежна с любой строкой, которая началась раньше. Затем мы группируем смежные строки.
По сути, вы не можете сделать это (найти покрывающее множество разбиений леса) в чистой теории множеств (например, как ограниченное количество запросов без цикла).
Чтобы сделать это наиболее похожим на набор способом,
Создайте временную таблицу для разделения леса (10 или 11 столбцов, 4 из ошибки №1, 4 из ошибки №2, 1 для идентификатора раздела, 1 для раунда, в который был вставлен узел, и 1 для различных оптимизаций, о которых я не могу вспомнить с температурой 38C.
Запустите цикл (BFS или DFS, что бы вы ни нашли, чтобы упростить реализацию алгоритма разделения леса). Сложная часть, по сравнению с графиками, заключается в что у вас может быть много поддеревьев, соединенных сверху с текущим поддеревом
. Вы можете использовать запрос sheepsimulator в качестве основного строительного блока для цикла (например, найти 2 соединенных узла)
Когда цикл разбиения завершен,просто сделайте
select min(p1.start_time), max(p2.end_time), p1.partition,p2.partition from partitions p1, partitions p2 where p1.partition = p2.partition group by p1.partition,p2.partition /* This will need to be tweaked using COALESCE to deal with NULL end times in obvious way) */
Прошу прощения за то, что не написали точный код для разбиения леса (он может быть записан в разделе разбиения на дерево) - я очень устал и уверен, что поиск в Google даст код, теперь, когда вы знаете структуру tdata и проблему имя (или вы можете опубликовать это как более точно сформулированный вопрос в StackOverflow - например, «Как реализовать алгоритм для полного разбиения леса деревьев в виде цикла в SQL».
SELECT machineid, min(start_time), max(ifnull(end_time, '3000-01-01 00:00'))
FROM faults
GROUP BY machineid
должен выполнить эту работу (при необходимости заменив ifnull эквивалентной функцией Oracle).
SELECT DISTINCT
t1.machineId,
MIN(t2.start_time) start_time,
MAX(COALESCE(t2.end_time, '3210/01/01')) end_time
FROM FAULTS t1
JOIN FAULTS t2 ON t1.machineId = t2.machineId
AND ((t2.start_time >= t1.start_time
AND (t1.end_time IS NULL OR t2.start_time <= t1.end_time)
)
OR
(t1.start_time >= t2.start_time
AND (t2.end_time IS NULL OR t1.start_time <= t2.end_time)
))
GROUP BY t1.machineId, t1.part_id
Я проверил этот запрос на следующих данных:
machine_id |part_id |start_time |end_time
-------------------------------------------------------------------------
1 |2 |05 Oct 2009 09:00:00 |NULL
1 |3 |05 Oct 2009 08:00:00 |05 Oct 2009 10:00:00
2 |2 |30 Sep 2009 12:00:00 |30 Sep 2009 14:00:00
2 |3 |30 Sep 2009 15:00:00 |30 Sep 2009 16:00:00
2 |4 |30 Sep 2009 16:00:00 |30 Sep 2009 17:00:00
3 |2 |28 Sep 2009 12:00:00 |28 Sep 2009 14:00:00
3 |4 |28 Sep 2009 13:00:00 |28 Sep 2009 15:00:00
Я получил это:
machine_id |start_time |end_time
-----------------------------------------------------------------
1 |05 Oct 2009 08:00:00 |01 Jan 3210 00:00:00
2 |30 Sep 2009 12:00:00 |30 Sep 2009 14:00:00
2 |30 Sep 2009 15:00:00 |30 Sep 2009 17:00:00
3 |28 Sep 2009 12:00:00 |28 Sep 2009 15:00:00
Хотел бы я дать полный ответ, но вот подсказка, чтобы найти перекрывающиеся простои:
select a.machineid, a.start_time, a.end_time, b.start_time, b.end_time
from faults a,
faults b,
where a.machineid = b.machineid
and b.start_time >= a.start_time
and b.start_time <= a.end_time;
Я считаю, что для этого вам понадобится хранимая процедура или что-то вроде рекурсивных общих табличных выражений (CTE) (как существует в SQL srever) или иначе (в одном операторе SQL) вы не сможете получить правильный ответ, если 3 или более строк вместе образуют непрерывный диапазон охватываемых дат.
например:
|----------|
|---------------|
|----------------|
Фактически не выполняя упражнение, я мог бы предложить, чтобы в сохраненной процедуре построить таблицу всех «кандидатных дат», а затем построить таблицу, содержащую все даты, которые НЕ охвачены диапазоном дат в существующей строке, а затем создайте выходной набор результатов, "отрицая" этот набор.
См. Это обсуждение - с решением внизу: http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft. public.sqlserver.programming & tid = 2bae93da-c70e-4de4-a58b-d8cc0bf8ffd5
Хе-хе.
В SIRA_PRISE, который поддерживает интервальные типы, решить эту проблему так же просто, как
SELECT machineID, period FROM Faults.
IN где 'period' - атрибут типа временного интервала, начальная и конечная точки которого - start_time и end_time вашей таблицы SQL.
Но поскольку вы, вероятно, вынуждены решать эту проблему в SQL, и с системой, которая не поддерживает типы интервалов, я могу только желаю вам много храбрости.
Два совета:
Объединение двух интервалов может быть обработано в SQL с использованием сложных конструкций CASE (если interval_values_overlap, то low_start_time, high_end_time, и все такое).
Поскольку вы не можете заранее сообщите, сколько строк объединятся в одну, вы, вероятно, будете вынуждены писать рекурсивный SQL.