|
![]() |
#1 |
Модератор
|
А код, который отыщет свободные диапазоны RecId в компании на объеме данных, сопоставимом с постановкой задачи (500Гб) - будет?
__________________
-ТСЯ или -ТЬСЯ ? |
|
![]() |
#2 |
Moderator
|
Цитата:
Для этих манипуляций у меня имеется джоб оббегания по таблицам Аксапты и сохранения данных в Аксесе: X++: static void Job350_AllRecIds(Args _args) { str strFileName = @'C:\AxForumTests\Gustav\RecId.mdb'; str strFolderName; Filename filename; FilenameType filenameType; FilePath filePath; container conPath; COM dbe, db; COM cnn, rst; COM flds, fld; int i, nLines; int timeFullStart, timeFullFinish; Dictionary dictionary = new Dictionary(); TableId tableId; DictTable dictTable; Common common; int row, timeStart; int recordCount; #CCADO #define.dbLangGeneral(';LANGID=0x0409;CP=1252;COUNTRY=0') void recreateAccessTable(str _table, str _fields) { try { nLines = infolog.line(); db.Execute('DROP TABLE [' + _table + ']'); } catch (Exception::Error) { infolog.clear(nLines); } db.Execute( 'CREATE TABLE [' + _table + '] (' + _fields + ')' ); } ; timeFullStart = timenow(); // parse file name ----------------------------------------------------------------------------- [filePath, filename, filenameType] = fileNameSplit(strFileName); conPath = str2con_RU(filePath, '\\'); // you can use str2con if you do not have Russian DIS-layer if (subStr(filePath,2,1) != ':') { info(@'For drive use only one character syntax: C:\...! Do not use: \\server\folder\...!'); return; } // create folders if they not exist ------------------------------------------------------------ if (conlen(conPath)>1) { strFolderName = conpeek(conPath,1); // C: for (i=2; i<=conlen(conPath); i++) { strFolderName += strFmt(@'\%1', conpeek(conPath,i)); // C:\AxForumTests... if (!WinAPI::folderExists(strFolderName)) WinApi::createDirectory(strFolderName); } } // create MDB-file if not exists --------------------------------------------------------------- dbe = new COM('DAO.DBEngine.36'); if (!WinAPI::fileExists( strFileName )) { try { nLines = infolog.line(); db = dbe.CreateDatabase(strFileName, #dbLangGeneral); } catch (Exception::Error) { infolog.clear(nLines); info( 'Probably mdb-file already exists and is open at the moment!' ); } } else { db = dbe.OpenDatabase( strFileName ); } // (re)create tables in MDB-file ---------------------------------------------------------------- recreateAccessTable( 'UsedRecId', 'TblId LONG, ' + 'DataAreaId TEXT(3),' + 'RecId LONG ' ); recreateAccessTable( 'RecIdHoles', 'FromRecId LONG, ' + 'ToRecId LONG ' ); db.Close(); db = null; dbe = null; // export EmplTable (a few fields) from Axapta to similar table in Access ---------------------- cnn = new COM('ADODB.Connection'); cnn.connectionString('Provider=Microsoft.Jet.OLEDB.4.0;' + 'Data Source=' + strFileName); cnn.Open(); rst = new COM('ADODB.Recordset'); rst.LockType(#adLockOptimistic); rst.Open('UsedRecId', cnn); flds = rst.Fields(); row = 0; for (i=1; i<= dictionary.tableCnt(); i++) { tableId = dictionary.tableCnt2Id(i); dictTable = new DictTable(tableId); print strFmt('%1 -- %2 -- %3', tableId, dictTable.name(), row); // если в очередной таблице нет записей // то переходим к следующей try { nLines = infolog.line(); recordCount = new SysDictTable(tableId).recordCount(); } catch //может случиться, если таблица есть в репозитарии, но нет в базе { infolog.clear(nLines); recordCount = 0; } if (! recordCount) continue; common = dictTable.makeRecord(); // цикл по записям таблицы (МОЖНО ОГРАНИЧИТЬ ДИАПАЗОН ПОИСКА RecId ПО ВСЕМ ТАБЛИЦАМ) while select common where common.RecId >= 800000001 && common.RecId <= 900000000 { row++; rst.AddNew(); fld = flds.Item('TblId' ); fld.Value(tableId); fld = flds.Item('DataAreaId'); fld.Value(common.dataAreaId); fld = flds.Item('RecId' ); fld.Value(common.RecId); rst.Update(); } } rst.Close(); rst = null; cnn.Close(); cnn = null; timeFullFinish = timenow(); box::info(strfmt('Total running time: %1 sec -- Records: %2', timeFullFinish - timeFullStart, row)); } Далее уже в Аксесе создаем VBA-модуль со следующей начинкой: Код: Option Compare Database Option Explicit Sub packHolesInIntSequenceToRanges() '=================================================================== ' Сворачивание "дырок" в последовательности целых чисел в диапазоны '=================================================================== Dim cnn As ADODB.Connection Dim rstSource As ADODB.Recordset Dim rstRanges As ADODB.Recordset Dim rangeNum As Integer 'счетчик непрерывных диапазонов Dim curr As Long 'текущее (очередное) значение из последовательности Dim prev As Long 'предыдущее значение (конец непрерывного диапазона) Const minDelta As Long = 25 'минимальный размер непрерывного диапазона '(диапазоны меньшей длины игнорируются) Const startFrom As Long = 15082620 '15000001 'стартовое значение процессса - либо "дырка", либо нет 'первый prev все равно на 1 меньше и считается не дыркой Const stopOn As Long = 19997895 'следующий NextVal - 25*кол-во пользователей - последний curr - считается дыркой Set cnn = Application.CurrentProject.AccessConnection Set rstSource = New ADODB.Recordset With rstSource Set .ActiveConnection = cnn .source = "SELECT * FROM UsedRecId WHERE DataAreaId=""ppp""" & _ " AND RecId >= " & CStr(startFrom) & _ " AND RecId <= " & CStr(stopOn) & " ORDER BY RecId" .Open End With Set rstRanges = New ADODB.Recordset With rstRanges Set .ActiveConnection = cnn .source = "RecIdHoles" .LockType = adLockOptimistic .Open End With rangeNum = 0 prev = startFrom - 1 Do While Not rstSource.EOF curr = rstSource("RecId").Value If curr - prev > 1 Then 'записываем диапазон, закончившийся на предыдущем If curr - prev - 1 >= minDelta Then 'здесь именно минус 1 rangeNum = rangeNum + 1 Debug.Print rangeNum rstRanges.AddNew rstRanges("FromRecId").Value = prev + 1 'From rstRanges("ToRecId").Value = curr - 1 'To rstRanges.Update End If End If prev = curr rstSource.MoveNext Loop 'для последнего диапазона curr = stopOn + 1 'не дырка If curr - prev > 1 Then 'записываем диапазон, закончившийся на предыдущем If curr - prev - 1 >= minDelta Then 'здесь именно минус 1 rangeNum = rangeNum + 1 Debug.Print rangeNum rstRanges.AddNew rstRanges("FromRecId").Value = prev + 1 'From rstRanges("ToRecId").Value = curr - 1 'To rstRanges.Update End If End If Set rstRanges = Nothing Set rstSource = Nothing Set cnn = Nothing End Sub Последующий перенос данных из аксессной RecIdHoles в RECIDHOLES в схеме Аксапты - любым желаемым способом, вплоть до приаттачивания RECIDHOLES к файлу MDB как таблицы ODBC и элементарного ручного копипаста из одной таблицы в другую. Или через Excel - вставляем данные RecIdHoles в колонки A и B, в ячейке C1 пишем формулу ="INSERT INTO RECIDHOLES VALUES ("&A1&","&B1&");" и копируем ее на следующие строки; далее копируем содержимое колонки С в QA (для MS SQL Server) или TOAD (для Oracle) и исполняем этот набор операторов INSERT. Последний раз редактировалось Gustav; 08.12.2010 в 11:28. |
|
|
За это сообщение автора поблагодарили: mazzy (2), Logger (10), lev (5), vml (1), S.Kuskov (8). |
Теги |
ax3.0, recid, дефрагментирование recid, законченный пример, полезное |
|
![]() |
||||
Тема | Ответов | |||
if (record) vs if (record.RecId) | 18 | |||
поля, содержащие RecId | 15 | |||
Что лучше select RecId или select TableId | 9 | |||
aEremenko: Дефрагментация RecID | 2 | |||
Два RecId у одной записи таблицы | 33 |
Опции темы | Поиск в этой теме |
Опции просмотра | |
|