Главная Форум Гостевая книга Ссылки О нас

















Документация

Советы

Разработка баз данных


Иерархические структуры...


Может у кого есть примеры или идеи как хранить иерархические структуры в базе данных. К примеру некую виртуальную файловую систему (типа вложенных папок). Желательно чтоб использовался язык триггеров и хранимых процедур. Структура из базы должна загружаться в компонент типа TTreeView Заранее благодарен!




Я делаю так:

Есть таблица Structure В ней три поля: Ресурс - autoInc, Владелец - integer, Значение - string Например
1 0 Root
2 1 FirstNode
3 1 SecondNode
4 1 ThirdNode
5 2 FisrtFirstSubNode
6 2 SecondFirstSubNode
7 3 SecondSubNode
8 4 FirstThirdSubNode
9 4 SecondThirsSubNode
Для отображения структуры в TreeView я поступаю так:

type TNodeData=record table:TDataset; resource,owner:integer; end;

(поле Table сделано для того чтобы в TreeView можно было отображать данные из различных таблиц типа Structure)

Затем в TreeView создается ветка

var
nodeData:^TNodeData;
node:TTreeNode;
new(nodeData);
nodeData.table:=table1;
nodeData.resource:=1nodeData.owner:=0;
node:=items.AddChild(nil,'Root');
node.data:=nodeData;

После чего достаточно перегрузить OnNodeExpanding - зная ресурс ветки которую мы распахиваем можно отфильтровать table1 - table1.Filter:='Владелец='+ресурс этой ветки table1.Filtered=true

while not table.EOF do
begin
и здесь делаем AddChild к распахиваемой ветке (создавая для каждой структуру TNodeData)

Примерно так, ну а вообще я могу поделится своим компонентом, пиши if u wish



Суммирование по деревьям


Может кто знает, какой-нибудь стандартный алгоритм суммирования по деревьям. Например есть дерево с n уровнями, сколько ветвей и сколько уровней я незнаю. Фактическое значения имеют только самые нижние уровни ветвей. Причем у каждой ветви может быть разное колличество уровней вложенности. Как скажем собрать сумму на кокой-нибудь средний уровень. Ну например если взять реестр Windows и значение каких-либо параметров сложить и получить сумму этих параметров для узла HKEY_CURRENT_USER.



Нужно использовать рекурсивные механизмы спуска по дереву и иметь метод определения наличия child узлов у текущего узла.
На примере TTreeView( идея)
GetResultForNode(node)) - ваша функция определения значения чего-либо для текущего узла.
function TDBTreeView.RecurseChilds(node: TTreeNode): double;
begin
while node <> nil do begin
if node.HasChildren then
Result := RecurseChilds(node.GetFirstChild);
Result := Result + GetResultForNode(node));
node := node.GetNextSibling;
end;
end;
function TDBTreeView.GetResult(curnode: TTreeNode;): double;
begin
Result := 0;
if curnode = nil then Exit;
Result := RecurseChilds(curnode.GetFirstChild);
end;

Эту идею можно распространить и на БД, естественно с написанием своих методов поиска child и навигации по ним. Более широкие возможности здесь в случае применения SQL-запросов. Но нужны специальные способы организации структуры, т.к. простейший, с использованием ID и PARENT не слишком функционален.



Как пронумеровать выбранные записи в SQL запросе, RecNo не работает


Использовать методы SQL сервера. Для каждого сервера, к сожалению, разные в Sybase SQL Anywhere - это number(*).
Например
select number(*), .... from ....
В Oracle, боюсь ошибиться, rowid или rownum

Комментарии от Andrey Mamylin

Для ORACLE...

ROWNUM - это псевдоколонка, пронумерованная в порядке следования строк для данного SELECTа (заполняется до выполнения ORDER BY).
Например, следующий SELECT вернет первые 10 строк для данной сортировки.
SELECT e.ROWNUM, e.*
FROM customer e
WHERE ROWNUM < 11
ORDER BY cust_id;
Однако нумерация будет не 1, 2, 3, 4, а что-то типа 10, 47, 9, 17 - ведь заполняется до выполнения ORDER BY.

ROWID - это внутренний номер строки в таблице. Однозначно идентифицирует оную. Можно использовать для корректировки выбранной в Grid строки, а порядок следования - совершенно произвольный.

С некоторым приближением можно использовать SEQUENCE - создается специальная конструкция, которая автоматически генерит нумерацию для некоторой вставленной в таблицу колонки (1,2,3,4... и т.д.) при добавлении новой строки. Если строку удалить - будет "дырка" в нумерации.
SEQUENCE "привязывается" к таблице триггером и хранит последний сгенерированный номер, который автоматически обновляется по-мере добавления строк...

