SQL - UDF - надумал я делать так:

ODBC

Модератор: Andrew™

Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
Ответить
Гость

Сообщение Гость »

Hello clalist,

Надумал я делать так:
есть UDF с параметрами listClassName(<параметры>) и есть таблица udf_listClassName

каждый раз, когда мне нужны данные в Кларионе я командую:

Код: Выделить всё

DELETE
FROM udf_listClassName

INSERT INTO udf_listClassName
        SELECT *
        FROM listClassName(<параметры>)

а затем использую эту таблицу в Кларионе привычным способом - разворачиваю в Browse и т.д.

Можно, однако, и для этой нужды создать UDF - но это ИМХО не приципиально.

--
Best regards,
Иван mailto:shkmail@inbox.ru

Написал: ClaList(2)
Гость

Сообщение Гость »

и появилась у меня мысля: если с системой работают одновременно несколько операторов и каждый задает свои <параметры>, то ведь начнутся проблемы: сервер постоянно будет создавать новые таблицы - скорость, + к тому же серьезно возрастет вероятность сбоев?

может быть выход заключается в том, чтобы выборки хранить на на SQL-сервере, а как TPS-файлы на самой машине - они ведь играют роль временных данных?

или создавать на сервере разные таблицы выборок для разных операторов?

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

но как тогда задавать параметры? изменять описание представления?
или использовать данные из некоторой "системной таблицы", где указан ID оператора и параметры его выборки, опять же - как задавать ID оператора....

Короче у меня явно не хватает знаний и опыта...

--
Best regards,
Иван

Прежде чем ждать советов ты бы дал народу пример своей хранимки, которая тебе генерирует нужную выборку. Тогда было бы можно обсуждать предметно.
А так просто непонятно - отчего бы не пользоваться простыми запросами или вьшками.

--
Best regards,
Vadym mailto:vadim@softcreator.com
ICQ: 82308757

(Добавление)

Здрям!

Буду проще...

Есть таблица bigTable.

Имеется параметры, определяющие выборку из это таблицы.
Для осуществления выборки (с этими параметрами) используются или UDF, или StoredProc.

Для того, чтобы использовать полученную выборку, необходимо ее куда-то сохранить.

Посмотрев, как это делается в Programmer's Guide и прочих TFM, делаю вывод, что используются таблицы, носящие временный характер и имеющие DRIVER('MSSQL').

({PROP:SQLFilter}, мне кажется, в данном случае не подходит - уж слишком сложные действия выполняются в UDF (или StoredProc) при выборке по параметрам)

Все работает, все замечательно, и тонкости программирования SQL и Clarion здесь не обсуждаются. Вопрос вот в чем.

Если эта "временная" таблица tempTable была создана в результате действий
пользователя на одной машине как результат выборки по одним параметрам - Param1, а другой пользователь в то же самое время приводит своими действиями к созданию ТОЙ ЖЕ таблицы, но с другим содержанием - результат выборки по другим параметрам - Param2 - это ведь потенциальный источник проблем?
Ведь два брауза, построенные по одной и той же таблице и выводить будут одно и тоже? То есть один из пользователей получит не то. что хотел!

Или же создавать такие временные таблицы отдельно для кадого пользователя?

СПАСИБО

--
Best regards,
Иван mailto:shkmail@inbox.ru


(Добавление)
Короче у меня явно не хватает знаний и опыта...
Архитектура корпоративных программных приложений. Мартин Фаулер
Издательство ВИЛЬЯМС. 2004.

Рекомендую.

С уважеием,
Олейников Виктор. ovv@inbox.ru

Здраствуйте, Иван!

Времменные таблицы создаются сервером для каждой сессии(соединения) свои и они не пересекаются, так что 2 разных пользователя получат только свой набор данных.

Вообще надо понимать, что любой запрос к серверу(для получения данных), приводит к созданию временной таблицы для результирующего набора данных, а уже потом отправляет получателю отобранные данные.

----------------------------
С уважением, Бирюков Александр

Написал: ClaList(2)
Гость

Сообщение Гость »

что такое #временнаяТаблица - это таблица, которая видна только в текущей сессии и грохается автоматически после завершения сессии, тут грабля может быть в другом, если один юзверь открыл ДВА раза Browse и выполнил загрузку с разными входными параметрами, тогда надо просто принять правило формирования имени временной таблицы, примерно так:

'TmpTable' & THREAD()

