Страница 1 из 1

Добавлено: 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 это не указано. Сейчас над этим поработаю.
кстати, имело бы смысл указать драйверок.....
Да, конечно же, забыл указать драйверок. Это 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) вернет общее кол-во записей в этой выборке.

=============================
С уважением, Олег А. Руденко

Действительно неверный :( . У меня есть фрагмент из старой программы, где я таким образом строил Progress. Там крутится, проверил.
Для драйверов 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


(Добавление)
Заведомо быстрее просто пересчитать.
Заведомо ли? Всё-таки драйвер имеет возможность всё это дело оптимизировать. И просмотреть только интересующие поля.
"The dynamic INDEX is created as a temporary file"
Ага. Created :)
Тогда уж лучше объявить вьюшку по имеющемуся ключу с фильтром и посмотреть сколько в ней будет записей.
Гы... 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)