Помогите плиз с поиском правильного решения

mrakk

Есть процедура или скалярная функция, на входе параметр nvarchar или text примерно следующего вида : ' (id13 + 41) / id15*10 'в этой строке idXX являет с собой ссылку на ячейку заранее известного столбца в заранее известной таблице, где id=XX, которая имеет значение int. Функция должна возвращать результат формулы. (формула может быть любого вида). Помогите плиз
18 ответов

mrakk

mrakk,а как насчет заранее известной строки? Раз уж вы скалярное значение хотите.


mrakk

Не совсем понял )я хочу результат формулы в переменную типа int


mrakk

mrakk,а что у вас не получается?


mrakk

Не совсем понял )я хочу результат формулы в переменную типа int
Это здорово, но объясните - что в вашем понимании "ссылка на ячейку известного столбца".


mrakk

есть таблица :data-----------id value -----------1 102 153 144 455 19есть процедура, на входе параметр text равный '(id1 + id3) / 6'необходимо, чтобы функция поняла, что id1 = 10, id3=14 и вернула мне в итоге число 4


mrakk

mrakk,а что у вас не получается?
вот максимум что получается : declare @inn nvarchar(1000)set @inn = '10+13-3'declare @res intexec ('select '+ @inn)а если бы вместо числа было бы idXX как описано в предыдущем посте - не знаю уже что делать (((


mrakk

mrakk,делайте разбор строки, ищите ваши idXX и заменяйте их на (select value from Data where id = XX)


mrakk

а вы жестко ограничены таким представлением?его неудобно распарсиватьудобнее было бы id5# напримертогда вам надо распарсить формулу, вычленить эти id , динамически собрать запрос и подставить его в формулувы уверены что другого способа кроме как формула с id нету для решения вашей задачи?


mrakk

mrakk,делайте разбор строки, ищите ваши idXX и заменяйте их на (select value from Data where id = XX)
тогда еще вопрос - как результат exec ('select '+ @inn) положить в переменную типа int?


mrakk

а вы жестко ограничены таким представлением?его неудобно распарсиватьудобнее было бы id5# напримертогда вам надо распарсить формулу, вычленить эти id , динамически собрать запрос и подставить его в формулувы уверены что другого способа кроме как формула с id нету для решения вашей задачи?
это абсолютно непринципиально - главное как-то отделить в формуле ссылки на числа от самих чисел


mrakk

mrakk,вот такая хрень получилась
if OBJECT_ID('tempdb..#data') is not null drop table #data
create table #data (id int, value int)
insert #data
select <b>1</b>, <b>10</b> union all
select <b>2</b>, <b>15</b> union all
select <b>3</b>, <b>14</b> union all
select <b>4</b>, <b>45</b> union all
select <b>5</b>, <b>19</b>

declare @s varchar(<b>8000</b>) set @s = '(id1+id4)/6'
declare @sql varchar(<b>8000</b>)
;with cte as
(
	select s, N, patindex('%[^0-9]%', substring(s,N+<b>2</b>, <b>8000</b>)) N1 from
	(select @s s, PATINDEX('%id[0-9]%', @s) N)t
		union all
	select s, N, patindex('%[^0-9]%', substring(s,N+<b>2</b>, <b>8000</b>)) N1 from
	(
		select s, PATINDEX('%id[0-9]%', s) N from
		( select cast(SUBSTRING(s, <b>1</b>, N-<b>1</b>) + '(select value from #data where id ='
				 + substring(s, N+<b>2</b>, N1-<b>1</b>) + ')' + SUBSTRING(s,N+<b>2</b>+N1-<b>1</b>, <b>8000</b>)
				 as varchar(<b>8000</b>)) s
		 from cte
		 where N > <b>0</b>
		) t
	) t
)
select @sql = 'select ' + s from cte
where N = <b>0</b>

select @sql
declare @t table (val int)
insert @t
exec(@sql)
drop table #data
declare @res int
select @res = val from @t

select @res


mrakk

Вместо insert exec естессно можно воспользоваться sp_executesql.


mrakk

iljy, спасибо большое! именно то, что надо !


mrakk

iljy,не мог бы найти ошибку в своем коде, был очень признателен.например, при значении '(id123+1)/1*id2' дает ошибку (((


mrakk

iljy,не мог бы найти ошибку в своем коде, был очень признателен.например, при значении '(id123+1)/1*id2' дает ошибку (((
Еще один наступивший на граблиЛучше всего такие задачи решать на клиентеПотому что на сервере придется писать- либо писать парсер для разбивки выражения на атомарные действия- либо писать расширенную процедуру


mrakk

iljy,не мог бы найти ошибку в своем коде, был очень признателен.например, при значении '(id123+1)/1*id2' дает ошибку (((
вернее '(id1+1)/1*id2'


mrakk

mrakk,ошибка - потому что не учитывалась ситуация, когда переменная стоит последней
if OBJECT_ID('tempdb..#data') is not null drop table #data
create table #data (id int, value int)
insert #data
select <b>1</b>, <b>10</b> union all
select <b>2</b>, <b>15</b> union all
select <b>3</b>, <b>14</b> union all
select <b>4</b>, <b>45</b> union all
select <b>123</b>, <b>19</b>

declare @s varchar(<b>8000</b>) set @s = '(id123+1)/1*id2'
declare @sql nvarchar(<b>4000</b>)
;with cte as
(
	select s, N, patindex('%[^0-9]%', substring(s,N+<b>2</b>, <b>8000</b>)) N1 from
	(select @s s, PATINDEX('%id[0-9]%', @s) N)t
		union all
	select s, N, isnull(nullif(patindex('%[^0-9]%', substring(s,N+<b>2</b>, <b>8000</b>)),<b>0</b>), len(s) - N) N1 from
	(
		select s, PATINDEX('%id[0-9]%', s) N from
		( select cast(SUBSTRING(s, <b>1</b>, N-<b>1</b>) + '(select value from #data where id ='
				 + substring(s, N+<b>2</b>, N1-<b>1</b>) + ')' + SUBSTRING(s,N+<b>2</b>+N1-<b>1</b>, <b>8000</b>)
				 as varchar(<b>8000</b>)) s
		 from cte
		 where N > <b>0</b>
		) t
	) t
)
select @sql = N'select @res = ' + s from cte
where N = <b>0</b>

select @sql
declare @res int
exec sp_executesql @sql, N'@res int output', @res = @res output
drop table #data

select @res


mrakk

Еще один наступивший на граблиЛучше всего такие задачи решать на клиентеПотому что на сервере придется писать- либо писать парсер для разбивки выражения на атомарные действия- либо писать расширенную процедуру
почесав голову пришел к выводу, что лучше в клиенте )