powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Алгебраическое выражение
18 сообщений из 18, страница 1 из 1
Алгебраическое выражение
    #39968462
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Добрый день!

Есть замечательный сайт, где можно ввести любое алгебраическое выражение и программа может раскрыть скобки или наоборот вынести общий множитель за скобки . Т.е. вводим, к примеру, вот такую строку для раскрытия скобки:
(a^2 + 3*a*b + 4*b^2)*(-2*a^2 + 14*b^2)
и получаем следующую строку:
- 2•a4 - 6•a3•b + 6•a2•b2 + 42•a•b3 + 56•b4

Программа работает просто отлично, но есть одно маленькое ограничение: алгебраическое выражение не должно превышать 256 символов, а мне этого не достаточно. Я часто имею дело с выражениями более 1000 символов, поэтому хочу создать хранимую процедуру в SQL Server’е (здесь вместо массива можно использовать табличную переменную, которую можно и фильтровать, и сортировать, в общем очень и очень даже удобный инструмент).
Что я пробовал?
Пока что начал с простейшего примера. Выражения с "+" или "–" без скобок беру и обрабатываю вот таким образом.
Код: 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.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
CREATE PROCEDURE [dbo].[p_AlgebraicExpression]
(@Expression AS Varchar(MAX))
AS BEGIN
    SET NOCOUNT ON;

    -- Убираем пробелы, а также заменяем запятые на точку.
    SET @Expression = REPLACE(REPLACE(REPLACE(REPLACE(@Expression,
        ' ', ''), ',', '.'), CHAR(13), ''), CHAR(10), '');

    IF @Expression Is Null OR @Expression = ''
    GOTO TheEnd;

    DECLARE @MainTable AS TABLE (ID Int Identity Primary Key,
        Coef Float, MemberExpression Varchar(100), Operator Char(1), Remark Varchar(10));
    DECLARE @ABC AS TABLE (ID Int, Letter Varchar(5), Degree Float, Remark Varchar(10));
    DECLARE @Result AS Varchar(MAX), @Exp Varchar(MAX), @Coef Varchar(100) = '', @i Int;

    SET @Exp = REPLACE(REPLACE(REPLACE(REPLACE(@Expression, '+', '!'), '-', '!'), '(', '!'), ')', '!');
    SET @i = CASE WHEN LEFT(@Exp, 1) = '!' THEN 1 ELSE 0 END;

    WHILE LEN(@Expression) > @i AND @i Is Not Null
    BEGIN
        INSERT @MainTable (MemberExpression, Operator)
        SELECT
            CASE WHEN CHARINDEX('!', @Exp, @i+1) = 0
                 THEN SUBSTRING(@Exp, @i+1, LEN(@Exp))
                 ELSE SUBSTRING(@Exp, @i+1, CHARINDEX('!', @Exp, @i+1)-@i-1) END,
            CASE WHEN @i = 0 THEN '+' ELSE SUBSTRING(@Expression, @i, 1) END;

        SET @i = CHARINDEX('!',  @Exp, @i+1);
        IF @i = 0
        SET @i = Null;
    END;

    -- SELECT * FROM @MainTable;

    UPDATE @MainTable
    SET Coef = CASE WHEN Operator = '-' THEN '-' ELSE '' END +
        CASE
            WHEN IsNumeric(MemberExpression) = 1 THEN MemberExpression
            WHEN MemberExpression LIKE '[A-z]%' THEN '1'
            WHEN MemberExpression LIKE '%*%'
                THEN LEFT(MemberExpression, PATINDEX('%*%', MemberExpression)-1)
            WHEN MemberExpression LIKE '%[A-z]%'
                THEN LEFT(MemberExpression, PATINDEX('%[A-z]%', MemberExpression)-1) END;

    UPDATE @MainTable
    SET MemberExpression = CASE
        WHEN MemberExpression NOT LIKE '%[A-z]%' THEN ''
        WHEN MemberExpression LIKE '[0-9]%' THEN SUBSTRING(MemberExpression,
            PATINDEX('%[A-z]%', MemberExpression), LEN(MemberExpression))
        ELSE MemberExpression END;

    -- Проверка
    -- SELECT * FROM @MainTable;

    INSERT INTO @ABC(ID, Letter, Degree)
    SELECT M.ID,
           CASE WHEN S.Items NOT LIKE '%^%' THEN S.Items
                ELSE LEFT(S.Items, CHARINDEX('^', S.Items) - 1) END Letter,
           CASE WHEN S.Items NOT LIKE '%^%' THEN 1
                ELSE SUBSTRING(S.Items, CHARINDEX('^', S.Items) + 1, 20) END Degree
    FROM @MainTable M CROSS APPLY dbo.Split(M.MemberExpression, '*') S
    WHERE M.MemberExpression LIKE '%[A-z]%';

    UPDATE @MainTable
    SET MemberExpression = STUFF((SELECT '*' + A.Letter + CASE WHEN SUM(A.Degree) = 1 THEN ''
                                        ELSE '^' + CAST(SUM(A.Degree) AS Varchar(MAX)) END
                                  FROM @ABC A
                                  WHERE A.ID = M.ID
                                  GROUP BY A.Letter
                                  ORDER BY A.Letter FOR XML PATH('')), 1, 1, '')
    FROM @MainTable M
    WHERE MemberExpression LIKE '%[A-z]%';

    -- Проверка
    -- SELECT * FROM @MainTable;

    WITH
    A AS (SELECT ISNULL(MemberExpression, '') MemberExpression, SUM(Coef) Coef
            FROM @MainTable
            GROUP BY ISNULL(MemberExpression, '')),
    R AS (SELECT REPLACE((SELECT CASE WHEN A.Coef > 0 THEN ' + ' ELSE '' END +
                    REPLACE(REPLACE(CAST(A.Coef AS Varchar(Max)), '.', ','), '-', ' - ') +
                    '*' + A.MemberExpression
                    FROM A
                    WHERE A.Coef <> 0
                    ORDER BY MemberExpression FOR XML PATH('')), ' 1*', ' ') AS Expression)
    SELECT @Result = CASE
        WHEN LEFT(R.Expression, 3) = ' + ' THEN STUFF(R.Expression, 1, 3, '')
        WHEN LEFT(R.Expression, 3) = ' - ' THEN STUFF(R.Expression, 1, 3, '-')
        ELSE LTRIM(R.Expression) END
    FROM R;

