Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Возвращение из пользовательской функции значения по наростающей в Update запрос / 21 сообщений из 21, страница 1 из 1
28.02.2019, 17:28
    #39780542
Возвращение из пользовательской функции значения по наростающей в Update запрос
Объясните пожалуйста в чем затруднение, или подскажите если не трудно другой способ решения задачи:

В поле таблицы необходимо проставить код с контрольной суммой вычисляемой по определенному алгоритму на основании порядкового номера.

Поскольку в колонке изначально значения нет, то порядковый номер беру(возможно ошибочно) из суммы пустых полей этой таблицы:
Код: sql
1.
2.
3.
4.
SELECT count(*)
FROM  table1 t1
where t1.DATEGEN = @date_akt -- месячная выборка
and t1.cod <> 0



Результат этого запроса инкриминирую и помещаю в пользовательскую функцию вместе с алгоритмом расчета:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
CREATE FUNCTION get_cod(@head char(8), @date_akt date) -- кроме даты константа для расчета
	RETURNS char(14)
	BEGIN
		declare @used_cod int;
		declare @used_cod_char char(5);
		declare @core char(13);
                ....
		declare @result char(14);
		SET @used_cod = (SELECT count(*) -- место, где считаю сколько уже занесено кодов
			FROM  table1 t1
			where t1.DATEGEN = @date_akt
			and t1.cod <> 0)
		SET @used_cod = @used_cod +1 -- получаю след.номер
		SET @used_cod_char= STUFF('00000',6-(len(@used_cod)),len(@used_cod),RTRIM(LTRIM(CAST(@used_cod AS char))));	-- это маска для №3 будет например 00003
		SET @core= @head + @used_cod_char --- продолжаю собирать контрольную сумму
		SET @noteven = (select CAST(left(@core,1) AS int)
			+ CAST(SUBSTRING(@core,3,1) AS int)
                 .....   --- тело формулы по условию, всякие расчеты по чет/не чет и т.д. 
		SET @result = @core + CAST(@remainder AS char(1)) -- конец вычисления контрольного числа, тоже к теме не имеет отношения
		RETURN @result
END



Прогнав на select-е при пустой колонке cod и при полностью заполненной доп. запросом убеждаюсь что контрольная сумма 1-го и последних чисел верна. Вроде-бы функция написана верно.

Теперь запускаю запрос на заполнение:

Код: sql
1.
2.
3.
4.
Update t1 set t1.cod = dbo.get_cod('77720190228',@dategen)
FROM   dbo.person p
INNER JOIN table1 t1 on (t1.acc = p.c_acc)	 
where p.n_district=2 and t1.DATEGEN = @dategen --  в реальной таблице связей больше, но к теме это не имеет отношения ets.



Запрос отрабатывает на ожидаемом кол-ве строк, но выдает в колонке cod только 1-ю контрольную сумму на всей выборке.
Почему? не сработало!
Подсознательно понимаю... что транзакция update запроса не завершилась до конца все выборки и в поле cod пусто, и функция выгребая кол-во заполненных полей не получает постепенное нарастание т.к. запрос вызвавший ее еще на отработал. Наверно это
самое простое объяснение, но мне как быть, был бы это PHP поставил бы глобальную переменную и черпал бы из нее нарастающую величину. А тут как быть...

Обернул запрос в пару BEGIN TRANSACTION - WAITFOR DELAY '00:00:01.00' -COMMIT TRAN но это ожидаемо не помогло.

Помогите пожалуйста советом малопрактикующему sql-програмисту.
...
Рейтинг: 0 / 0
28.02.2019, 18:02
    #39780559
TaPaK
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
Сергей Прокопенко 8,

Через cross apply вызови, а так бред чистой воды
...
Рейтинг: 0 / 0
28.02.2019, 18:28
    #39780575
court
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
TaPaKСергей Прокопенко 8,

Через cross apply вызови, а так бред чистой водыне поможет

ТС, хочет видеть при каждом "следующем" вызове функции в Update , к-во "обновившихся" записей в этом же Update !
Вообщем, там "проце-дурный" подход в самом кондовом его виде :)

ТС,