Иногда, (не всегда), может прокатить следующее...
select ROWNUM,
A.cust_id
from
(
SELECT cust_id cust_id
FROM customer
WHERE .......
GROUP by cust_id
) A
order by A.cust_id
А вообще - нумерация строк в таблицах противоречит основным принципам реляционности... ORACLE - это не Fox Pro и ...
Однако, если край нужно - можно сделать ручками на клиенте, используя вышеуказанные конструкции, а затем выводить в SELECT.

PS. Говорят??? еще есть некий хитрый способ с примененим DISTINCT.

Комментарий от "Petr Abramov":
В Oracle начиная с 8.1.5 кляуза order by возможна в подзапросе, и тогда rownum не перемешиваются. Например:

select rownum,q.*
from
( select *
from CUSTOMER
order by CUST_ID
) q
Комментарий от Кости (kostik78ua@yahoo.com):
Если нужно пронумеровать последовательно строки через ROWNUM, можно воспользоваться запросом в запросе:

SELECT e.ROWNUM, e.*
FROM (
SELECT *
FROM customer
ORDER BY cust_id) e
WHERE e.ROWNUM < 11


Поиск в Большой БД:((


Не такая уж это и большая БД. Я делаю очень сложные выборки (например letf outer join с другой не менее маленькой табличкой), из таблицы, в которой сейчас более 600 000 записей.... и ниче, время до минуты... Ну конечно это и не DBase, а SQL Server. Но смысл всеравно остается в индексах.
Правильно поставь индекс по полю которым искать будешь, и сортировать, будет скорость - совершенно нормальная.
Только учти, чем больше индексов, и чем они сложнее (например индекс по строковому полю исессно больше и медленнее) тем дольше будет вставка в базу. А выборка по индексу практически всегда быстрее. Тут надо найти оптимальный вариант, который зависит только от режимов работы БД, ее структуры и выборок, которых из нее делают чаще всего.
И еще подумай над првильной организацией таблицы.



Почему при создании алиаса БД типа Microsoft Access 97 у меня BDE Administrator запрашивaет пароль, которого я, естественно, не знаю!


В компоненте database есть свойство "loginpromt" так вот если его устанавить в false, его самого законектить на алиус в BDE, и подключатся к базе не на прямую а через него то дурацкие вопросы типа login и pasword появляться не будут

type
Query1: TQuery;
Database1: TDatabase;
procedure FormCreate(Sender: TObject);
procedure TM_form.FormCreate(Sender: TObject);
begin
Database1.AliasName: = 'имя псевдонима из BDE администратора' ;
Database1.DatabaseName:=' Dra_ta_ta';
Database1.LoginPrompt:= False; // весь фокус в этом свойстве
Database1.Connected:=true;
Query1. DatabaseName: = ' Dra_ta_ta';
Query1.open;
// вышеприведенный этот код вполне можно сразу установить в инспекторе объектов
end;




Как сделать ProgressBar, отображающий ход события Query.Open?


Как сделать ProgressBar, отображающий ход события Query.Open?



никак IMHO. ну приблизительно можно по статистике выполнения запроса(из предположения, за сколько он раньше выполнялся, за столько и сейчас).
А вообще-то все запросы должны выполнятся за время не более 1-5 сек - если правильно составить запрос, проиндексировать и т.п.

Это возможно, если использовать ADO-компоненты для доступа к данным. Там такое реализовано.

Да, запрос должен работать быстро. Но если вопрос поставить немного по другому. Что если скажем, вам надо отобразить процесс формирования пребольшого отчета со сложным алгоритмом построения, кучей разных выборок, сравнейний и проверок, это что тоже должно уместится в 1-5 сек.
Посмотри пример из Delphi
C:\Program Files\Borland\Delphi5\Demos\Db\Bkquery
там показано как сделать "фоновый" запрос. Если использовать БДЕ, то может быть полезна Callback функция. Обрати внимание на cbCANCELQRY

Посмотрел. Ну и что? Ход события query.Open все-равно отобразить нельзя! А при чем тут фоновый процесс?
и cbCancelCRY и процесс позволят прервать запрос, но не показать ProgressBar, а все потому, что не знаем сколько он будет выполнятся всего!-Ведь вопрос именно в этом.
А двигать-то прогресс бар как раз можно в переллельном потоке.
Проблема в том, что невозможно узнать масштаб этого прогресс бара ДО выполнения запроса

При достижении maxvalue начинай снова. Информативности - полное зиро, зато будешь знать что прога не повесилась.

Да и не надо информативности, главное иллюзия для пользователя. Пусть он думает, что все так и надо. Вот например в Internet Explorer тоже есть ProgressBar, и я когда-то думал что он тоже что-то отображает.

Господа, есть предложение. В RX есть такой забавный компонент - RXDice, конкретное назначение коего мне до сих пор не ясно, но не в этом суть. Смысл в следующем: привязать приращение ProgressBar к валюесу этого самого кубика, дабы прогрессбар изменялся при "выпадении" валюеса кубика. Должно получиться забавно. Предлагаю обсудить и, возможно, реализовать (если в этом есть какой-то смысл)

Да но помоему RX работает только с БДЕ.

Дайсу БДЕ не нужен.
Вместо стандарстного прогресс бара можно взять LEDMeter из набора Simon (http://www.picsoft.de), получится красивенько.





Какой формат данных предпочесть в Delphi? dBase или Paradox?


Если вам действительно все равно, то вот несколько пунктов 'за' формат Paradox: Широкий выбор типов полей, включая автоинкремент, BLOBs, и т.п.
Соблюдение целостности данных, контроля данных, обновления индексов на уровне ядра BDE. Первичный индекс таблицы автоматически соблюдает уникальность записей, вторичные индексы обеспечивают отсортированный "вид" на записи таблицы.

Комментарий от "Anatoly Podgoretsky" (nps@nps.vnet.ee) Если вам действительно все равно, то вот несколько пунктов 'за' формат dBase:

Широкий выбор типов полей, включая автоинкремент, BLOBs, и т.п. Соблюдение целостности данных, контроля данных, обновления индексов на уровне ядра BDE.
Первичный индекс таблицы автоматически соблюдает уникальность записей, вторичные индексы обеспечивают отсортированный "вид" на записи таблицы.

Плюс: Индексы с выражениями, "уникальный индекс", устойчивость по сравнению с Парадокс и простота восстановления порушенной базы, поддержка приизводителем, для Парадокса в данный момент отсутствует.



[InterBase+Delphi] Refresh Query


К копоненту TQuery (реализованы кэшированные изменения при помощи TUpdateQuey) привязан TDBGrid и TDBNavigtor и все пекрасно работает, но при нажатии кнопки Refresh на навигаторе выскакивет ошибка "Table does not support this operation because it is not uniquely indexed". Таблица имеет первичный ключ и один дополнительный индекс по символьному полю.
Lookup поля не определены. Но такое происходит как в отдельной таблице без всяких Lookup, но с внешним ключем, так и в таблицах со связкой Master-Detail.
Программа работает в СУБД InterBase 5.0



Почитай внимательно родной делфийский хелп по TQuery, там же чёрным по белому написано что метод Refresh работает ТОЛЬКО для таблиц PARADOX или DBase!!! А в твоём случае надо просто закрывать и снова открывать запрос, других методов для IB я пока не встречал!



Проблема заключается в следующем: Delphi 3. Paradox. Есть база данных, работающая на локальной машине правильно. Как сделать, что б с этой же базой работали и другие машины из локальной сети? Пробовал выделить каталог с базами в сеть, на других машинах подключить этот каталог и прописать его в алиасах. При загрузке базы на разных машинах вроде все нормально, а как только начинаешь добавлять записи - все!!! - на каждой машине происходит добавление своей записи и внесенные изменения с другой машины не видны. Как мне добиться, что б как только одна машина внесла изменения (например добавила запись), вторая и все остальные увидели их? Пробовал в Table1 разрешить кэширование и использовать commitupdate, но результат тот же.


Нужно в настройках BDE установить local share в True, а в net dir на всех машинах прописать путь в одно и тоже место. Такая проблема может быть если при работе в сети все станции Win95/98 и сетевая станция работает одновременно со станцией где хранится база. Тогда возможны потери данных, индексов и т.д. Решение : или не работать на той машине где база или на машину где база поставить WinNT.



Как послать на Delphi комманды SQL - DELETE и INSERT ?


Попытался присвоить код DELETE FROM MyTable WHERE (условие) в TQuery, а он не хочет выполняться. =( Какие еще есть способы организовать управление через комманды SQL базой, как, например, это делает SQL Explorer?



Во первых такую команду через TQuery надо вызывать методом ExecSQL. А во вторых можно через TDataBase методом Execute. Ну и если не поможет, то третий, самый надежный метод: напрямую через API BDE процедурой DbiQExecDirect (конечно если у тебя база через BDE подключенна).



Конвертация DBF в DB


Долго и без особого успеха искал конвертор баз данных: из DBASE III+ в PARADOX. Проблема решилась просто. В утилите TBVIEW.EXE (Semi@seznam.cz) есть режимы экспорта-импорта. Если кто-то столкнулся с аналогичной проблемой - имейте в виду, что не обязательно писать довольно сложные программы конвертации БД.


Copyright © 2004 by [W_W_F]Team



Здесь могла бы быть Ваша реклама!



Hosted by uCoz