TheEnd:
    SELECT @Result Result;
END;



Теперь запускаю процедуру и получаю ответ.
Код: sql
1.
EXEC [dbo].[p_AlgebraicExpression] '12*a*a*b*c + 37*b*a^2*c - 15*d^3*e + 12*e*d*d*d'


Ответ:
49*a^2*b*c - 3*d^3*e

Теперь мне надо усложнить задачу: добавить скобки и умножить (или делить) выражения, а в некоторых случаях даже возводить на определенную степень (только на целые числа, рациональные степени не рассматриваю). В интернете много пишут про обратную польскую нотацию (ОПН), но как им пользоваться пока не совсем понял. Приведу вот такой пример с числами (для наглядности):
5+(7-(3+4)*2)*(2+2*2)
По идее программа должна плюсовать 3+4 в первую очередь, ну и дальше по алгоритму. Вот как написать это в процедуре?
Прочел несколько статей про ОПН. Мне не понятно как же грамотно собрать в стек (я так понимаю отдельный столбец отдельной таблицы) а потом по приоритету выстроить алгоритм.

Спасибо заранее за подсказку / наводку и за прочую помощь.
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39968479
Фотография Ennor Tiegael
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studieren,

С ОПН вам нужно строить дерево, а не стек. Открывающая скобка - создаем дочернюю ноду, закрывающая - возвращаемся на уровень выше. Как-то так.
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39968497
Фотография court
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studieren
В интернете много пишут про обратную польскую нотацию (ОПН), но как им пользоваться пока не совсем понял.
тут хорошо расписано и преобразование в ОПЗ и расчет из ОПЗ
Алгоритмы и методы: Обратная польская запись (исходники)

studieren,

А зачем это вообще ?
"Глобальная цель" какая ?
Случайно, не вычислить выражение заданное строкой ?
(не упростить выражение с параметрами, а именно вычислить)
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39968498
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studieren,

https://github.com/dharmatech/Symbolism
Оберните в CLR процедуру или функцию.
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39968539
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ennor Tiegael
studieren,

С ОПН вам нужно строить дерево, а не стек. Открывающая скобка - создаем дочернюю ноду, закрывающая - возвращаемся на уровень выше. Как-то так.

Мне не совсем понятно как это на практике выглядит. Вы можете показать самый простейший пример? Мне бы саму идею понять как это реализовать.


court
...
А зачем это вообще ?
"Глобальная цель" какая ?
Случайно, не вычислить выражение заданное строкой ?
(не упростить выражение с параметрами, а именно вычислить)

Для решения некоторых сложных математических задач, а именно Диафантово уравнения. Сейчас вручную решаю в MS Excel.
Что же касается Вашей ссылки, то я к сожалению не знаю С++. Подобного рода статей перечитал, но так и не понял как реализовать. К примеру в той же статье пишут, что выражение a + ( b - c ) * d следует превращать на a b c - d * +. Допустим, так. Как теперь программе объяснить из выражения a b c - d * +, что сначала нужно вычислить b - c, потом умножить на d и только потом добавить а?
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39968572
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Идея ОПЗ для меня более менее понятнее стала после чтения Wikipedia: Обратная польская запись .
Там приводится пример: берём запись 3 + 4 * 2 / (1 - 5)^2 и превращаем на 3 4 2 * 1 5 - 2 ^ / +. Если я понял правильно, то полученную запись я читаю заново слева направо. Беру первые 3 символа: 3 4 2, здесь нет знака. Значит пропускаю. Беру следующие 3 символа 4 2 *, здесь есть знак, умножаю и получаю 8, после чего в записе заменяю 4 2 * на 8 и получаю 3 8 1 5 - 2 ^ / +. Опять до первого получения знака читаю слева направа и дохожу до 1 5 -. Получаю -4 и сразу заменяю. Затем по тому же сценарию воздвигаю во 2-степень и т.д.
Вот теперь вся логика стала понятнее для меня.
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39968579
TaPaK
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studieren
Идея ОПЗ для меня более менее понятнее стала после чтения Wikipedia: Обратная польская запись .
Там приводится пример: берём запись 3 + 4 * 2 / (1 - 5)^2 и превращаем на 3 4 2 * 1 5 - 2 ^ / +. Если я понял правильно, то полученную запись я читаю заново слева направо. Беру первые 3 символа: 3 4 2, здесь нет знака. Значит пропускаю. Беру следующие 3 символа 4 2 *, здесь есть знак, умножаю и получаю 8, после чего в записе заменяю 4 2 * на 8 и получаю 3 8 1 5 - 2 ^ / +. Опять до первого получения знака читаю слева направа и дохожу до 1 5 -. Получаю -4 и сразу заменяю. Затем по тому же сценарию воздвигаю во 2-степень и т.д.
Вот теперь вся логика стала понятнее для меня.

хорошо что в только целые числа бывают
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39968588
Фотография court
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studieren
Допустим, так. Как теперь программе объяснить из выражения a b c - d * +, что сначала нужно вычислить b - c, потом умножить на d и только потом добавить а?


т.е. вернуть "польскую запись" обратно, к "нормальному" виду и вычислить ?
А зачем тогда было вообще к ней, к ОПЗ преобразовывать ??

