Книга знаний

1С:Предприятие / Объекты конфигурации / Документы

Изменение времени документов для выстраивания их на временной оси

Изменение времени документов от времени начала до времени окончания для выстраивания их на временной оси используя хранимую процедуру MSSQLАвтор статьи: mikecool | Редакторы:
Последняя редакция №2 от 23.06.06 | История
URL: http://kb.mista.ru/article.php?id=260

Ключевые слова: Документ, время,хранимая, процедура, SQL


Однажды столкнулся с ситуацией: пользователь, обладающий административными правами в 1С, перенес документы за предыдущий день, время которых было в районе 23:51. Остальные пользователи, активно работающие с базой и создавая документы, успели внести порядка 500 документов пока не закончился день по меркам 1С. Это случилось в 13.15 дня. Естессно, пришлось быстро писать обработку меняющую время документов. Все это(написание обработки и исправление) заняло порядка получаса времени. Довольно много для розничной торговли с высоким товарооборотом. Поэтому подумал и решил, что если у меня будет процедурка, которая будет исправлять время документов и выстраивать их по новой с интервалом в 1 секунду - то это решение возникшей у меня проблемы.

Возникла единственная проблема: после использования процедуры атрибут ВремяДок содержит время 00:00:00
Пока эту проблему не решил. Может кто поможет...
Далее привожу текст процедуры(сильно ее здесь не описываю, ибо снабдил некоторыми комментариями, будут вопросы - обращайтесь)

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
/*
    Процедура выполняет 'выстраивание' документов по времени, начиная
    с даты @StartD и времени @StartT и заканчивая датой @EndD и
    временем @EndT
*/
ALTER      PROCEDURE ChangeTimeDocs (@StartD char(10) = '', @StartT char(8) = '',
           @EndD char(10) = '', @EndT char(8) = '')
/*
    Параметры
    @StartD, @EndD - дата начала/конца правки, формат 'ГГГГ-ММ-ДД'
    @StartT, @EndT - Время начала/конца правки, формат 'ЧЧ:ММ:СС'
*/

AS

SET NOCOUNT ON

BEGIN

   IF @StartD = ''
       SELECT @StartD = Left(GetDate(), 10)

   IF @StartT = ''
       SELECT @StartT = '00:00:00'

   IF @EndD = ''
     SELECT @EndD = @StartD

   IF @EndT = ''
     SELECT @EndT = '23:59:59'

   /*
       @StartTime, @EndTime - символьное представление времени(ЧЧ:ММ:СС)
       @StartTimeI, @EndTimeI - время в секундах
       @Start, @End - строки для ограничения выборки из _1sjourn
       @CharDate - представление даты выборки в формате ГГГГММДД
   */
   DECLARE @Year INT, @Month INT, @Day INT,
                   @YearC CHAR(4), @MonthC CHAR(2), @DayC CHAR(2),
                   @StartTime CHAR(8), @EndTime CHAR(8),
                   @StartTimeI INT, @EndTimeI INT,
                   @Start CHAR(17), @End CHAR(17), @CharDate CHAR(8)
   -- для хождения циклом по диапазону дат показалось удобным иметь
 -- следующие переменные
   DECLARE @StartDate_Date DATETIME, @EndDate_Date DATETIME
   -- переменные для рассчитываемых значений даты и времени
 DECLARE @TempDate DATETIME, @TempTime INT

   -- переменные для значений из курсора документов
   DECLARE @Id_doc CHAR(9), @Id_DocDef INT, @DTIOld CHAR(23), @DTINew CHAR(23)
   -- Всего документов, значение для увеличения времени
   DECLARE @DocsCount INT, @Multiplier INT
   -- количество секунд в дне
   DECLARE @SecInDay INT

   -- начальная инициализация
   SELECT @StartDate_Date = CAST((@StartD+' '+@StartT) AS DATETIME)
   SELECT @EndDate_Date = CAST((@EndD+' '+@EndT) AS DATETIME)
   SELECT @TempDate = @StartDate_Date
   SELECT @SecInDay = 23*3600+59*60+59