мне всё равно не до конца понятно зачем это надо, разве нельзя из ХП просто
вернуть результирующий SELECT, ну или результирующая выборка сложная и требует временной таблицы то в ХП сделать примерно следующее:

создали Временную таблицу
наполнили временную таблицу
SELECT ... FROM временная таблица
DROP Временная таблица

в результате на клиета попадёт именно результирующий SELECT

или хочется сделать полнофункциональный Browse, может Queue подойдёт?

Andrew Myalin
andrew@arsis.ru
http://mavcla.arsis.ru (MAV Direct ODBC)
ICQ: 10659412
Yahoo group: clarion@yahoogroups.com
Написал: ClaList(2)
Гость

Сообщение Гость »

Времменные таблицы создаются сервером для каждой сессии(соединения) свои и они не пересекаются, так что 2 разных пользователя получат только свой набор данных.
согласен, но в соответствии с тем, как я умудрился сделать это на Clarion:

Код: Выделить всё

udf_listObjPropVals{PROP:SQL} = 'DELETE FROM udf_listObjPropVals'

udf_listObjPropVals{PROP:SQL} = !
       'INSERT INTO udf_listObjPropVals SELECT
IDVal,IDObj,IDProp,Name,IDPropType,Type,Val,StartDT ' & !
       'FROM dbo.listObjPropVals_ALL(' & Objects.IDObj & ')'
результаты выборки попадают в одну и туже таблицу
Вообще надо понимать, что любой запрос к серверу(для получения данных), приводит к созданию временной таблицы для результирующего набора данных, а уже потом отправляет получателю отобранные данные.
вот я и не знаю - как сохранить эти временные данные через
...{PROP:SQL} = 'SELECT ...'?
ведь тут надо указать именно таблицу MSSQL (по крайней мере именно так указано в хелпе) а она заводится по умолчанию на том сервере с которым установил соединение.

или использовать таблицы, размещенные локально и отдельно настраивать для них "источник данных ODBC"?

но это тоже проблему не снимает, поскольку и на одно и том же компе в принципе могут вращаться несколько экземпляров программы, а про многопоточность и говорить не приходится

--
Best regards,
Иван
результаты выборки попадают в одну и туже таблицу
Если уж хоцца так извратно получать результат из ХП - то можно конечно же. Правда об уникальности таблицы нужно заботиться самостоятельно.
Т.е. как минимум привязаться к ID усера и номеру потока. Привязка к ID усера - идея не лучшая (могут с разных станциый входить под одним логином). Я бы сделал превязку к имени компа - это гарантирует уникальность "коннекта".
вот я и не знаю - как сохранить эти временные данные через
...{PROP:SQL} = 'SELECT ...'?
А о каком сохранении ты говоришь? Скорее всего ты просто не очень представляешь о чем речь шла. Ты пишешь свою ХП, которая так или иначе готовит временную локальную таблицу (поддержка "уникальности" данной таблицы - забота сервера) - такая таблица должна иметь имя, начинающееся со знака '#'. Готовит - означает удаляет на старте ХП если существует такая, создает новую, наполняет ее нужным тебе содержимым и в самом конце делает выборку из данной таблицы и удаляет временную таблицу. Вот и все...
А потом ты просто вызываешь эту ХП у себя в проге, используя таблицу с подходящей структурой для выгребания результата запроса.

--
Best regards,
Vadym mailto:vadim@softcreator.com
ICQ: 82308757

(Добавление)

Hello Иван,

Код: Выделить всё

DELETE
 FROM udf_listClassName

 INSERT INTO udf_listClassName
         SELECT *
         FROM listClassName(<параметры>)
сейчас сделано так:

Код: Выделить всё

udf_listObjPropVals{PROP:SQL} = 'DELETE FROM udf_listObjPropVals'

udf_listObjPropVals{PROP:SQL} = !
       'INSERT INTO udf_listObjPropVals SELECT IDVal,IDObj,IDProp,Name,IDPropType,Type,Val,StartDT ' & !
       'FROM dbo.listObjPropVals_ALL(' & Objects.IDObj & ')'
эти два оператора выполняются у меня каждый раз, когда меняется параметр - Objects.IDObj, соответственно меняется содержимое таблицы.

но таблица udf_listObjPropVals - это таблица MSSQL сервера, имеется в единственном экземпляре.
использование двух одинаковых программ с тем кодом, что я привел выше, приводит к искажению данных, если у двух пользователей имеются разные параметры - Objects.IDObj.
это заметно, например, при прокрутке Browse - содержание одной выборке "плавно дополняется" записями из другой выборки.