а вообще, как-то так

Код: 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.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
declare
	@Expression AS Varchar(MAX) = 'abc-d*+'
	,@v varchar(max)
	,@n1 varchar(max)
	,@n2 varchar(max)
	,@res varchar(max)
	,@i integer


declare @stack table (id int identity, v varchar(max))

set @i = 1
while @i<=len(@Expression) begin
	set @v = SUBSTRING(@Expression, @i, 1)

	if @v not in ('+','-','*','/') begin
		insert @stack (v) values (@v)
	end
	else begin
		;with cte as (select v, ROW_NUMBER()over(order by id desc) as rn from @stack )
		select 
			@n1 = max(case when rn=1 then v end)
			,@n2 = max(case when rn=2 then v end)
		from cte

		;with cte as (select v, ROW_NUMBER()over(order by id desc) as rn from @stack )
		delete from cte where rn<=2

		set @res = '('+@n1+@v+@n2+')'

		insert @stack (v) values (@res)
	end
	set @i=@i+1
	
end
select v from @stack

--
declare 
	@a int=1
	,@b int=2
	,@c int=3
	,@d int=4
	,@result int
	,@stmt nvarchar(max)

select @Expression = v from @stack

set @Expression = replace(@Expression,'a','@a')
set @Expression = replace(@Expression,'b','@b')
set @Expression = replace(@Expression,'c','@c')
set @Expression = replace(@Expression,'d','@d')

set @stmt = cast('select @result='+@Expression as nvarchar(max))

exec sp_executesql 
	@stmt = @stmt
	,@params = N'@a int, @b int, @c int, @d int, @result int out'
	,@a=@a, @b=@b, @c=@c, @d=@d, @result=@result out

select @result as result



v((d*(c-b))+a)

result5
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39968590
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
TaPaK
хорошо что в только целые числа бывают


Это же всего лишь простой пример для нагладности. На практике не только дробные числа могут быть, но и неизвестные буквенные переменные. Вот там мне придётся решать более сложную проблему. :)
Я просто до этого сам принцип ОПЗ не понимал, до меня только дошло.
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39968596
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
court,

Спасибо за пример. Я с числами оперировал только для наглядности. На самом же деле я в основном буду работать с алгебраическими выражениями. Чаще буквами, а не числами. Числа у меня будут появляться в основном в качестве коэффициента или показателя степени. Если бы речь шла только о калькуляции, то конечно же я воспользовался бы динамическим запросом.
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39968616
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Что-то я рано радовался. ОПЗ с числами хорошо работает, но вот как быть с буквами? Пока у меня не получается.
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39969210
Фотография a_voronin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studieren,