/*
Теперь пробегаемся от даты старта до даты конца с интервалом в день
и внутри каждого дня выстраиваем документы, присваивая каждому новое
время, начиная с времени первого документа
В зависимости от количества документов, интервал секунда или доли секунды
*/
   WHILE @TempDate <= @EndDate_Date
   BEGIN
       -- взяли составляющие части 'рассчетной' даты
     SELECT @Year            = DATEPART(YEAR, @TempDate)
     SELECT @Month        = DATEPART(MONTH, @TempDate)
     SELECT @Day            = DATEPART(DAY, @TempDate)

       -- время начала дня '00:00:00' или переданное время старта
       IF DATEDIFF(DAY, @TempDate, @StartDate_Date)=0
           SELECT @StartTimeI =    CAST(LEFT(@StartT, 2) AS INT)*3600 +
                                                       CAST(SUBSTRING(@StartT, 4, 2) AS INT)*60 +
                                                       CAST(RIGHT(@StartT, 2) AS INT)
       ELSE
           SELECT @StartTimeI = 1
       
       IF @StartTimeI = 0
           SELECT @StartTimeI = 1

       -- получаем время в 36-ом формате
       SELECT @StartTime = dbo.Convert10to36(@StartTimeI)

       -- время конца дня '23:59:59' или переданное время окончания
       IF DATEDIFF(DAY, @TempDate, @EndDate_Date)=0
           SELECT @EndTimeI = (CAST(LEFT(@EndT, 2) AS INT)*3600 +
                                                   CAST(SUBSTRING(@EndT, 4, 2) AS INT)*60 +
                                                   CAST(RIGHT(@EndT, 2) AS INT))*10000
       ELSE
           SELECT @EndTimeI = @SecInDay * 10000
   
       -- получаем время в 36-ом формате
       SELECT @EndTime        = dbo.Convert10to36(@EndTimeI)
       -- значение рассчетного времени, которое будет использоваться для установки
       -- нового времени
       SELECT @TempTime    = @StartTimeI * 10000
       
       -- преобразуем момент начала-конца в символьный вид
       SELECT @YearC = CAST(@Year AS CHAR)
       SELECT @MonthC = CAST(@Month AS CHAR)
       IF LEN(@MonthC) = 1
           SELECT @MonthC = '0' + @MonthC
       SELECT @DayC = CAST(@Day AS CHAR)
       IF LEN(@DayC) = 1
           SELECT @DayC = '0' + @DayC

       SELECT @CharDate    = @YearC+@MonthC+@DayC
       SELECT @Start        = RTRIM(@CharDate + @StartTime)
       SELECT @End                = RTRIM(@CharDate + @EndTime)

       -- Выбираем документы за период
       -- курсор объявлен статическим, чтобы имелся слепок данных до обработки
       -- хотя может статика тут и не нужна...
     DECLARE Docs CURSOR STATIC FOR
       SELECT j.IDDOC AS IDDOC, j.IDDocDef AS IDDOCDEF,
                        j.Date_Time_IDDOC AS DTI_Old
               FROM _1sjourn as j (NOLOCK)
            WHERE (j.Date_Time_IdDoc >= @Start) AND
                        (j.Date_Time_IdDoc <= @End)
       
       OPEN Docs
   
       -- это количество документов, попавших в выборку
       SELECT @DocsCount = @@CURSOR_ROWS

       -- если мы упорядочиваем доки в пределах дня, то и число секунд
       -- берем между временем начала и временем конца
       IF DATEDIFF(DAY, @StartDate_Date, @EndDate_Date) = 0
           SELECT @SecInDay = @EndTimeI/10000 - @StartTime/10000

       -- вот на это значение будем домножать результирующие дату-время документа
       -- для расположения документа на временной оси
       -- отношение @SecInDay / @DocsCount ввел для универсальности - вдруг документов
       -- окажется более 84000 в день...
       SELECT @Multiplier = 10000
       IF @DocsCount > @SecInDay
           SELECT @Multiplier = @Multiplier * @SecInDay / @DocsCount
       
       FETCH NEXT FROM Docs
       INTO @Id_doc, @Id_DocDef, @DTIOld
       
       WHILE @@FETCH_STATUS = 0
       BEGIN
           SELECT @DTINew    = LEFT(@DTIOld, 8) +
           dbo.Convert10to36(@TempTime)+ RIGHT(@DTIOld, 9)
           UPDATE _1sjourn
                SET Date_Time_IDDOC = @DTINew
            WHERE IDDOC = @Id_doc AND IDDocDef = @Id_DocDef
           
           -- увеличим время на одну секунду(или долю секунды)
           SELECT @TempTime = @TempTime + 1 * @Multiplier

           -- выбираем след. документ
           FETCH NEXT FROM Docs
           INTO @Id_doc, @Id_DocDef, @DTIOld
           
       END
       
       CLOSE Docs
       
       -- переходим в следующий день
       SELECT @TempDate = DATEADD(DAY, 1, @TempDate)
   END
 
   DEALLOCATE Docs

END

GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO

Используемые процедурой функции(правленные процедуры, заимствованные из http://www.sinor.ru/~my1c/knowhow/SQLcnvID.html):

-- 1-я функция
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO

ALTER    FUNCTION Convert10to36
   (@Deci int )
RETURNS char(6)
AS
BEGIN
--SET NOCOUNT ON
DECLARE @j INT
declare @Res36 CHAR(9)
DECLARE @Arr36 CHAR(36)
SELECT @Arr36 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
SELECT @Res36 = ''
SELECT @j = LOG(@Deci)/LOG(36) +1
while @j>0
begin
SELECT @Res36 = LTRIM(RTRIM(@Res36)) + SUBSTRING(@Arr36, @Deci/POWER(36,@j-1) +1 ,1)
SELECT @Deci = @Deci%POWER(36,@j-1)
SELECT @j =@j-1
end
return @Res36
END

GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO

-- 2-я функция
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO

CREATE FUNCTION Convert36to10f
   (@Res36 char(9) )
RETURNS int
AS
BEGIN
--SET NOCOUNT ON
DECLARE @j INT
declare @Deci int
DECLARE @Arr36 CHAR(36)
SELECT @Arr36 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
SELECT @Deci = 0
SELECT @j = 1
while @j <= LEN(LTRIM(RTRIM(@Res36)))
begin
if @j <> 1
SELECT @Deci = @Deci*36
SELECT @Deci = @Deci + CHARINDEX(SUBSTRING(LTRIM(RTRIM(@Res36)), @j,1),@Arr36) -1
SELECT @j = @j+1
end
return @Deci
END

GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO


Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2025 | Mista.ru

Яндекс.Метрика