Будет что-то типа этого
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
;with cte as (
  SELECT 
    t1.*
    ,used_cod = sum(case when t1.cod <> 0 then 1 else 0 end)over()
    ,curr_cod_add = row_number()over(order by case when t1.cod <> 0 then 1 else 0 end)
  FROM   dbo.person p
  INNER JOIN table1 t1 on (t1.acc = p.c_acc)	 
  where p.n_district=2 and t1.DATEGEN = @dategen
)
update cte
set = /* вот тут должна быть вся та "вакханалия", которую ты делаешь в функции. Твой @used_cod (из функции) для каждой записи будет равен used_cod+curr_cod_add */
where t1.cod = 0


Выполни запрос из cte отдельно и посмотри результат, - думаю поймешь идею ...
...
Рейтинг: 0 / 0
28.02.2019, 18:32
    #39780576
court
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
fix
court
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
;with cte as (
  SELECT 
    t1.*
    ,used_cod = sum(case when t1.cod <> 0 then 1 else 0 end)over()
    ,curr_cod_add = row_number()over(order by case when t1.cod <> 0 then 1 else 0 end)
  FROM   dbo.person p
  INNER JOIN table1 t1 on (t1.acc = p.c_acc)	 
  where p.n_district=2 and t1.DATEGEN = @dategen
)
update cte
set cte.cod = /* вот тут должна быть вся та "вакханалия", которую ты делаешь в функции. Твой @used_cod (из функции) для каждой записи будет равен used_cod+curr_cod_add */
where cte.cod = 0
...
Рейтинг: 0 / 0
28.02.2019, 20:48
    #39780628
Возвращение из пользовательской функции значения по наростающей в Update запрос
Спасибо court за помощь.
Я нарушил правило: не брать данные в функции из вне, кроме, как только из параметров функции.
1 шаг, создаю доп.поле cod1
2. обновляю его номером строки через over()
3. update таблицы той же функцией но уже с 3-мя параметрами, где новый - наращенный cod
4. подтираю - удаляю столбец сod1

Хотя можно и через CTE-красивее

Спасибо.
...
Рейтинг: 0 / 0
28.02.2019, 21:06
    #39780635
TaPaK
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
Сергей Прокопенко 8,
авторЯ нарушил правило: не брать данные в функции из вне, кроме, как только из параметров функции.

2 Правило бойцовского клуба?
...
Рейтинг: 0 / 0
28.02.2019, 21:19
    #39780642
invm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
Сергей Прокопенко 8Я нарушил правило: не брать данные в функции из вне, кроме, как только из параметров функции.Вы в своем update всего-то нарвались на Halloween Problem.
...
Рейтинг: 0 / 0
28.02.2019, 21:22
    #39780646
TaPaK
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
invmСергей Прокопенко 8Я нарушил правило: не брать данные в функции из вне, кроме, как только из параметров функции.Вы в своем update всего-то нарвались на Halloween Problem.
нет
...
Рейтинг: 0 / 0
28.02.2019, 21:30
    #39780649
invm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
TaPaKнетПлан запросите у ТС'а.
...
Рейтинг: 0 / 0
28.02.2019, 21:31
    #39780650
TaPaK
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
invmTaPaKнетПлан запросите у ТС'а.
авторSET @used_cod = (SELECT count(*) -- место, где считаю сколько уже занесено кодов
FROM table1 t1
where t1.DATEGEN = @date_akt
and t1.cod <> 0)
это явно не оттуда
...
Рейтинг: 0 / 0
01.03.2019, 10:24
    #39780806
invm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
TaPaK,

https://sqlperformance.com/2013/02/sql-plan/halloween-problem-part-4
Раздел "SCHEMABINDING and T-SQL Scalar Functions"
...
Рейтинг: 0 / 0
01.03.2019, 10:40
    #39780819
TaPaK
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
invm,
вот план его запроса, разве Eager Spool не есть "та защита" от Halloween ?

...
Рейтинг: 0 / 0
01.03.2019, 10:55
    #39780828
Руслан Дамирович
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
TaPaKinvm,
вот план его запроса, разве Eager Spool не есть "та защита" от Halloween ?


Так там в конце как раз и рассказано, что использование не SCHEMABOUND функции, заставляет предполагать оптимизатор в необходимости защиты, а не сам факт ее необходимости.
...
Рейтинг: 0 / 0
01.03.2019, 10:57
    #39780829
TaPaK
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
Руслан ДамировичTaPaKinvm,
вот план его запроса, разве Eager Spool не есть "та защита" от Halloween ?