пока у меня две идеи:
1. либо создавать для каждого запроса новую таблицу с уникальным именем а потом ее удалять
2. либо после получения данных перебрасывать их в локальную таблицу, либо с ODBC-драйвером, либо другим

(
вроде как в том cлучае, если будет ODBC, будет проще перебросить
простым
tempTable{PROP:SQL} = 'SELECT ... FROM udf_listObjPropVals'
)
'TmpTable' & THREAD()
Вот это, кстати идея! У меня была мысль именовать таблицы по ID пользователя, но Вы предложили более радикальное решение!
или хочется сделать полнофункциональный Browse, может Queue подойдёт?
очень хочется :)

а по поводу Queue - это просто подсунуть List вместо Queue, созданной автоматически (как в случае Browse), очередь, созданную вручную?
То есть после того, как сделана выборка, перегнать содержание временного файла в Queue и работать дальше только с ней?

Я где-то так уже делал - придется много писать вручную...

В общем, СПАСИБО за целых две идеи!!!
Первая - некрасивая, вторая нудная, но завтра буду пробовать.
:))))))

--
Best regards,
Иван
Написал: ClaList(2)
Гость

Сообщение Гость »

Наверное, будет в тему.
Я сейчас использую такую схему построения отчетов. Не SQL, но, думаю, это не важно.
В словаре объявляется временная таблица с переменным именем и одним полем ID.
Эта таблица создается в индивидуальном каталоге пользователя и открывается с монопольным доступом. Специальный шаблон ищет первое свободное имя xxx.tps для временной таблицы при входе в окно отчета, а при завершении работы с отчетом удаляет временную таблицу.
Итоги формируются в локальную очередь, затем номера строк записываются в ID временной таблицы. Это позволяет использовать все наработки для стандартных Browse (поиск, фильтр, итоги и расшифровки колонок и т.п.) и не прописывать в словаре структуру таблицы конкретного отчета.
Промежуточные заголовки групп и итоги выделяются стилем.
Окно шаблона имеет две (редко больше) закладки. На одной задаются параметры отчета, на второй показывается итоговый Browse.
Отдельные шаблоны отвечают за:
1. Сохранение и восстановление параметров отчета, как одиночных, так и списковых - а-ля 1С.
2. Вызов отчета в автоматическом режиме, например, из другого отчета.
3. Сохранение и восстановление формата Browse с возможностью выбора сохраненных ранее вариантов.
4. Кнопка расшифровки отчета, позволяющая запустить в отдельном потоке отчет-расшифровку или открыть форму документа.

Для печати Browse используется сильно переделанный под себя шаблон "печать
как есть" от Сергея Павлова (как мне показалось, с "буржуйскими корнями").
Этот шаблон позволяет автоматически разворачивать лист в ландшафт и разбивать на страницы по горизонтали. Доделывать пришлось перенос длинных строк, разделение строк линией, передачу стиля для выделения внутренних заголовков и итогов и прочие мелочи, связанные с внутренним стандартом оформления отчетов.
Для вывода в Excel используется шаблон и класс DirectExcel Олега Руденко, доработанный на предмет передачи стилей для внутренних заголовков и итогов групп.
Дополнительная возможность - вывод в текстовый формат и CSV, также переделанный шаблон Олега.

Такой подход покрывает основную массу отчетов и позволяет на основе однажды сделанной мастер-процедуры очень быстро разрабатывать итоговый отчет - остается, как правило, расставить параметры и поля в List и написать рутинки заполнения локальной очереди и вызова расшифровки.
Еще можно отметить, что многие отчеты имеют типовые формы. Это позволяет создавать дополнительные заготовки (взаиморасчеты, карточка товара и т.п.), а затем импортировать их в заказное приложение с минимальной адаптацией или совсем без нее.
Пользователи, привыкшие к интерфейсу 1С, реагируют вполне положительно, т.к наиболее востребованный функционал перекрывается, а скорость формирования несопоставимо выше.

С уважением,
Вячеслав Черников support@finsoft.ryazan.ru

Код: Выделить всё

udf_listObjPropVals{PROP:SQL} = 'DELETE FROM udf_listObjPropVals'

 udf_listObjPropVals{PROP:SQL} = !
        'INSERT INTO udf_listObjPropVals SELECT
