Независимый форум, посвященный системе БОСС-Кадровик и всему, что с ней связано
|
|
Предыдущая тема :: Следующая тема |
Автор |
Сообщение |
zhenya17
Зарегистрирован: 04.02.2009 Сообщения: 190 Откуда: Кемерово
|
Добавлено: Вт Фев 14, 2012 07:20 Заголовок сообщения: Кавычка, взорвавшая мозг :))) |
|
|
Есть небольшая x-процедура. Весь текст приводить не буду, остановлюсь на ключевом. В процедуру передаётся несколько параметров, в том числе, переменная ldate__ - дата увольнения сотрудника. Мне нужно было добавить небольшую проверку, но не тут-то было... В процедуре поле ldate__ используется много раз и имеет некоторое значение, допустим, '2012-01-14'. Но! Экспериментальным путём удалось установить, что когда выполняется условие "IF NextDate > ldate__", то из ldate__ куда-то девается кавычка, т.е. return 2 выдаёт '2012-02-14', а return 3 - '2012-02-14. Из-за этого, естественно, последующие sql-запросы выдают ошибку.
Мой мозг взорван... Может, кто-то видит что-то криминальное в строке между ретурнами №2 и №3? Вообще не представляю, в каком направлении копать
Код: | ALIAS BegMonth == fdate__;
WHILE (BegMonth <= ldate__) THEN {
return 1: ldate__;
SELECT dateadd(day,-1,dateadd(month, 1, BegMonth)) INTO NextDate;
return 2: ldate__;
IF NextDate > ldate__ THEN LOCAL NextDate == ldate__;
return 3: ldate__;
SELECT datediff(day,BegMonth,dateadd(day,1,NextDate)) INTO MonthDays;
-- SELECT isnull(Max(d), convert(datetime,ldate__,104))
SELECT isnull(Max(d),'1900-01-01')
Into EndMonth
From (Select Top MonthDays d from #LS_CALEND where d >= BegMonth order by d) as cal;
if EndMonth = '1900-01-01' then alias EndMonth == ldate__;
-- Корректировка дней MonthDays на неявки
SELECT Count(*)
Into MonthDays
From (Select Top MonthDays d from #LS_CALEND where d >= BegMonth order by d) as cal;
--return BegMonth,EndMonth,MonthDays, fdate__, ldate__;
SELECT
(CASE WHEN FROMD < BegMonth THEN BegMonth ELSE FROMD END),
(CASE WHEN TOD > EndMonth THEN EndMonth ELSE TOD END),
CAST(STRING AS INTEGER)
INTO PrivilegeBegin, PrivilegeEnd, PrivilegeValue
FROM PR_GROUP_VALUE
WHERE ID_GROUP = IdGroup AND ID_REF = AutoCard AND FROMD <= EndMonth AND TOD >= BegMonth;
SELECT COUNT(*)
INTO PrivilegeDay
From (Select Top MonthDays d from #LS_CALEND where d >= PrivilegeBegin and d <= PrivilegeEnd order by d) as cal;
Let LeaveDaysMonth = 0.00;
IF comp_out_flg_ = 1 THEN {
IF MonthDays > 15 THEN {
IF PrivilegeDay > 15 THEN Let LeaveDaysMonth = Round(PrivilegeValue*1.00/12,2)
ELSE Let LeaveDaysMonth = Round(LeaveDaysConst*1.00/12,2);
Let LeaveDays = LeaveDays + LeaveDaysMonth;
};
}
ELSE {
IF PrivilegeDay > 15 THEN Let LeaveDaysMonth = Round(PrivilegeValue*1.00/12,2)
ELSE Let LeaveDaysMonth = Round(LeaveDaysConst*1.00/12,2);
Let LeaveDays = LeaveDays + LeaveDaysMonth;
};
--> $LS Excel
IF ShowExcel = 1 THEN {
Let Absence = datediff(day,BegMonth,EndMonth)-MonthDays+1;
Excel.Cells(Row, 1).Value = MonthCount;
Excel.Cells(Row, 2).Value = BegMonth;
Excel.Cells(Row, 3).Value = EndMonth;
Excel.Cells(Row, 4).Value = MonthDays;
IF Absence > 0 THEN Excel.Cells(Row, 5).Value = Absence;
IF PrivilegeDay > 0 THEN Excel.Cells(Row, 6).Value = PrivilegeDay;
IF PrivilegeValue > 0 THEN Excel.Cells(Row, 7).Value = PrivilegeValue;
IF LeaveDaysMonth > 0 THEN Excel.Cells(Row, 8).Value = LeaveDaysMonth;
Let MonthCount = MonthCount + 1;
Let Row = Row + 1;
};
--< $LS Excel
SELECT dateadd(day, 1, EndMonth) INTO BegMonth;
return 4: ldate__;
}; --WHILE
|
|
|
Вернуться к началу |
|
 |
vladimir22
Зарегистрирован: 14.01.2010 Сообщения: 21
|
Добавлено: Вт Фев 14, 2012 14:41 Заголовок сообщения: |
|
|
Не, мозг взорван раньше.
Это последствия
А какой смысл Вы вкладываете в оператор:
IF NextDate > ldate__ THEN LOCAL NextDate == ldate__;
Причем как в слово "LOCAL" в даном контексте, так и в оператор "==" ? |
|
Вернуться к началу |
|
 |
RVV Большой шоколадный орден

Зарегистрирован: 14.01.2010 Сообщения: 449
|
Добавлено: Вт Фев 14, 2012 15:58 Заголовок сообщения: |
|
|
А я всегда думал, что присвоение в операторе ALIAS пишется через :=
а не так
ALIAS BegMonth == fdate__;
чудо, что этот код вообще работает ... |
|
Вернуться к началу |
|
 |
Mike Большой шоколадный орден

Зарегистрирован: 07.04.2011 Сообщения: 255
|
Добавлено: Вт Фев 14, 2012 17:13 Заголовок сообщения: |
|
|
RVV писал(а): | А я всегда думал, что присвоение в операторе ALIAS пишется через :=
а не так
ALIAS BegMonth == fdate__;
чудо, что этот код вообще работает ... |
еще "=" можно =) |
|
Вернуться к началу |
|
 |
zhenya17
Зарегистрирован: 04.02.2009 Сообщения: 190 Откуда: Кемерово
|
Добавлено: Ср Фев 15, 2012 07:44 Заголовок сообщения: |
|
|
Что касается чудо-строчки IF NextDate > ldate__ THEN LOCAL NextDate == ldate__;, то я в неё никакой смысл не вкладывала, т.к. изначально код не мой. Но понятно, что эту строчку я рассматривала очень пристально
На самом деле, в зависимости от того, стоит в ней "Local", "Let", "Alias" или просто приравнивание, а также в зависимости от знаков "=", "==" или ":=" в NextDate тоже то появляется, то исчезает кавычка, либо выдаётся программная ошибка ))
В том-то и дело, что я не могу найти какой-то логической зависимости... Могу только привести полный код процедуры
Код: | (pId__, fdate__, ldate__, comp_out_flg_ = 0, ShowExcel = 0);
LOCAL LeaveDays = 0.00;
IF OBJECT_ID('TEMPDB..#LS_CALEND') IS NOT NULL THEN DROP TABLE #LS_CALEND;
$SELECT CALEND.D INTO #LS_CALEND FROM (SELECT D FROM Z_CALEND GROUP BY D) AS CALEND
WHERE CALEND.D BETWEEN fdate__[''] AND ldate__[''];
SELECT SUM(DATEDIFF(DAY,(CASE WHEN FROMD < fdate__[''] THEN fdate__[''] ELSE FROMD END),(CASE WHEN TOD > ldate__[''] THEN ldate__[''] ELSE TOD END)) + 1)
INTO AdmDays
FROM PR_LEAVE
WHERE OPERAT = 5 AND PID = pId__ AND FROMD <= ldate__[''] AND TOD >= fdate__[''];
IF AdmDays > 14 THEN
DELETE #LS_CALEND
FROM #LS_CALEND, PR_LEAVE
WHERE #LS_CALEND.D BETWEEN PR_LEAVE.FROMD AND PR_LEAVE.TOD
AND PR_LEAVE.OPERAT IN (3, 5, 7)
AND PR_LEAVE.PID = pId__
AND PR_LEAVE.TOD >= fdate__['']
ELSE
DELETE #LS_CALEND
FROM #LS_CALEND, PR_LEAVE
WHERE #LS_CALEND.D BETWEEN PR_LEAVE.FROMD AND PR_LEAVE.TOD
AND PR_LEAVE.OPERAT IN (3, 7)
AND PR_LEAVE.PID = pId__
AND PR_LEAVE.TOD >= fdate__[''];
DELETE #LS_CALEND
FROM #LS_CALEND, PR_WALK, TYP_ABSENCE
WHERE #LS_CALEND.D BETWEEN PR_WALK.FROMD AND PR_WALK.TOD
AND TYP_ABSENCE.CODE_ABSENCE = PR_WALK.CODE_ABSENCE
AND TYP_ABSENCE.SWITCH_ON = 1
AND PR_WALK.PID = pId__
AND PR_WALK.TOD >= fdate__[''];
SELECT COUNT(*) FROM #LS_CALEND INTO PerDays;
IF ExistsPrivilege = 0 AND comp_out_flg_ = 0 THEN {
Let LeaveDays = LeaveDaysConst;
--> $LS Excel
IF ShowExcel = 1 THEN {
Let Absence = datediff(day,fdate__,ldate__)-PerDays+1;
Excel.Cells(Row, 1).Value = 1;
Excel.Cells(Row, 2).Value = fdate__;
Excel.Cells(Row, 3).Value = ldate__;
Excel.Cells(Row, 4).Value = PerDays;
Excel.Cells(Row, 5).Value = Absence;
Excel.Cells(Row, 8).Value = LeaveDays;
Let Row = Row + 1;
};
--< $LS Excel
}
ELSE {
IF ExistsAllPeriod = 1 AND comp_out_flg_ = 0 THEN {
SELECT TOP 1 CAST(STRING AS INTEGER) INTO LeaveDays FROM PR_GROUP_VALUE
WHERE ID_GROUP = IdGroup AND ID_REF = AutoCard AND FROMD <= ldate__ AND TOD >= fdate__;
--> $LS Excel
IF ShowExcel = 1 THEN {
Let Absence = datediff(day,fdate__,ldate__)-PerDays+1;
Excel.Cells(Row, 1).Value = 1;
Excel.Cells(Row, 2).Value = fdate__;
Excel.Cells(Row, 3).Value = ldate__;
Excel.Cells(Row, 4).Value = PerDays;
Excel.Cells(Row, 5).Value = Absence;
Excel.Cells(Row, 6).Value = PerDays;
Excel.Cells(Row, 7).Value = LeaveDays;
Excel.Cells(Row, 8).Value = LeaveDays;
Let Row = Row + 1;
};
--< $LS Excel
}
ELSE {
ALIAS BegMonth == fdate__;
WHILE (BegMonth <= ldate__) THEN {
return 1: ldate__;
SELECT dateadd(day,-1,dateadd(month, 1, BegMonth)) INTO NextDate;
return 2: ldate__, NextDate;
-- IF NextDate > ldate__ THEN LOCAL NextDate == ldate__;
IF NextDate > ldate__ THEN ALIAS NextDate == ldate__;
return 3: ldate__, NextDate;
SELECT datediff(day,BegMonth,dateadd(day,1,NextDate)) INTO MonthDays;
-- SELECT isnull(Max(d), convert(datetime,ldate__,104))
SELECT isnull(Max(d),'1900-01-01')
Into EndMonth
From (Select Top MonthDays d from #LS_CALEND where d >= BegMonth order by d) as cal;
if EndMonth = '1900-01-01' then alias EndMonth == ldate__;
-- Корректировка дней MonthDays на неявки
SELECT Count(*)
Into MonthDays
From (Select Top MonthDays d from #LS_CALEND where d >= BegMonth order by d) as cal;
--return BegMonth,EndMonth,MonthDays, fdate__, ldate__;
SELECT
(CASE WHEN FROMD < BegMonth THEN BegMonth ELSE FROMD END),
(CASE WHEN TOD > EndMonth THEN EndMonth ELSE TOD END),
CAST(STRING AS INTEGER)
INTO PrivilegeBegin, PrivilegeEnd, PrivilegeValue
FROM PR_GROUP_VALUE
WHERE ID_GROUP = IdGroup AND ID_REF = AutoCard AND FROMD <= EndMonth AND TOD >= BegMonth;
SELECT COUNT(*)
INTO PrivilegeDay
From (Select Top MonthDays d from #LS_CALEND where d >= PrivilegeBegin and d <= PrivilegeEnd order by d) as cal;
Let LeaveDaysMonth = 0.00;
IF comp_out_flg_ = 1 THEN {
IF MonthDays > 15 THEN {
IF PrivilegeDay > 15 THEN Let LeaveDaysMonth = Round(PrivilegeValue*1.00/12,2)
ELSE Let LeaveDaysMonth = Round(LeaveDaysConst*1.00/12,2);
Let LeaveDays = LeaveDays + LeaveDaysMonth;
};
}
ELSE {
IF PrivilegeDay > 15 THEN Let LeaveDaysMonth = Round(PrivilegeValue*1.00/12,2)
ELSE Let LeaveDaysMonth = Round(LeaveDaysConst*1.00/12,2);
Let LeaveDays = LeaveDays + LeaveDaysMonth;
};
--> $LS Excel
IF ShowExcel = 1 THEN {
Let Absence = datediff(day,BegMonth,EndMonth)-MonthDays+1;
Excel.Cells(Row, 1).Value = MonthCount;
Excel.Cells(Row, 2).Value = BegMonth;
Excel.Cells(Row, 3).Value = EndMonth;
Excel.Cells(Row, 4).Value = MonthDays;
IF Absence > 0 THEN Excel.Cells(Row, 5).Value = Absence;
IF PrivilegeDay > 0 THEN Excel.Cells(Row, 6).Value = PrivilegeDay;
IF PrivilegeValue > 0 THEN Excel.Cells(Row, 7).Value = PrivilegeValue;
IF LeaveDaysMonth > 0 THEN Excel.Cells(Row, 8).Value = LeaveDaysMonth;
Let MonthCount = MonthCount + 1;
Let Row = Row + 1;
};
--< $LS Excel
SELECT dateadd(day, 1, EndMonth) INTO BegMonth;
return 4: ldate__;
}; --WHILE
); --ELSE {
}; --ELSE {
};
break LeaveDays; |
Процедура служит для расчёта дней коменсации при увольнении. Точнее, у нас сделана удобная Excel-форма, в которую выводится детализация расчёта, чтобы можно было понять, откуда взялось количество дней. Процедура была написана в 2007г. и работает стабильно кроме одного случая: глюк возникает, если у человека есть отпуск без сохранения з/п в день увольнения.
Например, товарищ взял отпуск без сохранения з/п с 1 по 5.02.2012г. и 5.02.2012г. увольняется. В этом случае при расчёте компенсации вылезет ошибка. Просто до этого кадровиков просили, чтобы они делали отпуск на 1 день покороче, а в табеле вручную проставляли код "ДО"в последний рабочий день. Но это же неудобно, хочется довести до ума...
У меня есть ещё мысли, с какой стороны зайти. Но просто про эту кавычку всё равно интересно, т.к. не могу понять, что к чему  |
|
Вернуться к началу |
|
 |
vladimir22
Зарегистрирован: 14.01.2010 Сообщения: 21
|
Добавлено: Ср Фев 15, 2012 13:54 Заголовок сообщения: |
|
|
Доргая zhenya17 !
Не имеет абсолютно никакого значения что делает процедура
Просто строка, на которую Вам указали в начале поста и которая вызывает ошибку - это БРЕД.
Поэтому и быз задан вопрос - каков смысл этой строки, что собственно она должна делать ?
Чтобы было понятно что подсказать как ее переписать.
Было написано:
IF NextDate > ldate__ THEN LOCAL NextDate == ldate__;
сейчас Вы переписали на:
IF NextDate > ldate__ THEN ALIAS NextDate == ldate__;
Но, понимаете ли, это что в лоб, что полбу.
Опять не попали
Поясню свое впечателение от этой строки.
Во-первых, знак "==" - это логическое сравнение.
Что он должен делать в случае объявления новой переменной (что по ALIAS что по LOCAL) ?
Во-вторых, У Вас объявляется новая переменная NextDate. А как она соотносится с переменной с тем же именем в операторе сравнения слева ? Тем более что время жизни такой переменной в случае LOCAL вообще ограничено текущим блоком (от оператора THEN до конца строки) ?
Может должно быть написано что-то типа:
IF NextDate[''] > ldate__[''] THEN Let NextDate = ldate__[''];
??????????? |
|
Вернуться к началу |
|
 |
zhenya17
Зарегистрирован: 04.02.2009 Сообщения: 190 Откуда: Кемерово
|
Добавлено: Чт Фев 16, 2012 11:11 Заголовок сообщения: |
|
|
vladimir22, спасибо, что не оставляете меня без надежды на спасение
vladimir22 писал(а): | Просто строка, на которую Вам указали в начале поста и которая вызывает ошибку - это БРЕД.
Поэтому и быз задан вопрос - каков смысл этой строки, что собственно она должна делать ?
Чтобы было понятно что подсказать как ее переписать. | По моей логике, с точки зрения программирования, эта строка тоже кажется бредовой. Хотя бы уже потому, что перед ней идёт Select, который запихивает значение в эту переменную, поэтому назначение Local мне непонятно. Я разобралась в логичекой части алгоритма и понимаю, что делается в процедуре и в этой строке, но я не знаю, о чём думал человек, написавший "Local". В частности, из-за этого я и начала экспериментировать с этой строкой.
vladimir22 писал(а): | Было написано:
IF NextDate > ldate__ THEN LOCAL NextDate == ldate__;
сейчас Вы переписали на:
IF NextDate > ldate__ THEN ALIAS NextDate == ldate__;
Но, понимаете ли, это что в лоб, что полбу.
Опять не попали
| Не совсем так. Я понимаю, что в данном случае что алиас, что локал должно быть "что в лоб, что по лбу". Поэтому я не написала алиас, я просто пробовала различные варианты: с local, с alias, с Let и просто без ключевого слова, в том числе, меняла и знаки присвоения. К сожалению, у меня нет в голове чёткой картинки, что если написать так-то, то проблема будет решена. есть лишь то, что описано в руководстве по "БОСС-Дизайнеру".
vladimir22 писал(а): | Может должно быть написано что-то типа:
IF NextDate[''] > ldate__[''] THEN Let NextDate = ldate__[''];
??????????? | Вариант с кавычками я тоже пробовала В частности, предложенный Вами вариант возвращает в ретурне№3 дату ldate__ с кавычками, а NextDate - без кавычек, поэтому злополучную строку мы проходим, а дальше рубимся на следующей же строке - sql-запросе, т.к. он получается следующего содержания: Код: | SELECT isnull(Max(d),'1900-01-01') From (Select Top -38932 d from #LS_CALEND where d >= '2012-01-24' order by d) as cal |
Если попробовать более логичную, на мой взгляд, конструкцию IF NextDate[''] > ldate__[''] THEN Let NextDate[''] = ldate__[''], то мы проходим и нашу злополучную строку, и последующий sql-запрос, но потом опять рубимся на кавычке, но уже в другом месте. И так какой-то замкнутый круг...
Согласна с RVV в одном: RVV писал(а): | чудо, что этот код вообще работает ... |
А хочется сделать так, чтобы это было не чудом, а закономерностью! Но победить эти 137 строчек кода пока что получается 
Последний раз редактировалось: zhenya17 (Чт Фев 16, 2012 11:14), всего редактировалось 1 раз |
|
Вернуться к началу |
|
 |
vladimir22
Зарегистрирован: 14.01.2010 Сообщения: 21
|
Добавлено: Чт Фев 16, 2012 11:11 Заголовок сообщения: |
|
|
Хотя, прощу прощения, страшие товарищи меня переубедили, что так писать можно и даже как-то должно работать.
Имеется в виду:
IF NextDate > ldate__ THEN ALIAS NextDate == ldate__;
а вот с вариантом:
IF NextDate > ldate__ THEN LOCAL NextDate == ldate__;
поосторожнее.
Таам как минимум создается вторая переменная NextDate.
Вы именно этого хотели в первоначальном варианет алгоритма ?
Только не понятно зачем так вообще писать.
См. предложенный вариант с Let.
Если заменить на него ошибка остается ? |
|
Вернуться к началу |
|
 |
zhenya17
Зарегистрирован: 04.02.2009 Сообщения: 190 Откуда: Кемерово
|
Добавлено: Чт Фев 16, 2012 11:18 Заголовок сообщения: |
|
|
Про вариант с Let написала выше. Мы писали сообщения почти одновременно, воможно, Вы не видели предыдущего поста. |
|
Вернуться к началу |
|
 |
zhenya17
Зарегистрирован: 04.02.2009 Сообщения: 190 Откуда: Кемерово
|
Добавлено: Чт Фев 16, 2012 11:21 Заголовок сообщения: |
|
|
Кстати, самое фиговое, что я победила этот код 26.01.2012г, о чём сделала пометку в списке своих задач. Но поскольку сейчас идут всякие активные разработки, то, походу, забыла перенести изменения с тестовой на реальную базу. А второй раз на меня озарение никак не находит  |
|
Вернуться к началу |
|
 |
vladimir22
Зарегистрирован: 14.01.2010 Сообщения: 21
|
Добавлено: Чт Фев 16, 2012 15:12 Заголовок сообщения: |
|
|
Тогда надо смотрть по трассировку.
Поскольку функция написана так, что ее работа зависит не только о явно передаваемых параметров, но и от переменных, созданных где-то снаружи то только по ее тексту сказать что не так может оказаться невозможно.
Но в любом случае - трассирова Вам в руки.
Если предложенный мною запрос возвращает NextDate без кавычек - то действительно либо надо все тело функции переписать так, чтобы датные переменные на зависели от наличия или отсутствия кавычек - т.е. с маской [''].
Или в моем примере дописать AS DATE:
IF NextDate[''] > ldate__[''] THEN Let NextDate = ldate__[''] AS DATE;
Тогда тип переменной NextDate останется "date" и на везде сразу будет подставляться с кавычками. |
|
Вернуться к началу |
|
 |
|
|
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете голосовать в опросах
|
|