15.01.2008, 15:23 | #1 |
Участник
|
Взаимоисключающие условия для like
Исходные данные задачи:
1. Есть Table1 c полями: a. Id – код b. Amount – сумма 2. Есть периодическая операция, которая должна выбрать записи из table1 и увеличить значение поля Amount на заданную величину. При запуске операции открывается временная таблица tmpTable1, с полями: a. Mask – маска для поля id в Table1 b. addAmount – величина , на которую необходимо увеличить значение в поле Amount в Table1 Т.е. примерно такой код: X++: While select from tmpTable1 Join forUpdate Table1 where Table1.Id like tmpTable1.Mask { Table1.Amount += tmpTable1.addAmount; Table1.update(); } Пример: Вариант 1 (корректный) - когда одна запись из table1 может быть сджойнена только с одной записью tmpTable1 Mask1 = 6* Mask2 = 7* Вариант2 (некорректный) - когда одна запись из table1 может быть с джойнена c несколькими записями tmpTable1 Mask1 = 6* Mask2 = *7 |
|
15.01.2008, 15:44 | #2 |
Модератор
|
Почитайте про outter, exists и про innerjoin.
Справка по select С Уважением, Георгий |
|
15.01.2008, 15:49 | #3 |
Участник
|
То есть Вам надо обнаружить наличие двух строчек с одним id из tabl1. Если это так то в томи же цикле и проверяйте очевидным образом
|
|
15.01.2008, 15:54 | #4 |
Moderator
|
Цитата:
P.S. Насколько я понимаю, при условиях варианта 1 значение, например, 67 однозначно попадет на 6*, а при условиях варианта 2 значению 67 будут соответствовать и 6*, и *7, что недопустимо. А чему из двух должно однозначно соответствовать 67 во втором случае? Т.е. какие "правила игры"? |
|
15.01.2008, 16:05 | #5 |
Участник
|
Пример1 (корректный):
Записи table1 7489 +10 7569 +11 6758 +12 6547 +13 Записи tmpTable1: 7* +2 6* +3 После выполнения получу такие данные в table1 7489 +12 (+2 по маске 7*) 7569 +13 (+2 по маске 7*) 6758 +15 (+3 по маске 6*) 6547 +16 (+3 по маске 6*) Пример2 (некорректный по БП): Записи table1 7489 +10 7569 +11 6758 +12 6547 +13 Записи tmpTable1: *7 +2 6* +3 После выполнения получу такие данные в table1 7489 10 (0 нет подходящей маски) 7569 11 (0 нет подходящей маски) 6758 15 (+3 по маске 6*) 6547 18 (+3 по маске 6* и +2 по маске *7) – возможность появления таких ситуаций я хочу исключить, выполнив проверку данных в таблице tmpTable1. |
|
15.01.2008, 16:10 | #6 |
Участник
|
|
|
15.01.2008, 16:17 | #7 |
Moderator
|
|
|
15.01.2008, 16:24 | #8 |
Участник
|
Правила игры одно – если в таблице tmpTable1 есть хотябы 2 записи, которым потенциально может удовлетворять одно и тоже значение id из таблицы table1, то это ошибка. Если таких записей нет, то и ошибки нет.
|
|
15.01.2008, 16:28 | #9 |
Участник
|
Заводим переменную, куда пишем значение приращения по маске, если значение этой переменной было 0. При переходе к новой записи в table1 значение этой переменной обнуляем. Если проверка на 0 не сработала, то откатываем приращение по этой строке.
|
|
15.01.2008, 16:35 | #10 |
Участник
|
Цитата:
Можно конечно написать что-то типа: X++: select firstOnly from table1 join tmpTable1 where table1.id like tmpTable1.mask join tmpTable2 where table1.id like tmpTable2.mask && tmpTable1.recId != tmpTable2.recId; А как это сделать не обращаясь к table1? |
|
15.01.2008, 16:39 | #11 |
Участник
|
Может так сойдет?
X++: Set updated = new Set(Types::Int64); While select from tmpTable1 Join forUpdate Table1 where Table1.Id like tmpTable1.Mask { if (!updated.in(Table1.RecID)) { Table1.Amount += tmpTable1.addAmount; Table1.update(); updated.add(Table1.RecID) } } Последний раз редактировалось belugin; 15.01.2008 в 16:41. |
|
15.01.2008, 16:40 | #12 |
Участник
|
вот такой запрос:
X++: select firstOnly tmpTable1 join tmpTable2 where tmpTable2.Mask like tmpTable1.Mask && tmpTable2.RecId != tmpTable1.RecId; |
|
15.01.2008, 16:44 | #13 |
Участник
|
Если в таблице tmpTable1 есть хотябы 2 записи, которым потенциально может удовлетворять одно и тоже значение id из таблицы table1, то это ошибка и обновлять table1 не нужно.
to belugin Ну это почти тоже самое, что предложил dn |
|
15.01.2008, 17:05 | #14 |
Участник
|
Я думаю, задача состоит в том, чтобы узнать, имеет ли пересечение языки порождаемые двумя регулярными выражениями. Попробовал погуглиь, но ничего не нашел.
Друг другом маск проверять по лайку не стоит так как для пары ?BС like A?С оно даст неверный результат, хотя обе маски подходят по ABC |
|
15.01.2008, 17:13 | #15 |
Участник
|
Цитата:
Вот такой if тоже false вернет X++: if("7*" like "76") X++: if("76" like "7*") |
|
15.01.2008, 17:18 | #16 |
Участник
|
в-общем, ороший предлог окунуться в теорию формальных грамматик
|
|
15.01.2008, 17:24 | #17 |
Участник
|
Без table1 вы не можете точно сказать - пересекаются значения, соответствующие маскам или нет. Потенциально, 7* и *7 могут вернуть одинаковые записи, но в вашем примере пересений нет.
По поводу like - левая часть проверяется как есть, без преобразования метасимволов
__________________
Axapta v.3.0 sp5 kr2 |
|
15.01.2008, 17:33 | #18 |
Участник
|
Меня, пожалуй, устроит решение запросом с использованием table1, так как перспектива
Цитата:
Сообщение от belugin
в-общем, ороший предлог окунуться в теорию формальных грамматик
В примере пересечений нет, но если потенциально они возможны, то в идеале хотелось бы выдавать ошибку и не выполнять обновления table1 |
|
15.01.2008, 20:58 | #19 |
Moderator
|
Зацепило. Поигрался на тему. Сваял джоб-имитатор ситуации, использовав три временных буфера от таблицы InventTable. Получил набор хороших id-шников, которые можно засунуть, например, в map и далее уже без анализа использовать в цикле. Одним словом - выкладываю, а там, может, на что-то натолкнет еще...
P.S. 09:50 16.01.08. Добавил еще один временный буфер и сделал имитацию обновления исходной таблицы. Джоб обновил. X++: static void Test_6_star_7(Args _args) { InventTable table1_t; // исходная таблица InventTable tmpTable1_m; // маски InventTable tmpTable2_g; // хорошие id InventTable tmpTable3_u; // обновления для хороших id // InventTable inventTable; ; // ниже везде id храним в ItemId, Amount в Height //(просто так выбрали подходящие поля из InventTable) // имитация table1 (исходная таблица) table1_t.setTmp(); ttsbegin; table1_t.ItemId = '7489'; table1_t.Height = 10; table1_t.doInsert(); table1_t.ItemId = '7569'; table1_t.Height = 11; table1_t.doInsert(); table1_t.ItemId = '6758'; table1_t.Height = 12; table1_t.doInsert(); table1_t.ItemId = '6547'; table1_t.Height = 13; table1_t.doInsert(); ttscommit; /* // а можно прочитать из реальной постоянной таблицы // например, из inventTable ttsbegin; while select inventTable { table1_t.data(inventTable); table1_t.doInsert(); } ttscommit; */ info('--- 1. ДО ОБНОВЛЕНИЯ:'); while select table1_t info( strFmt('id: %1, Amount: %2', table1_t.ItemId, table1_t.Height) ); // имитация tmpTable1 (маски) tmpTable1_m.setTmp(); ttsbegin; tmpTable1_m.ItemId = '*7'; tmpTable1_m.Height = 2; tmpTable1_m.doInsert(); tmpTable1_m.ItemId = '6*'; tmpTable1_m.Height = 3; tmpTable1_m.doInsert(); ttscommit; // хорошие id - во временной служебной таблице tmpTable2_g.setTmp(); ttsbegin; while select ItemId, count(RecId) from table1_t group by ItemId join tmpTable1_m where table1_t.ItemId like tmpTable1_m.ItemId { if (table1_t.RecId==1) { tmpTable2_g.ItemId = table1_t.ItemId; tmpTable2_g.doInsert(); } } ttscommit; // готовим набор обновлений (id и Amount) - во временной служебной таблице tmpTable3_u.setTmp(); ttsbegin; while select ItemId from tmpTable2_g join Height from tmpTable1_m where tmpTable2_g.ItemId like tmpTable1_m.ItemId { tmpTable3_u.ItemId = tmpTable2_g.ItemId; tmpTable3_u.Height = tmpTable1_m.Height; tmpTable3_u.doInsert(); } ttscommit; info('--- 2. ОБНОВЛЕНИЯ:'); while select tmpTable3_u info( strFmt('id: %1, addAmount: %2', tmpTable3_u.ItemId, tmpTable3_u.Height) ); // обновляем исходную таблицу ttsbegin; while select forupdate table1_t join tmpTable3_u where table1_t.ItemId == tmpTable3_u.ItemId { table1_t.Height += tmpTable3_u.Height; table1_t.doUpdate(); } ttscommit; info('--- 3. ПОСЛЕ ОБНОВЛЕНИЯ:'); while select table1_t info( strFmt('id: %1, Amount: %2', table1_t.ItemId, table1_t.Height) ); } Код: --- 1. ДО ОБНОВЛЕНИЯ: id: 6547, Amount: 13.00 id: 6758, Amount: 12.00 id: 7489, Amount: 10.00 id: 7569, Amount: 11.00 --- 2. ОБНОВЛЕНИЯ: id: 6758, addAmount: 3.00 --- 3. ПОСЛЕ ОБНОВЛЕНИЯ: id: 6547, Amount: 13.00 id: 6758, Amount: 15.00 id: 7489, Amount: 10.00 id: 7569, Amount: 11.00 |
|