IDVal,IDObj,IDProp,Name,IDPropType,Type,Val,StartDT ' & !
        'FROM dbo.listObjPropVals_ALL(' & Objects.IDObj & ')'
RTFM, RTFM и еще раз RTFM. Если не поможет повторить до просветления.
(
вроде как в том cлучае, если будет ODBC, будет проще перебросить простым
tempTable{PROP:SQL} = 'SELECT ... FROM udf_listObjPropVals'
)
3. Поставить перед именем таблицы #.
4. Работать непосредственно с набором, который возвращает функция. Типа:
udf_listObjPropVals{PROP:SQL} = 'SELECT
IDVal,IDObj,IDProp,Name,IDPropType,Type,Val,StartDT ' & !
'FROM dbo.listObjPropVals_ALL(' & Objects.IDObj & ')'
Правда редактировать эти записи через стадартную форму не получится.
Придется сделать отдельную функцию на добавление/исправление/удаление записей. И вызывать ее (через PROP:SQL) вместо стандартных процедур.

С уважением, Алексей Каминский
Нач. отд. АСУ ЖБК100
3. Поставить перед именем таблицы #.
ну, если я правильно понял, то в самом SQL это делается так:
--------------------

Код: Выделить всё

DROP TABLE #udf_listObjPropVals

SELECT IDVal,IDObj,IDProp,Name,IDPropType,Type,Val,StartDT 
INTO #udf_listObjPropVals 
FROM dbo.listObjPropVals(1, @DT)

SELECT * FROM #udf_listObjPropVals
DROP TABLE #udf_listObjPropVals
--------------------
и это понятно...

а вот
4. Работать непосредственно с набором, который возвращает функция. Типа:
udf_listObjPropVals{PROP:SQL} = 'SELECT
IDVal,IDObj,IDProp,Name,IDPropType,Type,Val,StartDT ' & !
'FROM dbo.listObjPropVals_ALL(' & Objects.IDObj & ')'
не совсем - пункт 4 - альтернатива пункту 3, или их необходимо выполнять одновременно?

--
Best regards,
Иван

(Добавление)

Hello Vadym,

Вот так я делаю это в Query Analyzer:
------------------------------------
USE Serteko

DECLARE @DT DATETIME
SET @DT = GETDATE()

DROP TABLE #udf_listObjPropVals

SELECT IDVal,IDObj,IDProp,Name,IDPropType,Type,Val,StartDT
INTO #udf_listObjPropVals
FROM dbo.listObjPropVals(1, @DT)

SELECT * FROM #udf_listObjPropVals

DROP TABLE #udf_listObjPropVals
------------------------------------

а вот так я пытаюсь сделать это в Кларионе:
----------------------------------------------
dummySQL{PROP:SQL} = !
'SELECT IDVal,IDObj,IDProp,Name,IDPropType,Type,Val,StartDT ' & !
'INTO #udf_listObjPropVals ' & !
'FROM dbo.listObjPropVals(' & Objects.IDObj & ', ' & CLIP(todayStr) &')'
----------------------------------------------

при этом udf_listObjPropVals - таблица, на основе которой строится Browse, она объявлена в словаре как MSSQL.
А потом ты просто вызываешь эту ХП у себя в проге, используя таблицу с подходящей структурой для выгребания результата запроса.
вот я и не понимаю - куда можно "выгрести результат запроса", чтобы его можно было просмотреть с помощью стандартного Browse?

я могу объявлять временные таблицы в словаре Clarion-а?
если да, то имя должно включать '#'?
судя по тому, как работает пример в Query Analyzer - должно!
иначе этот пример не работает.

а если я создал Browse для этой таблицы, то при открытии окна (видимо CheckOpen) возмущается, что файл
"#udf_..." или "dbo.#udf_..." или "dbo.udf_..." не найден!