Так там в конце как раз и рассказано, что использование не SCHEMABOUND функции, заставляет предполагать оптимизатор в необходимости защиты, а не сам факт ее необходимости.
и?
...
Рейтинг: 0 / 0
01.03.2019, 11:02
    #39780833
TaPaK
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
Руслан Дамирович,

точнее если читать не только поперёк, а ещё и вдоль (как крокодила), то вся суть сводится к
автор Unless a scalar function is declared with the SCHEMABINDING option, SQL Server assumes the function accesses tables.
а тут хоть вдоль хоть поперёк обращение к таблице есть. Что соответчсеввно с доблаением даже SCHEMABINDING в планах ничего не меняет
...
Рейтинг: 0 / 0
01.03.2019, 11:31
    #39780847
invm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
TaPaK,

Лично я считаю, что дело в детерминированности, а не в SCHEMABINDING.
В недетерминированной скалярной функции потенциально возможен доступ к данным, поэтому в план добавляется halloween protection.
...
Рейтинг: 0 / 0
01.03.2019, 11:32
    #39780849
TaPaK
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
invmTaPaK,

Лично я считаю, что дело в детерминированности, а не в SCHEMABINDING.
В недетерминированной скалярной функции потенциально возможен доступ к данным, поэтому в план добавляется halloween protection.
так проблема не в Halloween Problem?
...
Рейтинг: 0 / 0
01.03.2019, 11:42
    #39780869
invm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
TaPaKтак проблема не в Halloween Problem?Решили попридираться к словам?
Ок, дело в защите от Halloween Problem.
...
Рейтинг: 0 / 0
01.03.2019, 17:07
    #39781138
Руслан Дамирович
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
court...
Тогда уж так как-то:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
CREATE FUNCTION get_cod( @head CHAR(8), @used_code INT )
RETURNS CHAR(20)
WITH SCHEMABINDING
	BEGIN
		DECLARE
      @char CHAR(12),
		  @core CHAR(20),
      ....
		  @result char(20)
    ;
		SET @char = RIGHT( REPLICATE( '0', 11 ) + CONVERT( VARCHAR(12), @used_code ), 11 );	-- это маска для №3 будет например 00003
		SET @core= @head + @char --- продолжаю собирать контрольную сумму
		SET @noteven = (select CAST(left(@core,1) AS int)
			+ CAST(SUBSTRING(@core,3,1) AS int)
                 .....   --- тело формулы по условию, всякие расчеты по чет/не чет и т.д. 
		SET @result = @core + CAST( @remainder AS char(1) ) -- конец вычисления контрольного числа, тоже к теме не имеет отношения
		RETURN @result
END
;
DECLARE @dategen DATE = GETDATE()
;
WITH 
cte as (
  SELECT 
    t1.[cod],
    [used_code] = row_number()over(order by case when t1.cod = 0 then 1 else 0 end)
  FROM
    dbo.person p
    INNER JOIN table1 t1 on (t1.acc = p.c_acc)	 
  WHERE
    p.n_district=2 and t1.DATEGEN = @dategen
)
UPDATE 
  cte
SET 
  cod = get_cod( '77720190228',[used_code] )
WHERE 
  cod = 0
;


...
Рейтинг: 0 / 0
01.03.2019, 18:58
    #39781207
Владислав Колосов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Возвращение из пользовательской функции значения по наростающей в Update запрос
Подозреваю, что автор хотел на самом деле вот это сделать:

Код: sql
1.
2.
declare @val int = 0
update tbl set @val = @val + 1, fn_some_calculation(@val, tbl.field1, tbl.field2)
...
Рейтинг: 0 / 0
02.03.2019, 22:01
    #39781412
Возвращение из пользовательской функции значения по наростающей в Update запрос
Все гениальное просто:

Владислав КолосовПодозреваю, что автор хотел на самом деле вот это сделать:

Код: sql
1.
2.
declare @val int = 0
update tbl set @val = @val + 1, fn_some_calculation(@val, tbl.field1, tbl.field2)


Спасибо, Владислав Колосов

У CTE есть 1н большой минус, коллеги замещающие тебя во время больничного или отпуска решительно не приемлют такую форму записи и норовят впихнуть пароль от TeamViewer-ра.
...
Рейтинг: 0 / 0
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Возвращение из пользовательской функции значения по наростающей в Update запрос / 21 сообщений из 21, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]