Як зробити двонаправлений запит

[ виправити ] текст може містити помилки, будь ласка перевіряйте перш ніж використовувати.

скачати

Євген Каратаєв

Мені давно було цікаво, чи можна зробити в Cache 'такий запит, щоб його можна було б прокручувати тому, наприклад щось на зразок команди, парною до Fetch, наприклад Prior. Власні кошти Cache 'чомусь не надають такої можливості. Для цього я вивчив характер взаємодії sql-двигуна з Cache Object Script. У результаті досліджень з'ясувалося, що це можливо, хоча і не настільки гладко, як би того хотілося. Сподіваюся, читач з розумінням поставиться до виниклої некрасиво.

Візьмемо й зробимо рутину з наступним текстом:

run ()

& Sql (declare cur CURSOR for select ID, Name, Home

from Sample.Person order by ID asc)

& Sql (open cur)

& Sql (fetch cur)

& Sql (close cur)

q

Скомпіліруем і збережемо текст отриманої int-рутини. Після чого змінимо рутину наступним чином:

run ()

& Sql (declare cur CURSOR for select ID, Name, Home

from Sample.Person order by ID desc)

& Sql (open cur)

& Sql (fetch cur)

& Sql (close cur)

q

І також збережемо текст отриманої int-рутини. У запиті можна використовувати будь-яку наявну у Вас таблицю, просто в даному випадку я використав таблицю зі штатного дистрибутива.

Звіривши отримані тексти int-рутин. Нічого особливо романтичного у роботі автоматичного генератора не спостерігається, за винятком того, що згенеровані тексти повністю збігаються за винятком заміни операції $ o () на $ zp (), які один одного прямо протилежні за напрямком. Таким чином, для реалізації двобічної прокручування використовуємо обидва варіанти і спробуємо поєднати їх дані, залишивши і використавши коди (рутини) доступу.

Для роботи нам будуть потрібні якісь чергові дані. Створюємо новий клас, наприклад User.NameList, спадкоємець% Persistent та% Populate. Додаємо йому нову властивість Name:% String. Зберігаємо, компілюємо. У терміналі створюємо 10 об'єктів для тіста:

d # # class (User.NameList). Populate ()

Запускаємо SQL Manager і для перевірки що дійсно створена таблиця sql і містить тестові дані, виконуємо запит

select ID, Name from NameList.

Якщо все було в порядку, то буде показана табличка з двома колонками і десятком рядків. Імена англомовні, вигадані. Для перевірки роботи прокручування в обидві сторони створимо рутину (наприклад FetchBack) з кодом

Test ()

n ascHandle, descHandle, ascSelect, descSelect,

n ok, i, AtEnd, Row, ID, Name, State, ascClose, descClose

; Первісне вираження - "select ID, Name from NameList"

; Щоб ходити по ньому, перетворимо в два

s ascSelect = "select ID, Name from NameList order by ID ASC"

s descSelect = "select ID, Name from NameList order by ID DESC"

S ok = # # class (% DynamicQuery). SQLPrepare (. DescHandle, descSelect)

S ok = # # class (% DynamicQuery). SQLExecute (. DescHandle)

s descClose = descHandle

S ok = # # class (% DynamicQuery). SQLPrepare (. AscHandle, ascSelect)

S ok = # # class (% DynamicQuery). SQLExecute (. AscHandle)

s State = $ li (ascHandle, 1)

s ascClose = ascHandle

; Йдемо на 4 кроки вперед

s $ li (ascHandle, 1) = State

w "4 steps forward",!

fi = 1:1:4 d

. d # # class (% DynamicQuery). SQLFetch (. ascHandle,. Row,. AtEnd)

. q: (AtEnd = 1)! (Row = "")

. s ID = $ li (Row, 1)

. s Name = $ li (Row, 2)

. w "ID =" _ID_ ", Name =" _Name,!

s State = $ li (ascHandle)

; Повертаємося на 2 кроки назад

s $ li (descHandle, 1) = State

w "2 steps backward",!

fi = 1:1:2 d

. d # # class (% DynamicQuery). SQLFetch (. descHandle,. Row,. AtEnd)

. q: (AtEnd = 1)! (Row = "")

. s ID = $ li (Row, 1)

. s Name = $ li (Row, 2)

. w "ID =" _ID_ ", Name =" _Name,!

s State = $ li (descHandle)

; Знову на 4 кроки вперед

s $ li (ascHandle, 1) = State

w "4 steps forward",!

fi = 1:1:4 d

. d # # class (% DynamicQuery). SQLFetch (. ascHandle,. Row,. AtEnd)

. q: (AtEnd = 1)! (Row = "")

. s ID = $ li (Row, 1)

. s Name = $ li (Row, 2)

. w "ID =" _ID_ ", Name =" _Name,!

s State = $ li (ascHandle)

d # # class (% DynamicQuery). SQLClose (. ascClose)

d # # class (% DynamicQuery). SQLClose (. descClose)

q

Компілітуем, виконуємо. У моєму випадку це виглядає як

USER> d Test ^ FetchBack ()

4 steps forward

ID = 1, Name = Presley, Samantha H.

ID = 2, Name = Quine, Keith G.

ID = 3, Name = Jones, Elvira A.

ID = 4, Name = Townsend, Howard D.

2 steps backward

ID = 3, Name = Jones, Elvira A.

ID = 2, Name = Quine, Keith G.

4 steps forward

ID = 3, Name = Jones, Elvira A.

ID = 4, Name = Townsend, Howard D.