ничего не понимаю...
вопрос не в том, как выгрести, а куда выгрести!
могу ли я развернуть Browse на основе временной (# - для SQL Server-а) таблицы?

--
Best regards,
Иван

(Добавление)

Код: Выделить всё

 DROP TABLE #udf_listObjPropVals

 SELECT IDVal,IDObj,IDProp,Name,IDPropType,Type,Val,StartDT
 INTO #udf_listObjPropVals
 FROM dbo.listObjPropVals(1, @DT)

 SELECT * FROM #udf_listObjPropVals
 DROP TABLE #udf_listObjPropVals
--------------------
и это понятно...
Похоже не совсем.
Надо так:

Код: Выделить всё

udf_listObjPropVals{PROP:SQL} = 'DROP TABLE #udf_listObjPropVals'
udf_listObjPropVals{PROP:SQL} = !
        'INSERT INTO #udf_listObjPropVals SELECT
 IDVal,IDObj,IDProp,Name,IDPropType,Type,Val,StartDT ' & !
        'FROM dbo.listObjPropVals_ALL(' & Objects.IDObj & ')'
И, соответственно, в описании таблицы udf_listObjPropVals аттрибут Full PathName поставить равным #udf_listObjPropVals. Или добавить:
udf_listObjPropVals{PROP:SQL} = ' SELECT * FROM #udf_listObjPropVals '
Только Insert надо делать до Open таблицы. Дальше сервер сам разруливать все будет.

Написал: ClaList(2)
Гость

Сообщение Гость »

Сделай так:

после всех твоих PROP:SQL добавь
udf_listObjPropVals{PROP:SQL} =
'SELECT IDVal,IDObj,IDProp,Name,IDPropType,Type,Val,StartDT FROM #udf_listObjPropVals '
Или воспользуйся пунктом 4 вместо всего вышеперечисленного (что, впрочем,
делает тоже самое, только не явно).

С уважением, Алексей Каминский
PS: я так делал.

Код: Выделить всё

USE Serteko

 DECLARE @DT     DATETIME
 SET @DT = GETDATE()

 DROP TABLE #udf_listObjPropVals

 SELECT IDVal,IDObj,IDProp,Name,IDPropType,Type,Val,StartDT 
 INTO #udf_listObjPropVals 
 FROM dbo.listObjPropVals(1, @DT)

 SELECT * FROM #udf_listObjPropVals

 DROP TABLE #udf_listObjPropVals
И что - неужто работает?!
Происходит вставка в несуществующую таблицу?!
Вообще-то нужно ее создать перед тем, как делать INSERT.
И удалять в самом начале нужно условно - если таблица существует:
IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '#udf_listObjPropVals')
DROP TABLE #udf_listObjPropVals
при этом udf_listObjPropVals - таблица, на основе которой строится Browse, она объявлена в словаре как MSSQL.
Не совсем понятно, что это должно делать.
Имело в виду - в ХП готовится некая выборка во временной таблице и в конце-концов в ней выполняется запрос на получение содержимого этой временной таблицы (т.е. по сути то, что написано выше).
А в клаше нужно просто вызывать эту ХП и вытащить результат финального запроса ХП (SELECT * FROM #udf_listObjPropVals) обычными NEXT-ами - как это описано в хелпе.
вот я и не понимаю - куда можно "выгрести результат запроса", чтобы его можно было просмотреть с помощью стандартного Browse?
Никуда. Влегкую ты сможешь сделать просмотр выборки используя клашин шаблон BrowseBox только для запроса по sql view (но как я понял твои запросы через view не реализуемы - бывает и такое, хотя я не уверен что у тебя именно такой случай).
судя по тому, как работает пример в Query Analyzer - должно!
иначе этот пример не работает.
читай вышенаписанное. никакие временные таблицы на клаше тебе не нужны.
тебе нужна таблица, совпадающая по структуре с результатом выборки из временной таблицы (например SELECT * FROM #udf_listObjPropVals)
а если я создал Browse для этой таблицы, то при открытии окна (видимо CheckOpen) возмущается, что файл
"#udf_..." или "dbo.#udf_..." или "dbo.udf_..." не найден!
см.выше.
ничего не понимаю...
вопрос не в том, как выгрести, а куда выгрести!
вопрос не в этом. вопрос в том, что нет понимания прнципов работы клашиного драйвера - а это в хелп...
могу ли я развернуть Browse на основе временной
(# - для SQL Server-а) таблицы?
нет.

--
Best regards,
Vadym

(Добавление)
И что - неужто работает?!
Происходит вставка в несуществующую таблицу?!
Вообще-то нужно ее создать перед тем, как делать INSERT.
Вобще-то данная форма оператора select именно создает таблицу и помещает в нее набор записей возвращаемый выражением select (примерный перевод из SQL Books online) . А если таблица уже существует, то будет ошибка.

С уважением, Алексей Каминский

Не знал - буду иметь в виду. Но суть проблемы от этого не меняется ;)

--
Best regards,
Vadim
Написал: ClaList(2)
Ответить