Парзер выражений на MSSQL? Это что-то совершенно не от мира сего. БД явно не для этого предназначена.
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39969404
Фотография vikkiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
обычно инструмент подбирается под задачи, в данном случае больше похоже на натягивание совы на глобус задачи на инструмент
(хотя и желание держать всё в пределах одной технологии архитектурно оправданно)
кроме того если уж выбран путь с хранимыми процедурами - то на порядок легче и гибче по функциональности будет использовать
уже давно интегрированные в MSSQL средства: CLR (C#/VB/C++ ..), а так-же с недавнего времени ML/DS: Python, Java, R (через sp_execute_external_script)
где есть достаточно пакетов и для числовой и для символьной математики.
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39969576
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studieren
Идея ОПЗ для меня более менее понятнее стала после чтения Wikipedia: Обратная польская запись .
Там приводится пример: берём запись 3 + 4 * 2 / (1 - 5)^2 и превращаем на 3 4 2 * 1 5 - 2 ^ / +. Если я понял правильно, то полученную запись я читаю заново слева направо. Беру первые 3 символа: 3 4 2, здесь нет знака. Значит пропускаю. Беру следующие 3 символа 4 2 *, здесь есть знак, умножаю и получаю 8, после чего в записе заменяю 4 2 * на 8 и получаю 3 8 1 5 - 2 ^ / +. Опять до первого получения знака читаю слева направа и дохожу до 1 5 -. Получаю -4 и сразу заменяю. Затем по тому же сценарию воздвигаю во 2-степень и т.д.
Вот теперь вся логика стала понятнее для меня.


Как уже написали - дерево надо строить и потом его обходить.
Я делал такое.
Это лучший вариант.
В ваших выражениях есть скобки, операции с приоритетом, потом вы не указали, но еще в вашем случае есть унарные операции.
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39970373
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ролг Хупин,

Можете показать хотя бы маленький пример? Я что-то не пойму как в данном случае можно построить дерево.
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39970582
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studieren
Ролг Хупин,

Можете показать хотя бы маленький пример? Я что-то не пойму как в данном случае можно построить дерево.


нефиг делать

Типичная ветка:
операнд-операция-операнд


a+b*c
=================

+
/ \
a *
/\
b c


и т.д.

Но, я никоим орбазом не хотел бы вас сбивать с направления: сделать парсер на T-SQL
Без этого ветка станет пресной
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39970588
Ролг Хупин
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Здесь от алгебры только название темы, тем более, что означает "алгебраическое выражение" - загадка.

Вот тут есть какая-то реализация
http://vicking.narod.ru/articles/exprparser.htm

вникните, перепишите и просьба: покажите результат здесь, он наверняка будет полезен будущим читателям форума.
...
Рейтинг: 0 / 0
Алгебраическое выражение
    #39976476
studieren
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
studieren
Идея ОПЗ для меня более менее понятнее стала после чтения Wikipedia: Обратная польская запись .
Там приводится пример: берём запись 3 + 4 * 2 / (1 - 5)^2 и превращаем на 3 4 2 * 1 5 - 2 ^ / +. Если я понял правильно, то полученную запись я читаю заново слева направо. Беру первые 3 символа: 3 4 2, здесь нет знака. Значит пропускаю. Беру следующие 3 символа 4 2 *, здесь есть знак, умножаю и получаю 8, после чего в записе заменяю 4 2 * на 8 и получаю 3 8 1 5 - 2 ^ / +. Опять до первого получения знака читаю слева направа и дохожу до 1 5 -. Получаю -4 и сразу заменяю. Затем по тому же сценарию воздвигаю во 2-степень и т.д.
Вот теперь вся логика стала понятнее для меня.

Попробовал создать ХП, где работает ОПЗ с числовыми выражениями (правда только простые арифметические операции ^ * / + -, другие функции такие как тригонометрические, логарифмические и пр. проигнорировал). Мне необходимо было сначала понять механизм ОПЗ.
Код: 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.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
ALTER PROCEDURE dbo.p_Reverse_Polish_Notation
(@Expression AS Varchar(MAX))
AS BEGIN
    SET NOCOUNT ON;

    IF @Expression Is Null OR @Expression = ''
        GOTO Get_Result;

    SET @Expression = REPLACE(REPLACE(REPLACE(REPLACE(@Expression,
        ' ', ''), ',', '.'), CHAR(13), ''), CHAR(10), '');

    IF @Expression LIKE '%[^0-9().*^/+-]%'
    BEGIN
        SELECT Null AS Result, 'Обнаружен неверный символ.' AS ErrorMessage;
        RETURN;
    END;

    DECLARE @Stack AS Varchar(50) = '', @Operand AS Varchar(50) = '',
            @i AS Int = 1, @Result Float;
    DECLARE @Array AS TABLE (ID Int Identity(1, 1) Primary Key,
        Operand Float, Operator Varchar(50), Del Bit);

    /*  Приоритеты:
        высокий: ^
        средний: * /
        низкий: + &#8722;
        самый низкий: ()
    */
    WHILE @i <= LEN(@Expression)
    BEGIN
        -- Число
        IF SUBSTRING(@Expression, @i , 1) NOT LIKE '[^0-9.]' OR
           (SUBSTRING(@Expression, @i , 1) LIKE '[+-]' AND LEN(@Operand) = 0)
        BEGIN
            SET @Operand = @Operand + SUBSTRING(@Expression, @i , 1);
            IF @i = LEN(@Expression)
            BEGIN
                INSERT INTO @Array (Operand)
                SELECT CAST(@Operand AS Float);
            END
        END
        -- Операторы
        ELSE
        BEGIN
            IF LEN(@Operand) > 0 AND @Operand NOT IN ('+', '-')
            BEGIN
                INSERT INTO @Array (Operand)
                SELECT CAST(@Operand AS Float);
                SET @Operand = '';
            END;
            IF SUBSTRING(@Expression, @i , 1) = '^'
            BEGIN
                SELECT @Stack = @Stack + '^';
            END
            ELSE IF SUBSTRING(@Expression, @i , 1) LIKE '[*/]'
            BEGIN
                WHILE RIGHT(@Stack, 1) LIKE '[*/^]'
                BEGIN
                    INSERT INTO @Array (Operator)
                    SELECT RIGHT(@Stack, 1);
                    SET @Stack = LEFT(@Stack, LEN(@Stack)-1);
                END;
                SELECT @Stack = @Stack + SUBSTRING(@Expression, @i , 1);
            END
            ELSE IF SUBSTRING(@Expression, @i , 1) LIKE '[+-]'
            BEGIN
                WHILE RIGHT(@Stack, 1) LIKE '[*/^+-]'
                BEGIN
                    INSERT INTO @Array (Operator)
                    SELECT RIGHT(@Stack, 1);
                    SET @Stack = LEFT(@Stack, LEN(@Stack)-1);
                END;
                SELECT @Stack = @Stack + SUBSTRING(@Expression, @i , 1);
            END
            ELSE IF SUBSTRING(@Expression, @i , 1) = '('
            BEGIN
                IF @Operand = '-'
                BEGIN
                    INSERT INTO @Array (Operand)
                    SELECT -1;
                    SELECT @Operand = '', @Stack = @Stack + '*(';
                END
                ELSE
                BEGIN
                    SELECT @Stack = @Stack + '(';
                END;
            END
            ELSE IF SUBSTRING(@Expression, @i , 1) = ')'
            BEGIN
                WHILE RIGHT(@Stack, 1) <> '('
                BEGIN
                    INSERT INTO @Array (Operator)
                    SELECT RIGHT(@Stack, 1);
                    SET @Stack = LEFT(@Stack, LEN(@Stack)-1);
                END;
                SELECT @Stack = LEFT(@Stack, LEN(@Stack)-1), @Operand = '+';
            END;
        END;

        SET @i = @i + 1;
    END;
    WHILE LEN(@Stack) > 0
    BEGIN
        INSERT INTO @Array (Operator)
        SELECT RIGHT(@Stack, 1);
        SET @Stack = LEFT(@Stack, LEN(@Stack)-1);
    END;

    -- Теперь вычисляем выражение.
    WHILE EXISTS (SELECT TOP (1) 1 FROM @Array WHERE Operand Is Null)
    BEGIN
        SELECT @i = MIN(ID) FROM @Array WHERE Operand Is Null;

        WITH A AS (SELECT ID, LEAD(Operand, 2) OVER (ORDER BY ID DESC) A,
                              LEAD(Operand, 1) OVER (ORDER BY ID DESC) B
                   FROM @Array
                   WHERE ID <= @i AND Del Is Null)
        UPDATE @Array
        SET Operand = CASE Ar.Operator
            WHEN '^' THEN POWER(A.A, A.B)
            WHEN '*' THEN A.A * A.B
            WHEN '/' THEN A.A / A.B
            WHEN '+' THEN A.A + A.B
            WHEN '-' THEN A.A - A.B END
        FROM @Array Ar, A        
        WHERE Ar.ID = A.ID AND Ar.ID = @i;

        WITH A AS (SELECT LEAD(ID, 2) OVER (ORDER BY ID DESC) ID1,
                          LEAD(ID, 1) OVER (ORDER BY ID DESC) ID2, ID
                   FROM @Array
                   WHERE ID <= @i AND Del Is Null)
        UPDATE @Array SET Del = 1 FROM @Array Ar, A
        WHERE (Ar.ID = A.ID1 OR Ar.ID = A.ID2) AND A.ID = @i;
    END;

Get_Result:
    SELECT Operand AS Result FROM @Array WHERE Del Is Null;
END;


Вроде как работает. Правда какой-либо баг возможно прозевал.
Дальше. Теперь нужно было тоже самое, но только с буквами сочинить ХП. Получилось слишком грамоздка, работает медленовато, да и куча багов. Пока у меня совсем не получается с делением. Тут у меня пока совсем нет идей как решить деление.
Код: 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.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
CREATE FUNCTION dbo.f_SeparatePolinomialMember
(@Expression AS Varchar(MAX))
RETURNS @Polinomial TABLE (Coefficient Float, Member Varchar(Max))
AS BEGIN
    IF @Expression IS NULL
    RETURN;

    DECLARE @Table AS TABLE (Number Float, Letter Varchar(100), Degree Smallint);
    DECLARE @Counter Int = 1, @Slice Varchar(4000);

    WHILE @Counter != 0
    BEGIN 
        SELECT @Counter = CHARINDEX('*', @Expression);
        IF @Counter != 0
            SELECT @Slice = REPLACE(REPLACE(LEFT(@Expression, @Counter - 1), '(', ''), ')', '');
        ELSE
            SELECT @Slice = REPLACE(REPLACE(@Expression, '(', ''), ')', '');

        INSERT INTO @Table (Number, Letter, Degree)
        SELECT
            CASE WHEN ISNUMERIC(@Slice) = 1 THEN CAST(@Slice AS Float)
                 WHEN @Slice LIKE '-[A-z]%' THEN -1 END,
            CASE WHEN ISNUMERIC(@Slice) = 1 THEN Null
                 WHEN @Slice LIKE '-[A-z]%^%' THEN SUBSTRING(@Slice, 2, CHARINDEX('^', @Slice, 1)-1)
                 WHEN @Slice LIKE '[A-z]%^%' THEN LEFT(@Slice, CHARINDEX('^', @Slice, 1)-1)
                 WHEN @Slice LIKE '-[A-z]%' THEN SUBSTRING(@Slice, 2, LEN(@Slice)-1)
                 ELSE @Slice END,
            CASE WHEN ISNUMERIC(@Slice) = 1 THEN Null
                 WHEN @Slice NOT LIKE '%^%' THEN 1
                 WHEN ISNUMERIC(SUBSTRING(@Slice, CHARINDEX('^', @Slice, 1)+1, LEN(@Slice))) = 1
                 THEN CAST(SUBSTRING(@Slice, CHARINDEX('^', @Slice, 1)+1, LEN(@Slice)) AS Smallint)
                 ELSE Null END;

        SELECT @Expression = RIGHT(@Expression, LEN(@Expression) - @Counter);
        IF LEN(@Expression) = 0 BREAK;
    END;

    WITH L AS (SELECT STUFF((SELECT '*' + Letter +
                    CASE WHEN SUM(Degree) = 1 THEN ''
                         ELSE '^' + CAST(SUM(Degree) AS Varchar(MAX)) END
                  FROM @Table
                  GROUP BY Letter
                  ORDER BY Letter FOR XML PATH('')), 1, 1, '') AS Member)
    INSERT INTO @Polinomial (Coefficient, Member)
    SELECT ISNULL(EXP(SUM(LOG(CASE WHEN T.Number = 0 THEN 1 ELSE ABS(T.Number) END)))
           * POWER(-1, (SUM(CASE WHEN T.Number < 0 THEN 1 ELSE 0 END)))
           * MIN(CASE WHEN T.Number = 0 THEN 0 ELSE 1 END), 1) AS Coefficient,
           CASE WHEN L.Member LIKE '%[A-z]%' THEN L.Member ELSE '' END AS Member
    FROM @Table T, L
    GROUP BY L.Member;

    RETURN;
END;
GO
CREATE PROCEDURE dbo.p_AlgebraicExpression
(@Expression AS Varchar(MAX), @Divider AS Varchar(MAX) = Null)
AS BEGIN
    SET NOCOUNT ON;

    -- Убираем пробелы, а также заменяем запятые на точку.
    SET @Expression = REPLACE(REPLACE(REPLACE(REPLACE(@Expression,
        ' ', ''), ',', '.'), CHAR(13), ''), CHAR(10), '');

    IF @Expression Is Null OR @Expression = ''
    GOTO Get_Result;

    IF @Expression LIKE '%[^0-9A-z().*^/+-]%'
    BEGIN
        SELECT Null Result, 'Обнаружен неверный символ.' ErrorMessage;
        RETURN;
    END;
    IF @Expression LIKE '%[A-z][A-z][A-z]%'
    BEGIN
        SELECT Null Result, '3 буквы подряд не допускается.' ErrorMessage;
        RETURN;
    END;

    IF @Expression NOT LIKE '%[A-z]%'
    BEGIN
        EXECUTE dbo.p_Reverse_Polish_Notation @Expression;
        RETURN;
    END;
    IF @Expression LIKE '-[A-z]%'
        SET @Expression = STUFF(@Expression, 1, 1, '-1*');
    ELSE IF @Expression LIKE '+%'
        SET @Expression = STUFF(@Expression, 1, 1, '');

    DECLARE @Stack Varchar(MAX), @Operand Varchar(50), @Letter Varchar(100),
            @i AS Int, @Result AS Varchar(MAX), @ID0 Int, @ID1 Int, @ID2 Int, @Max Int;
    DECLARE @Array AS TABLE (ID Int Identity(1, 1) Primary Key,
        N Int INDEX Array_N, N0 Int INDEX Array_N0,
        Operand Float, Member Varchar(10), Operator Varchar(50));
    DECLARE @Members AS TABLE (N Int INDEX Members_N, Coef Float, Member Varchar(100));

    -- Для облегчения задачи попробуем убрать знак ^ для алгебраических значений со скобками.
    WHILE @Expression LIKE '%(%)^%'
    BEGIN
        SELECT @Stack = LEFT(@Expression, CHARINDEX(')^', @Expression)),
               @i = CHARINDEX(')^', @Expression),
               @Max = 0;
        WHILE @Max <> 1
        BEGIN
            SET @i = @i - 1;
            SET @Max = @Max + CASE SUBSTRING(@Expression, @i, 1)
                                   WHEN '(' THEN 1 WHEN ')' THEN -1 ELSE 0 END;
        END;
        SET @Stack = SUBSTRING(@Stack, @i, LEN(@Stack));
        SET @Operand = SUBSTRING(@Expression, CHARINDEX(')^', @Expression)+2, 50);
        WHILE ISNUMERIC(@Operand) = 0 OR LEN(@Operand) = 0
        BEGIN
            SET @Operand = LEFT(@Operand, LEN(@Operand)-1);
        END;
        IF LEN(@Operand) = 0
        BEGIN
            SELECT Null Result, 'Неверное алгебраическое выражение.' ErrorMessage;
            RETURN;
        END;
        SET @i = CAST(@Operand AS Int);
        SET @Expression = STUFF(@Expression, CHARINDEX(')^', @Expression)+1, 1+LEN(@Operand),
            CASE WHEN @i = 1 THEN '' ELSE REPLICATE('*' + @Stack, @i-1) END);
        SELECT @Stack = '', @Operand = '';
    END;
    SELECT @Stack = '', @Operand = '', @i = 1, @Letter = '';

    /* Проверка
    SELECT @Expression Expression;
    RETURN; */

    /*  Приоритеты:
        высокий: ^
        средний: * /
        низкий: + &#8722;
        самый низкий: ()
    */
    WHILE @i <= LEN(@Expression)
    BEGIN
        -- Буквы (переменные)
        IF SUBSTRING(@Expression, @i , 1) LIKE '[A-z]'
        BEGIN
            SELECT
                @Letter = CASE
                    WHEN SUBSTRING(@Expression, @i , 5) LIKE '[A-z][A-z][0-9][0-9][0-9]'
                    THEN UPPER(SUBSTRING(@Expression, @i , 5))
                    WHEN SUBSTRING(@Expression, @i , 5) LIKE '[A-z][0-9][0-9][0-9][0-9]'
                    THEN UPPER(SUBSTRING(@Expression, @i , 5))
                    WHEN SUBSTRING(@Expression, @i , 4) LIKE '[A-z][A-z][0-9][0-9]'
                    THEN UPPER(SUBSTRING(@Expression, @i , 4))
                    WHEN SUBSTRING(@Expression, @i , 4) LIKE '[A-z][0-9][0-9][0-9]'
                    THEN UPPER(SUBSTRING(@Expression, @i , 4))
                    WHEN SUBSTRING(@Expression, @i , 3) LIKE '[A-z][A-z][0-9]'
                    THEN UPPER(SUBSTRING(@Expression, @i , 3))
                    WHEN SUBSTRING(@Expression, @i , 3) LIKE '[A-z][0-9][0-9]'
                    THEN UPPER(SUBSTRING(@Expression, @i , 3))
                    WHEN SUBSTRING(@Expression, @i , 2) LIKE '[A-z][0-9]' OR
                         SUBSTRING(@Expression, @i , 2) LIKE '[A-z][A-z]'
                    THEN UPPER(SUBSTRING(@Expression, @i , 2))
                    ELSE LOWER(SUBSTRING(@Expression, @i , 1)) END,
                @i = CASE
                    WHEN SUBSTRING(@Expression, @i , 5) LIKE '[A-z][A-z][0-9][0-9][0-9]' THEN @i+4
                    WHEN SUBSTRING(@Expression, @i , 5) LIKE '[A-z][0-9][0-9][0-9][0-9]' THEN @i+4
                    WHEN SUBSTRING(@Expression, @i , 4) LIKE '[A-z][A-z][0-9][0-9]' THEN @i+3
                    WHEN SUBSTRING(@Expression, @i , 4) LIKE '[A-z][0-9][0-9][0-9]' THEN @i+3
                    WHEN SUBSTRING(@Expression, @i , 3) LIKE '[A-z][A-z][0-9]' THEN @i+2
                    WHEN SUBSTRING(@Expression, @i , 3) LIKE '[A-z][0-9][0-9]' THEN @i+2
                    WHEN SUBSTRING(@Expression, @i , 2) LIKE '[A-z][0-9]' OR
                         SUBSTRING(@Expression, @i , 2) LIKE '[A-z][A-z]' THEN @i+1
                    ELSE @i END;
            INSERT INTO @Array (Operand, Member)
            SELECT 1, @Letter;
            SET @Letter = '';
        END
        -- Число
        ELSE IF SUBSTRING(@Expression, @i , 1) LIKE '[0-9.]'
        BEGIN
            SET @Operand = @Operand + SUBSTRING(@Expression, @i , 1);
            IF @i = LEN(@Expression)
            BEGIN
                INSERT INTO @Array (Operand)
                SELECT CAST(@Operand AS Float);
                SET @Operand = '';
            END
        END
        -- Операторы
        ELSE
        BEGIN
            IF @Operand NOT IN ('+', '-') AND LEN(@Operand) > 0
            BEGIN
                INSERT INTO @Array (Operand)
                SELECT CAST(@Operand AS Float);
                SET @Operand = '';
            END;
            IF LEN(@Letter) > 0
            BEGIN
                INSERT INTO @Array (Member)
                SELECT @Letter;
                SET @Letter = '';
            END;
            IF SUBSTRING(@Expression, @i , 1) = '^'
            BEGIN
                SELECT @Stack = @Stack + '^';
            END
            ELSE IF SUBSTRING(@Expression, @i , 1) LIKE '[*/]'
            BEGIN
                WHILE RIGHT(@Stack, 1) LIKE '[*/^]'
                BEGIN
                    INSERT INTO @Array (Operator)
                    SELECT RIGHT(@Stack, 1);
                    SET @Stack = LEFT(@Stack, LEN(@Stack)-1);
                END;
                SELECT @Stack = @Stack + SUBSTRING(@Expression, @i , 1);
            END
            ELSE IF SUBSTRING(@Expression, @i , 1) LIKE '[+-]'
            BEGIN
                WHILE RIGHT(@Stack, 1) LIKE '[*/^+-]'
                BEGIN
                    INSERT INTO @Array (Operator)
                    SELECT RIGHT(@Stack, 1);
                    SET @Stack = LEFT(@Stack, LEN(@Stack)-1);
                END;
                SELECT @Stack = @Stack + SUBSTRING(@Expression, @i , 1);
            END
            ELSE IF SUBSTRING(@Expression, @i , 1) = '('
            BEGIN
                IF @Operand = '-'
                BEGIN
                    INSERT INTO @Array (Operand)
                    SELECT -1;
                    SELECT @Operand = '', @Stack = @Stack + '*(';
                END
                ELSE
                BEGIN
                    SELECT @Stack = @Stack + '(';
                END;
            END
            ELSE IF SUBSTRING(@Expression, @i , 1) = ')'
            BEGIN
                WHILE RIGHT(@Stack, 1) <> '('
                BEGIN
                    INSERT INTO @Array (Operator)
                    SELECT RIGHT(@Stack, 1);
                    SET @Stack = LEFT(@Stack, LEN(@Stack)-1);
                END;
                SELECT @Stack = LEFT(@Stack, LEN(@Stack)-1), @Operand = '+';
            END;
        END;

        SET @i = @i + 1;
    END;
    WHILE LEN(@Stack) > 0
    BEGIN
        INSERT INTO @Array (Operator)
        SELECT RIGHT(@Stack, 1);
        SET @Stack = LEFT(@Stack, LEN(@Stack)-1);
    END;
    -- Обратная польская запись завершена. Теперь приступаем к основной задаче.
    SELECT @i = 1, @ID0 = 0, @Max = ((SELECT MAX(ID) FROM @Array)-1)*0.5;
    WHILE @i Is Not Null
    BEGIN
        WITH M AS (SELECT MIN(ID) ID FROM @Array
                   WHERE Operator Is Not Null AND N0 Is Null AND ID > @ID0),
        II AS (SELECT A.ID, A.Operator,
                      CASE WHEN A.ID = M.ID THEN 1 ELSE 0 END Remark,
                      LEAD(A.ID, 1) OVER (ORDER BY A.ID DESC) ID1,
                      LEAD(A.ID, 2) OVER (ORDER BY A.ID DESC) ID2
               FROM @Array A, M
               WHERE A.ID <= M.ID AND (A.N Is Null OR (A.Operator Is Not Null AND A.N0 Is Null)))
        SELECT @ID0 = II.ID, @ID1 = II.ID1, @ID2 = II.ID2, @Stack = II.Operator
        FROM II WHERE II.Remark = 1;

        IF @ID1 Is Null OR @ID2 Is Null
        BREAK;

        UPDATE @Array
        SET N = CASE WHEN N Is Not Null THEN N ELSE @i END,
            N0 = CASE WHEN N Is Not Null THEN @i ELSE Null END
        WHERE ID IN (@ID0, @ID1, @ID2);

        IF @Stack = '^'
        BEGIN
            WITH
            A1 AS (SELECT TOP(1) COALESCE(M.Coef, A.Operand, 1) Degree
                  FROM @Array A LEFT JOIN @Members M ON A.N = M.N
                  WHERE A.ID = @ID1)
            INSERT INTO @Members (N, Coef, Member)
            SELECT @i, POWER(A.Operand, A1.Degree) Coef,
                   CASE WHEN LEN(A.Member) > 0 THEN
                        (SELECT PM.Member FROM dbo.f_SeparatePolinomialMember
                            (STUFF(REPLICATE('*'+A.Member, A1.Degree), 1, 1, '')) PM) ELSE '' END AS Member
            FROM @Array A, A1
            WHERE A.ID = @ID2;
        END;
        ELSE IF @Stack = '*'
        BEGIN
            WITH
            A2 AS (SELECT COALESCE(M.Coef, A.Operand, 1) Coef,
                          COALESCE(M.Member, A.Member, '') Member
                  FROM @Array A LEFT JOIN @Members M ON A.N = M.N
                  WHERE A.ID = @ID2),
            A1 AS (SELECT COALESCE(M.Coef, A.Operand, 1) Coef,
                          COALESCE(M.Member, A.Member, '') Member
                  FROM @Array A LEFT JOIN @Members M ON A.N = M.N
                  WHERE A.ID = @ID1),
            AA AS (SELECT A2.Coef*A1.Coef Coef,
                          CASE WHEN LEN(A1.Member) = 0 AND LEN(A2.Member) = 0 THEN '' ELSE
                          (SELECT PM.Member
                           FROM dbo.f_SeparatePolinomialMember(CASE
                                WHEN LEN(A2.Member) = 0 THEN A1.Member
                                WHEN LEN(A1.Member) = 0 THEN A2.Member
                                ELSE A2.Member + '*' + A1.Member END) PM) END Member
                   FROM A2, A1)
            INSERT INTO @Members (N, Coef, Member)
            SELECT @i, SUM(AA.Coef) Coef, AA.Member
            FROM AA
            GROUP BY AA.Member
            HAVING SUM(AA.Coef) <> 0;
        END;
        ELSE IF @Stack = '/'
        BEGIN
            WITH
            A2 AS (SELECT COALESCE(M.Coef, A.Operand, 1) Coef,
                          COALESCE(M.Member, A.Member, '') Member
                  FROM @Array A LEFT JOIN @Members M ON A.N = M.N
                  WHERE A.ID = @ID2),
            A1 AS (SELECT COALESCE(M.Coef, A.Operand, 1) Coef,
                          COALESCE(M.Member, A.Member, '') Member
                  FROM @Array A LEFT JOIN @Members M ON A.N = M.N
                  WHERE A.ID = @ID1),
            AA AS (SELECT A2.Coef/A1.Coef Coef,
                          CASE WHEN LEN(A1.Member) = 0 AND LEN(A2.Member) = 0 THEN '' ELSE
                          (SELECT PM.Member
                           FROM dbo.f_SeparatePolinomialMember(CASE
                                WHEN LEN(A2.Member) = 0 THEN '1/(' + A1.Member + ')'
                                WHEN LEN(A1.Member) = 0 THEN A2.Member
                                ELSE A2.Member + '/' + A1.Member END) PM) END Member
                   FROM A2, A1)
            INSERT INTO @Members (N, Coef, Member)
            SELECT @i, SUM(AA.Coef) Coef, AA.Member
            FROM AA
            GROUP BY AA.Member
            HAVING SUM(AA.Coef) <> 0;
        END;
        ELSE IF @Stack = '+'
        BEGIN
            WITH AA AS (SELECT ISNULL(M.Coef, A.Operand) Coef, COALESCE(M.Member, A.Member, '') Member
                        FROM @Array A LEFT JOIN @Members M ON A.N = M.N
                        WHERE A.ID = @ID2
                        UNION ALL SELECT ISNULL(M.Coef, A.Operand), COALESCE(M.Member, A.Member, '')
                        FROM @Array A LEFT JOIN @Members M ON A.N = M.N
                        WHERE A.ID = @ID1)
            INSERT INTO @Members (N, Coef, Member)
            SELECT @i, SUM(AA.Coef) Coef, AA.Member
            FROM AA
            GROUP BY AA.Member
            HAVING SUM(AA.Coef) <> 0;
        END
        ELSE IF @Stack = '-'
        BEGIN
            WITH AA AS (SELECT ISNULL(M.Coef, A.Operand) Coef, COALESCE(M.Member, A.Member, '') Member
                        FROM @Array A LEFT JOIN @Members M ON A.N = M.N
                        WHERE A.ID = @ID2
                        UNION ALL SELECT ISNULL(-M.Coef, -A.Operand), COALESCE(M.Member, A.Member, '')
                        FROM @Array A LEFT JOIN @Members M ON A.N = M.N
                        WHERE A.ID = @ID1)
            INSERT INTO @Members (N, Coef, Member)
            SELECT @i, SUM(AA.Coef) Coef, AA.Member
            FROM AA
            GROUP BY AA.Member
            HAVING SUM(AA.Coef) <> 0;
        END;

        SET @i = @i + 1;
        IF @i > @Max BREAK;
    END;

    SET @Result = '';

    UPDATE @Members SET Member = '' WHERE Member Is Null;

Get_Result:
    /* Проверка
    SELECT * FROM @Array;
    SELECT * FROM @Members; */
    
    SELECT @Result = @Result +
        CASE WHEN Member = '' OR Member Is Null THEN REPLACE(CAST(Coef AS Varchar(MAX)), '.', ',')
             WHEN Coef = 1 THEN '+' + Member
             WHEN Coef > 0 THEN '+' + REPLACE(CAST(Coef AS Varchar(MAX)), '.', ',') + '*' + Member
             WHEN Coef = -1 THEN '-' + Member
             WHEN Coef < 0 THEN REPLACE(CAST(Coef AS Varchar(MAX)), '.', ',') + '*' + Member END
    FROM @Members
    WHERE N = @Max AND Coef <> 0
    ORDER BY Member;

    SELECT CASE WHEN LEFT(@Result, 1) = '+' THEN STUFF(@Result, 1, 1, '')
                ELSE @Result END AS Result, Null AS ErrorMessage;
END;


Хранимка не работает со всеми математическим функциями кроме как арефматическими, воздвигать в степень можно только на натуральное число.

Проблема №1. не правильно работает деление
Проблема №2. очень и очень не оптимальное решение, слишком грамоздко.
Проблема №3. хотелось красиво упорядочивать выражение (в смысле сначала "a" с наибольшей степени, а потом в порядке убывание как принято у математиков, но тоже пока без идей).

Примеры:
Код: sql
1.
EXEC dbo.p_AlgebraicExpression '(a+b)^3*(a-b)'


Результат: -2*a*b^3+2*a^3*b+a^4-b^4
А вот так ошибка!
Код: sql
1.
EXEC dbo.p_AlgebraicExpression '(a+b)^3/(a+b)'


4+6*a+3*a^2*b/a+3*a^2*b/b

Если есть у кого-то совет как упростить и улучшить, решить проблемы, буду очень признателен.
...
Рейтинг: 0 / 0
18 сообщений из 18, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Алгебраическое выражение
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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