ID = 5, Name = Uberoth, Juanita D.

ID = 6, Name = Van De Griek, Michael K.

Бачимо, що два використані запиту гладко пошили по використовуваному стану. Це обумовлено тим, що обидва запиту абсолютно ідентичні за винятком напряму сортування. Дослідження кодів повернення функцій дозволяє зробити судження про більш правильне ставлення до закриття запитів.

Таким чином, скласти новий клас або набір класів, аналогічні по інтерфейсу штатним, не складає особливих проблем. За винятком того, що маючи один запит ми повинні будемо зробити з нього два. Для цього введемо деяку некрасивість - в тілі запиту зажадаємо вказівки обох сортувань і роздільників, що обмежують власне запит і сортування. Виберемо в якості роздільника символи $ $ $ і будемо вважати, що запит будується за схемою:

select ...

from ...

where ...

$ $ $ Order by ... asc

$ $ $ Order by ... desc

І що при цьому програміст візьме на себе інтелектуальну роботу з повторення сортування в обох кінцях. Поля, що потрапляють в сортування, повинні дійсно визначати рядок вибірки. Якщо поля у вибірці допускають неунікальні рядка, то слід ввести поле, введення якого зробить рядок унікальною. Це потрібно для коректного зшивання сортувань. Втім, це досить поверхневе теоретичне судження і після його перевірки воно може бути неправильним в якихось версіях.

Все, що нам знадобиться, це утримувати в одному запиті два описувача замість одного. При створенні запиту сконструіруем два об'єкти і при виконанні операцій будемо звертатися до відповідних нашим внутрішніх об'єктів і передавати їх дані штатним sql-движку.

Увагу привертає поведінка функцій доступу, наприклад, клас% DynamicSQLQuery, функція Fetch:

n% qref, rtn Set% qref = $ lg (qHandle, 1), rtn = $ lg (qHandle, 2)

Quit:% qref =""!( rtn = "") $ $ $ ERROR ($ $ $ GeneralError, "Query not Prepared")

QUIT $ $ Fetch ^ @ rtn

Як видно з тексту, сама функція приймає і передає qHandle по посиланню, але до згенерованої рутині звертається, передаючи значення через локальні змінні. Код згенерованої рутини закритий, але судячи з того, що стан qHandle повинно бути передано назовні, її модифікувати може тільки викликається рутина $ $ Fetch ^ @ rtn. Інших проблемних моментів я не знайшов, тому до справи.

Експортуємо класи% DynamicQuery,% DynamicSQLQuery і $ ResultSet в cdl. Дописуємо до їх іменами символ 2 і правимо коди так, щоб у% DynamicSQLQuery2 була внутрішня підтримка зворотного прокрутки, більш розгорнутого хендла, щоб у класу% DynamicQuery використовувався запит типу% DynamicSQLQuery2 і щоб клас% ResultSet2 мав ще одну функцію, що обертається до FetchBack.

Утворені у мене для Cache '4.1.9 класи можна завантажити за посиланням у кінці сторінки.

Перевірочний код приблизно наступного вигляду:

run ()

n result, i

Set result = # # class (% ResultSet2).% New ("% DynamicQuery2: SQL")

Do result.Prepare ("select ID, Name from NameList

$ $ $ Order by ID ASC $ $ $ order by ID DESC ")

Do result.Execute ()

fi = 1:1:4 d

. d result.Next ()

. Write result.Get ("ID"), result.Get ("Name"),!

fi = 1:1:2 d

. d result.Prior ()

. Write result.Get ("ID"), result.Get ("Name"),!

fi = 1:1:4 d

. d result.Next ()

. Write result.Get ("ID"), result.Get ("Name"),!

Do result.% Close ()

q

У результаті його роботи в терміналі видаються приблизно наступні дані:

USER> d run ^ fetch ()

1Presley, Samantha H.

2Quine, Keith G.

3Jones, Elvira A.

4Townsend, Howard D.

3Jones, Elvira A.

2Quine, Keith G.

3Jones, Elvira A.

4Townsend, Howard D.

5Uberoth, Juanita D.

6Van De Griek, Michael K.

Оскільки дані згенеровані випадковим чином, у Вашому випадку вони можуть виглядати інакше.

До неприємностей методу можна віднести наступні обставини -

Використання нестандартного набору класів

Але що заважає змінити штатні класи, якщо це дуже потрібно?

Використання нештатної sql конструкції

Але штатної немає, а яка різниця, які символи будуть там написані? Адже все одно щось писати треба буде.

У версії Cache 5 з'явився додатковий клас% ScrollableResultSet, який приблизно те ж саме і робить, і крім того об'єкт цього класу може бути збережений в базі даних. Це дозволяє просто організувати підкачування сторінок наприклад для веб інтерфейсу - видачу рядків порціями з збереженням контексту запиту між зверненнями до бази наприклад.

Додати в блог або на сайт

Цей текст може містити помилки.

Програмування, комп'ютери, інформатика і кібернетика | Реферат
15.1кб. | скачати


Схожі роботи:
Як зробити бізнес інвестиційно привабливим
Що можна зробити за допомогою генетичних модифікацій
Що заважає зробити успішніше CRM в Росії
Як зробити російську економіку керованої та ефективної
Як зробити процес внутрішніх аудитів інновативних та ефективним
Відносини з клієнтами що заважає зробити успішніше CRM в Росії
Види й типи логістики логістичне завдання зробити або купити інтермодальні системи постачань
© Усі права захищені
написати до нас