MAV Direct ODBC
Модератор: Andrew™
Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion и MAV который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion и MAV который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
FREE LIKE режим в конструкторе фильтров
Новый режим добавлен в конструктор фильтров - FREE LIKE, что означает что введённая конструкция подставляется в LIKE ? as is, единственно введён контроль на длину ввода , если введённое значение больше размера поля в БД по которому производится поиск, введённое значение обрезается до размера поля в БД и вместо LIKE в WHERE конструкцию попадёт обычное сравнение Field=?, иначе просто будет ошибка биндования.
Мелочь, а приятно
неоднократно меня спрашивали - а есть ли шаблон который контролирует количество одновременно запущенных оконных процедур в программе, с целью запрета запуска определённого количеста таких процедур и активацией уже открытого окна
я всё отмахивался, наверняка что то похожее есть и в ABCFree, зачем спрашивается изобретать велосипед. А вот сегодня разродится и сделал.
я всё отмахивался, наверняка что то похожее есть и в ABCFree, зачем спрашивается изобретать велосипед. А вот сегодня разродится и сделал.
MAVSelect
тут одну фичу заметил
декларируем курсор
хотим вытащить только одну запись
но далее, если не сделать принудительно tmp.Reset() или tmp.Reset(1) курсор не закрывался на сервере, он продолжал жить пока живёт объект tmp, в деструкторе закрывается.
самое интересное что на MSSQL 2000 ресурс под курсор на сервере автоматом закрывается, т к заказали 1 запись и уже получили 1 запись, и нет смысла держать откытым ресурс
библиотека подрихтована на тему если заказали определённое количество записей и читаем последнюю (ошибки нет, т к по ошибке происходит закрытие) закрываем принудительно курсор
декларируем курсор
Код: Выделить всё
tmp MAVSelect
Код: Выделить всё
tmp.Init(1,1)
tmp.BindFields(File)
IF NOT tmp.Run()
IF NOT tmp.Fetch()
! Вытащили
END
END
но далее, если не сделать принудительно tmp.Reset() или tmp.Reset(1) курсор не закрывался на сервере, он продолжал жить пока живёт объект tmp, в деструкторе закрывается.
самое интересное что на MSSQL 2000 ресурс под курсор на сервере автоматом закрывается, т к заказали 1 запись и уже получили 1 запись, и нет смысла держать откытым ресурс
библиотека подрихтована на тему если заказали определённое количество записей и читаем последнюю (ошибки нет, т к по ошибке происходит закрытие) закрываем принудительно курсор
-
- Бывалый
- Сообщения: 70
- Зарегистрирован: 07 Июль 2005, 5:39
- Откуда: Хабаровск
- Контактная информация:
Автоинкрементные поля
Вот еще проблема:
У таблицы есть автоинкрементное поле, в словаре ставлю у него Read only.
Так вот если в Init value прописать SELECT @@IDENTITY - все работает, а если Select SCOPE_IDENTITY( ) то нет. В трассе селект отрабатывает но значение поля = 0.
Хочется иметь возможность иметь значение поля с помощью SCOPE_IDENTITY( ), т.к. возможно использование триггеров с добавлением записей в другие таблицы с автоинкрементным полем
У таблицы есть автоинкрементное поле, в словаре ставлю у него Read only.
Так вот если в Init value прописать SELECT @@IDENTITY - все работает, а если Select SCOPE_IDENTITY( ) то нет. В трассе селект отрабатывает но значение поля = 0.
Хочется иметь возможность иметь значение поля с помощью SCOPE_IDENTITY( ), т.к. возможно использование триггеров с добавлением записей в другие таблицы с автоинкрементным полем
Re: Автоинкрементные поля
Этот вопрос неодократно подымался, 100% решения получения значенния IDENTITY поля после добавления никто не предложил, вероятность, что через волшебные SELECTы можно получить значения IDENTITY полей <= 100%. В твоём случае Select SCOPE_IDENTITY( ) врозвращает именно НОЛЬ, не считаю это проблемой библиотеки, что заказали то и получили.Денис писал(а):Вот еще проблема:
У таблицы есть автоинкрементное поле, в словаре ставлю у него Read only.
Так вот если в Init value прописать SELECT @@IDENTITY - все работает, а если Select SCOPE_IDENTITY( ) то нет. В трассе селект отрабатывает но значение поля = 0.
Хочется иметь возможность иметь значение поля с помощью SCOPE_IDENTITY( ), т.к. возможно использование триггеров с добавлением записей в другие таблицы с автоинкрементным полем
-
- Бывалый
- Сообщения: 70
- Зарегистрирован: 07 Июль 2005, 5:39
- Откуда: Хабаровск
- Контактная информация:
Re: Автоинкрементные поля
Помоему сдесь было только твое предложение по поводу Indentity полей - завести отдельную таблицу и самим вычислять очередное значение автоинкремента, а думаю что это неправельно. У сервера есть стандартные средства получения этого значения, их собственно 3. Это SELECT @@IDENTITY, SELECT SCOPE_IDENTITY() и SELECT IDENT_CURRENT('имя таблицы'). Подробно о них можно почитать в BOL.Andrew Myalin писал(а):Этот вопрос неодократно подымался, 100% решения получения значенния IDENTITY поля после добавления никто не предложил, вероятность, что через волшебные SELECTы можно получить значения IDENTITY полей <= 100%. В твоём случае Select SCOPE_IDENTITY( ) врозвращает именно НОЛЬ, не считаю это проблемой библиотеки, что заказали то и получили.Денис писал(а):Вот еще проблема:
У таблицы есть автоинкрементное поле, в словаре ставлю у него Read only.
Так вот если в Init value прописать SELECT @@IDENTITY - все работает, а если Select SCOPE_IDENTITY( ) то нет. В трассе селект отрабатывает но значение поля = 0.
Хочется иметь возможность иметь значение поля с помощью SCOPE_IDENTITY( ), т.к. возможно использование триггеров с добавлением записей в другие таблицы с автоинкрементным полем
Что значит "SELECTы можно получить значения IDENTITY полей <= 100%" ? Получается чтобы получить 100% нужно заводить для добавления ХП ? Или как ?
Re: Автоинкрементные поля
я приведу лишь цитаты большой переписки на эту темуДенис писал(а):Andrew Myalin писал(а):Денис писал(а):Вот еще проблема:
У таблицы есть автоинкрементное поле, в словаре ставлю у него Read only.
Так вот если в Init value прописать SELECT @@IDENTITY - все работает, а если Select SCOPE_IDENTITY( ) то нет. В трассе селект отрабатывает но значение поля = 0.
> А пробовал ли уважаемый получить значение SCOPE_IDENTITY() из Клариона
> после выполнения ADD(File)? Результатом всегда будет 0, полскольку запрос
> будет уже в другом скопе!
Да, так и будет.
ТШ> Все правильно, если использовать IDENT_CURRENT , поскольку он
ТШ> возвращает последний Indentity таблицы во всех сессиях и скопах,
ТШ> чтобы получить, именно то, что нужно, надо использовать
ТШ> Scope_Indentity(), но вот из
ТШ> Клариона это сделать не получится
потому что это надо делать в одном пакете, т е как уже тут говорилось INSERT
засовывать в ХП,
а ХП будет возвращать новое ID через Scope_Identity()
Вопрос исключительно от полного непонимания (незнания?) SQL-технологий.
В частности - алгоритмов работы SQL-сервера. Объясняю на пальцах, как для
второго курса: операция SQL INSERT выполняет только помещение передаваемых
значений в хранилище. Алгоритм следующий:
1. Прочитать значение Identity-поля из системной таблицы и увеличить на
заданное
значение.
2. Присвоить значение Identity-полю и всем Default-полям.
3. Добавить запись.
Все. Никакого перечитывания. Возвращает только ошибку.
Как же выкручиваются все разработчики? Заменой Insert на соответствующую
хранимую процедуру примерно такого типа:
--=======================================
CREATE PROCEDURE DisciplinaInsert
(@Creator int, @IUMU_Dis_code int = NULL, @IDis_Name varchar(500) = NULL)
AS
BEGIN
SET NOCOUNT ON
DECLARE @SID int, @LDateTime datetime
-- Добавляем
INSERT INTO Disciplina (UMU_Dis_code,
Dis_Name,
StartDate,
EndDate)
VALUES(@IUMU_Dis_code,
@IDis_Name,
DEFAULT,
DEFAULT)
IF @@Error = 0
BEGIN
SET @SID = SCOPE_IDENTITY()
RETURN @SID
END
ELSE
RETURN -1
END
--=====================================
Использовать необходимо именно SCOPE_IDENTITY(), а не @@IDENTITY.
Т.к. значение глобальной переменной @@IDENTITY может быть изменено
из другой сессии.
Re: Автоинкрементные поля
Ещё нашёлся самый умный, ну раз я предлагаю неправильно, почему у тебя , где всё есть правильно, возникают проблемы на пустом месте?Денис писал(а): Помоему сдесь было только твое предложение по поводу Indentity полей - завести отдельную таблицу и самим вычислять очередное значение автоинкремента, а думаю что это неправельно. У сервера есть стандартные средства получения этого значения, их собственно 3. Это SELECT @@IDENTITY, SELECT SCOPE_IDENTITY() и SELECT IDENT_CURRENT('имя таблицы'). Подробно о них можно почитать в BOL.
хочешь использование IDENTITY - не широко мыслишь, сам создаешь себе проблемы, а именно, придётся отказаться от штатных операций добавления INSERT, генерить на каждые такие таблицы ХП на INSERT, и не забывать при этом синхронизировать их при изменении структуры в БД, и их соответсвующие вызовы в программе, это раз
два - забудь при таком подходе про репликации данных, если таковые когда нибудь потребуются, а они в конце концов потребуются, фирма, филиалы и т д.
конечно можно остановится на SELECT @@IDENTITY, но при этом не забудь бубен прикупить для нештатных ситуаций.
если не тв хозяин в проектировке БД и есть такие таблицы то тут уж и в правду деваться не куда, придётся помучатся, если же ты сам хозяин в БД, то нахрена этот гемор?
с моей точки зрения IDENTITY это средство для ленивых, уж если ребятки введи такую возможность почему в той же самой доке по серваку напЫсано что в определённых задачах нельзя использовать IDENTITY механизмов.
-
- Бывалый
- Сообщения: 70
- Зарегистрирован: 07 Июль 2005, 5:39
- Откуда: Хабаровск
- Контактная информация:
Identity
По поводу примера, что ты привел. Его я не видел на форуме, так как вопросы разбросаны черте как по форуму. Я знаю что была большая переписка по этому поводу, но за ней не следил и была она давно.
Думал что с той поры что-то поменялось.
У себя я делал добавление через ХП, просто думал что с той поры что-то поменялось - вот и спросил.
Запрос SELECT ... для получения значения поля делается в другом scope из-за особенностей работы клары с таблицами, я так понимаю?
Думал что с той поры что-то поменялось.
У себя я делал добавление через ХП, просто думал что с той поры что-то поменялось - вот и спросил.
Запрос SELECT ... для получения значения поля делается в другом scope из-за особенностей работы клары с таблицами, я так понимаю?
Re: Identity
это не из за особенностей клары, уже вроде всё понятноДенис писал(а):Запрос SELECT ... для получения значения поля делается в другом scope из-за особенностей работы клары с таблицами, я так понимаю?
делай всё в одной ХП INSERT + получение IDENTITY
и возвращай в OUTPUT параметр
-
- Бывалый
- Сообщения: 70
- Зарегистрирован: 07 Июль 2005, 5:39
- Откуда: Хабаровск
- Контактная информация:
Re: Identity
Это понятно. Скажи как с наименьшими телодвижениями сделать чтоб при добавлении записи вызывалась ХП у нужными параметрами и т.д.это не из за особенностей клары, уже вроде всё понятно
делай всё в одной ХП INSERT + получение IDENTITY
и возвращай в OUTPUT параметр
Я делаю так: В шаблоне снимаю галку Incert, а в процедуре редактирования в класс ручками добавляю метод insert, в котором уже сам пишу то что мне нужно.[/quote]
Re: Identity
в шаблоне оставь всё как есть, просто OMIT на MAVINSERT поставь, хотя можно и как тыДенис писал(а):Это понятно. Скажи как с наименьшими телодвижениями сделать чтоб при добавлении записи вызывалась ХП у нужными параметрами и т.д.это не из за особенностей клары, уже вроде всё понятно
делай всё в одной ХП INSERT + получение IDENTITY
и возвращай в OUTPUT параметр
Я делаю так: В шаблоне снимаю галку Incert, а в процедуре редактирования в класс ручками добавляю метод insert, в котором уже сам пишу то что мне нужно.
как правильно и всегда правильно пробиндить все поля в ХП, т к имеют место быть OVER поля, то тут нужна определённая логика, которая заложена в библиотеке и которой можно воспользоваться.
Код: Выделить всё
в MAV:Save.Insert декларируешь
tmp MAVSelect
sql MAVExecSP
CODE
tmp.BindFields(File)
! биндуем все поля записи продекоарированные в DCT
loop i# = 1 to records(tmp.QCol)
get(tmp.QCol,i#)
DbFiles.Manager.QReadOnly.hField = tmp.QCol.AdrField
GET(DbFiles.Manager.QReadOnly,DbFiles.Manager.QReadOnly.hField)
IF ERRORCODE()
sql.BindParameter(tmp.QCol.Field)
END
end
! биндуем OUTPUT доп параметр для получения нового ID первичного поля
sql.BindParameter(File.IdentityField,SQL_PARAM_OUTPUT)
IF sql.Run('myInsertToTable')
MAVSHOWERROR
RETURN 1
END
RETURN 0
Re: Identity
Код: Выделить всё
можно попробовать ещё проще, без ХП но в одном скопе
в MAV:Save.Insert декларируешь
str MAVSTring
str2 MAVSTring
tmp MAVSelect
sql MAVExecSP
CODE
tmp.BindFields(File)
! биндуем все поля записи продекоарированные в DCT
j# = 0
loop i# = 1 to records(tmp.QCol)
get(tmp.QCol,i#)
DbFiles.Manager.QReadOnly.hField = tmp.QCol.AdrField
GET(DbFiles.Manager.QReadOnly,DbFiles.Manager.QReadOnly.hField)
IF ERRORCODE()
sql.BindParameter(tmp.QCol.Field)
str.AppendString(CHOOSE(j#=0,'',',') & '?')
str2.AppendString(CHOOSE(j#=0,'',',') & tmp.Field(SELF.QCol.Field))
j# += 1
END
end
! биндуем OUTPUT доп параметр для получения нового ID первичного поля
str.AppendString(CHOOSE(j#=0,'',',') & '?')
sql.BindParameter(File.IdentityField,SQL_PARAM_OUTPUT)
IF sql.Run('BEGIN insert into ' & MAVTABLENAME(File) &|
'(' & str2.S[1 : str2.Pos] & ') values(' & str.S[1 : str.Pos] & ') ' &|
?= SELECT SCOPE_IDENTITY() END'
MAVSHOWERROR
RETURN 1
END
RETURN 0