Добавлено: 14 Апрель 2004, 17:35
Здравствуйте всем!
C55H, ABC
Есть таблица с числовым полем (LONG), по которому создан ключ (нули не исключаются). Известно, что поле может принимать только неотрицательные значения. Как подсчитать количество записей с положительными значениями?
Варианты решения (может быть - не все):
1. Создать дополнительный ключ с крыжиком "Exclude nulls", а далее
RECORDS(<доп ключ>).
2. Конструкция LOOP ... END по таблице и тупо считать.
А можно ли вытащить порядковый номер записи по ключу? Тогда бы можно было применить конструкцию:
поле = 1
SET(<исходный ключ>,<исходный ключ>), вытащить первую запись с положительным значением, вытащить ее порядковый номер по ключу. Дальше все просто:
RECORDS(<исходный ключ>) - <порядковый номер> + 1.
Пробовал через Pointer(<исходный ключ>), который вроде бы specifies the entry order within the KEY or INDEX file. Но у меня ничего не получилось.
Чего делаю не так и можно ли вообще это реализовать? А может быть есть более рациональные решения?
Заранее благодарен.
Семен Попов <oit_svp@opfr.komi.com>
(Добавление)
Было-бы еще неплохо указать драйвер!
Для любого драйвера можно воспользоваться вариантом с Records(Key), если ключ содержит только одно поле и включен режим исключения нулевых записей.
Для Clarion-драйвера (DAT-файлы) можно использовать вышеописанный алгоритм с Pointer(Key). Таким образом, кстати, очень удобно определять кол-во записей при ограничении по диапазону.
Для TopSpeed-драйвера (TPS-файлы) этот алгоритм не пройдет - там немного другая структура ключей.
Для других драйверов - не знаю, возможно подскажут коллеги.
=============================
С уважением, Олег А. Руденко.
Oleg_Rudenko@mail.ru
Oleg_Rudenko@mail333.com
Библиотека DynaLib
http://dynalib.narod.ru
RECORSD(<кключ о этому полю>) = количество уникальных значений в ключе, кстати, имело бы смысл указать драйверок.....
С уважением, Ставич Олег
Укрсиббанк г.Харьков
oldstav@ukrsibbank.com
А если ключ не уникальный? Никогда раньше не экспериментировал с RECORDS(<ключ>), чтобы убедиться в этом на деле. Но в Manual к CW4.0 это не указано. Сейчас над этим поработаю.
Семен Попов
Как палиативный вариант:
Вводишь еще одну таблицу, где будет указано требуемое количество записей.
При всех операциях изменения/дополнения/удаления в основную таблицу сразу корректируешь значение во вспомогательной. Таким образом ты всегда и сразу знаешь итоговую цифру.
------------------------------------------------------------
Igor Gubin (igor@quantor.com)
Quantor-Soft Metall
Phone/Fax: (+7 095) 234 4905
WEB: http://www.metaldata.info
http://www.metaldata.ru
(Добавление)
Просто подсчитай, используя имеющийся ключ, сколько у тебя записей с 0-ым полем и вычти это из RECORDS(file). Ну а если ненулевых меньше, чем нулевых, то только прямой пересчет либо с конца, либо сделав set на первое ненулевое поле. Если это сиквел, то считать не циклом, а соотв. SELECT-ом.
WBR, Nick Tsigouro. MailTo:Nick@arsis.ru
Конечно, спасибо. Но когда в таблице много записей, причем нельзя ни из каких условий предположить, каких записей будет больше либо меньше, то данная процедура подсчета будет выполняться сравнительно долго.
Семен Попов
---------------------------------------
C уважением,
Юрий Философов,
Главный программист
Корпорация "Диполь", Саратов
E-mail yufil@tacis-dipol.ru (служ)
yufil@mail.ru (дом)
ICQ#75924439
Спасибо всем за исчерпывающие ответы, но хотел бы подробнее разобраться в ответе Юрия Философова.
Итак, еще раз: C55H, драйвер: TopSpeed; ключ: не уникальный, допускающий нули; поле может принимать только неотрицательные значения.
Я так понял, что Юра имеет в виду следующее:
Но итог все равно неверный.
С уважением, Семен
(Добавление)
Ты внимательно читаешь ответы на свои вопросы?
Или видишь только те, которые хочешь увидеть!?
Я же, кажеться, ясно написал - для TPS-драйвера вышеописанный алгоритм НЕПРИМЕНИМ!
Этот алгоритм работает ТОЛЬКО с DAT-дравером.
Ну и, возможно, еще с DBF-драйверами.
Если так уж сильно надо посчитать кол-во ненулевых записей, то самым быстрым вариантом для TPS-драйвера будет создание VIEW с нужным условием фильтра. И еще не забудь, что необходимо для этой VIEW задать отдельный порядок сортировки, в котором НЕЛЬЗЯ использовать ключевые поля.
Т.е., грубо говоря, задай для этой VIEW "левую" сортировку по какому-либо неключевому полю.
Тогда, после открытия этой VIEW, RECORDS(View) вернет общее кол-во записей в этой выборке.
=============================
С уважением, Олег А. Руденко
Действительно неверный
. У меня есть фрагмент из старой программы, где я таким образом строил Progress. Там крутится, проверил.
Для драйверов Clarion и Dbf работает 100%.
Тогда самый быстрый путь - построение динамического индекса
В базе данных объявить динамический индекс, а в программе написать
Build(File:Dynam,'+File:Field','File:Field>0')
Return(Records(File:Dynam))
---------------------------------------
C уважением,
Юрий Философов
Ну еще бы! Там POINTER дает дает порядковый номер записи в порядке сортировки (по файлу - физический) С тех пор (с введением других фооматов) POINTER признан устаревшим и к применению не рекомендуется. Рекомендуется вместо него использовать POSITION, но в данном вопросе это ни чего не дает.
В общем, отождествлять POINTER с номером записи неправильно, хотя для dat и dbf это так.
"The dynamic INDEX is created as a temporary file"
Тогда уж лучше объявить вьюшку по имеющемуся ключу с фильтром и посмотреть сколько в ней будет записей.
WBR, Nick Tsigouro
(Добавление)
Всё равно читать придётся. И выполнить много-много операций Next... А что быстрее - одна операция или много?
Зато всего две строки текста
---------------------------------------
C уважением,
Юрий Философов
WBR, Nick Tsigouro
Спасибо, ребята. Вопрос исчерпан. Попробую все варианты.
С уважением, Семен
Написал: ClaList(2)
C55H, ABC
Есть таблица с числовым полем (LONG), по которому создан ключ (нули не исключаются). Известно, что поле может принимать только неотрицательные значения. Как подсчитать количество записей с положительными значениями?
Варианты решения (может быть - не все):
1. Создать дополнительный ключ с крыжиком "Exclude nulls", а далее
RECORDS(<доп ключ>).
2. Конструкция LOOP ... END по таблице и тупо считать.
А можно ли вытащить порядковый номер записи по ключу? Тогда бы можно было применить конструкцию:
поле = 1
SET(<исходный ключ>,<исходный ключ>), вытащить первую запись с положительным значением, вытащить ее порядковый номер по ключу. Дальше все просто:
RECORDS(<исходный ключ>) - <порядковый номер> + 1.
Пробовал через Pointer(<исходный ключ>), который вроде бы specifies the entry order within the KEY or INDEX file. Но у меня ничего не получилось.
Чего делаю не так и можно ли вообще это реализовать? А может быть есть более рациональные решения?
Заранее благодарен.
Семен Попов <oit_svp@opfr.komi.com>
(Добавление)
Было-бы еще неплохо указать драйвер!
Для любого драйвера можно воспользоваться вариантом с Records(Key), если ключ содержит только одно поле и включен режим исключения нулевых записей.
Для Clarion-драйвера (DAT-файлы) можно использовать вышеописанный алгоритм с Pointer(Key). Таким образом, кстати, очень удобно определять кол-во записей при ограничении по диапазону.
Для TopSpeed-драйвера (TPS-файлы) этот алгоритм не пройдет - там немного другая структура ключей.
Для других драйверов - не знаю, возможно подскажут коллеги.
=============================
С уважением, Олег А. Руденко.
Oleg_Rudenko@mail.ru
Oleg_Rudenko@mail333.com
Библиотека DynaLib
http://dynalib.narod.ru
RECORSD(<кключ о этому полю>) = количество уникальных значений в ключе, кстати, имело бы смысл указать драйверок.....
С уважением, Ставич Олег
Укрсиббанк г.Харьков
oldstav@ukrsibbank.com
А если ключ не уникальный? Никогда раньше не экспериментировал с RECORDS(<ключ>), чтобы убедиться в этом на деле. Но в Manual к CW4.0 это не указано. Сейчас над этим поработаю.
Да, конечно же, забыл указать драйверок. Это TopSpeed.кстати, имело бы смысл указать драйверок.....
Семен Попов
Как палиативный вариант:
Вводишь еще одну таблицу, где будет указано требуемое количество записей.
При всех операциях изменения/дополнения/удаления в основную таблицу сразу корректируешь значение во вспомогательной. Таким образом ты всегда и сразу знаешь итоговую цифру.
------------------------------------------------------------
Igor Gubin (igor@quantor.com)
Quantor-Soft Metall
Phone/Fax: (+7 095) 234 4905
WEB: http://www.metaldata.info
http://www.metaldata.ru
(Добавление)
Просто подсчитай, используя имеющийся ключ, сколько у тебя записей с 0-ым полем и вычти это из RECORDS(file). Ну а если ненулевых меньше, чем нулевых, то только прямой пересчет либо с конца, либо сделав set на первое ненулевое поле. Если это сиквел, то считать не циклом, а соотв. SELECT-ом.
WBR, Nick Tsigouro. MailTo:Nick@arsis.ru
Конечно, спасибо. Но когда в таблице много записей, причем нельзя ни из каких условий предположить, каких записей будет больше либо меньше, то данная процедура подсчета будет выполняться сравнительно долго.
Семен Попов
Угу. Определяем Pointer(Key) для первой ненулевой записи и Pointer(Key) для самого старшего ключа. А потом вычитаем один из другого и прибавляем 1. Для Topspeed разница может быть отрицательной, значит, надо брать модуль разности...Чего делаю не так и можно ли вообще это реализовать? А может быть есть более рациональные решения?
---------------------------------------
C уважением,
Юрий Философов,
Главный программист
Корпорация "Диполь", Саратов
E-mail yufil@tacis-dipol.ru (служ)
yufil@mail.ru (дом)
ICQ#75924439
Спасибо всем за исчерпывающие ответы, но хотел бы подробнее разобраться в ответе Юрия Философова.
Итак, еще раз: C55H, драйвер: TopSpeed; ключ: не уникальный, допускающий нули; поле может принимать только неотрицательные значения.
Я так понял, что Юра имеет в виду следующее:
Код: Выделить всё
Field = 1
SET(Key,Key)
NEXT(File)
IF ~ERRORCODE()
BPOS# = POINTER(Key)
STOP('Begin ' & BPOS#)
ELSE
BPOS# = 0
STOP(ERROR())
END
CLEAR(Field, 1)
SET(Key,Key)
PREVIOUS(File)
IF ~ERRORCODE()
EPOS# = POINTER(Key)
STOP('End ' & EPOS#)
ELSE
EPOS# = 0
STOP(ERROR())
END
STOP('Итог ' & ABS(BPOS# - EPOS#) + 1)
С уважением, Семен
(Добавление)
Ты внимательно читаешь ответы на свои вопросы?
Или видишь только те, которые хочешь увидеть!?
Я же, кажеться, ясно написал - для TPS-драйвера вышеописанный алгоритм НЕПРИМЕНИМ!
Этот алгоритм работает ТОЛЬКО с DAT-дравером.
Ну и, возможно, еще с DBF-драйверами.
Если так уж сильно надо посчитать кол-во ненулевых записей, то самым быстрым вариантом для TPS-драйвера будет создание VIEW с нужным условием фильтра. И еще не забудь, что необходимо для этой VIEW задать отдельный порядок сортировки, в котором НЕЛЬЗЯ использовать ключевые поля.
Т.е., грубо говоря, задай для этой VIEW "левую" сортировку по какому-либо неключевому полю.
Тогда, после открытия этой VIEW, RECORDS(View) вернет общее кол-во записей в этой выборке.
=============================
С уважением, Олег А. Руденко
Действительно неверный

Для драйверов Clarion и Dbf работает 100%.
Тогда самый быстрый путь - построение динамического индекса
В базе данных объявить динамический индекс, а в программе написать
Build(File:Dynam,'+File:Field','File:Field>0')
Return(Records(File:Dynam))
---------------------------------------
C уважением,
Юрий Философов
Ну еще бы! Там POINTER дает дает порядковый номер записи в порядке сортировки (по файлу - физический) С тех пор (с введением других фооматов) POINTER признан устаревшим и к применению не рекомендуется. Рекомендуется вместо него использовать POSITION, но в данном вопросе это ни чего не дает.
В общем, отождествлять POINTER с номером записи неправильно, хотя для dat и dbf это так.
Ну скажешь тоже. Отсортировать, что бы пересчитать. Заведомо быстрее просто пересчитать.Build(File:Dynam,'+File:Field','File:Field>0')
Return(Records(File:Dynam))
"The dynamic INDEX is created as a temporary file"
Тогда уж лучше объявить вьюшку по имеющемуся ключу с фильтром и посмотреть сколько в ней будет записей.
WBR, Nick Tsigouro
(Добавление)
Заведомо ли? Всё-таки драйвер имеет возможность всё это дело оптимизировать. И просмотреть только интересующие поля.Заведомо быстрее просто пересчитать.
Ага. Created"The dynamic INDEX is created as a temporary file"

Гы... For non-SQL file systems, if a KEY field is used in the VIEW's ORDER attribute, then RECORDS returns negative one (-1)Тогда уж лучше объявить вьюшку по имеющемуся ключу с фильтром и посмотреть сколько в ней будет записей.
Всё равно читать придётся. И выполнить много-много операций Next... А что быстрее - одна операция или много?
Зато всего две строки текста

---------------------------------------
C уважением,
Юрий Философов
Вот именно поэтому и думаю, что заведомо. Если бы не было записи, я бы еще посомневался. Действительно, внутренняя реализация легко м.б. эффективнее внешнего цикла.Ага. Created
Действительно облом-с Значит надо еще попробовать без ключа, но с фильтром или с новым ключом. Хотя из за фразы о необходимости строить собственный ключ для правильного результата лишнего тоже будет много сделано, но не будет создания ключевого файла. На этом д.б. выигрыш.Гы... For non-SQL file systems, if a KEY field is used in the VIEW's ORDER attribute, then RECORDS returns negative one (-1)
Да по любому все или почти все читать.Всё равно читать придётся. И выполнить много-много операций
WBR, Nick Tsigouro
Спасибо, ребята. Вопрос исчерпан. Попробую все варианты.
С уважением, Семен
Написал: ClaList(2)