На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
Модераторы: Rouse_, jack128, Krid
Страницы: (2) [1] 2  все  ( Перейти к последнему сообщению )  
    > Базы данных с нуля, В помощь начинающим
      Итак, решил я открыть серию статей для помощи в овладении основными навыками программирования баз данных (БД, или DB - database). Я буду рассчитывать, что читатель имеет поняти о программировании в Дельфи, но абсолютно не знаком с базами данных. Первые несколько постингов будут о базах данных вообще, поэтому прошу не ругать меня - это не офтопик, очень быстро мы доберёмся до Дельфи.

      Итак базы данных существуют следующих видов:

      1) Древовидные - простейший пример - Windows Registry, файловая система FAT и XML - здесь информация хранится в древовидной структуре и доступ осуществляется через "путь", т.е. указание всех узлов от корневого до нужного. Например: "c:\My Docs\MyPictures\Me.jpg". Недостатки этого способа хранения данных является очень медленный поиск, если не известен путь и очень плохая устойчивость к повреждениям структуры. Преимущество - возможность хранить в классифицированном виде очень разнородную информацию и очень быстрый поиск при знании ключа. Эти базы данных мы разбирать здесь не будем.

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

      3) Объектные базы данных - новое веяние. Их мы разбирать здесь не будем, но интересующиеся найдут интересной дискуссию о них в нашем разделе по базам данных.

      4) Реляционные базы данных - именно с ними мы и будем работать. В дальнейшем если говорится "база данных", то подразумевается "Реляционная база данных". "Реляционный" - Relation - обозначает взаимосвязанный. С этими связями мы будем разбираться потом, а пока можно для простоты считать, что реляционная база данных - это набор двумерных простых таблиц. Недостатки реляционных баз данных - хранение только однородной информации, сложности в добавлении новых структур и взаимоотношений, информация хранящаяся в такой БД должна быть в нужной степени абстрагированна. Преимущества - прежде всего очень высокая скорость поиска - по этому параметру у реляционных баз данных конкурентов нет, высокая стабильность, обилие софта для их поддержки и разработки, удобность для очень широкого круга задач.
      With the best wishes, Vit
      I have done so much with so little for so long that I am now qualified to do anything with nothing
      Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
        Итак, Реляционная база данных упрощённо является набором таблиц. Таблица же есть основной строительный кирпичик базы данных. Расмотрим структуру таблицы. Для начала представте себе таблицу, например в Word...
        Что в ней есть?

        Во-первых есть строки и колонки (raw and columns). В базах данных, в отличие от Word есть строгие ограничения на их содержимое, да и терминология немного другая:
        1) Колонка называется тоже columns, но чаще употребляется понятие "поле" (field). Колонка всегда имеет имя (по которому ее можно найти) и обязана хранить данные только одного какого-либо типа - например целые числа, строки, дату/время и т.п. Создавая таблицу вы обязаны указать какой тип имеет каждое поле, другими словами, вы заранее должны определится, какого сорта данные будут хранится в колонке. Например, вот примерно так может выглядеть структура таблицы для хранения данных об участнике этого форума:

        - Ник - строка (25 символов)
        - ФИО - строка (250 символов)
        - Дата регистрации - Дата/время
        - Количество постингов - Целое
        - Показывать email - True/False

        Обратите внимание что для строк я указал конкретную длину, а для остальных ничего не указывал. Зачем? Ответ прост - каждая строка должна занимать строго одинаковое место (об исключениях потом), и это сделано для быстроты поиска. Действительно , если бы каждая строка имела разную длину, то чтобы найти например 1000 строку, надо было бы перечитать все 999 предыдущих строк, но если известно, что каждая строка занимает например 1Кб, то чтобы прочитать 1000 строку достаточно прочитать 1 Кб с 999Кб... Другая сторона этого - например мне надо сравнить даты в приведенной выше таблице - сделать это просто - я точно знаю что первую дату можно прочитать с 276 байта, и так же точно я знаю точные координаты каждой даты. Именно в этом и лежит одна из сторон высокой скорости работы баз данных (другие способы ускорения работы рассмотрим позже).

        2) Строка - в базах данных имеет специфическое название - запись (Record) - к Дельфийскому типу Record этот термин не имеет никакого отношения. Хотя большинство БД дают возможность перейти и прочитать например 10 запись, надо с самого начала попытаться никогда этим не пользоваться. Почему? Да просто потому что БД практически всегда подразумевают совместный доступ нескольких пользователей к одним и тем же данным, и если Вы хотите перейти на 10 запись, а другой пользователь в это время удалит запись номер 5, то вы перейдёте вовсе не на ту запись что ожидалось. А как же быть? У вас есть 2 способа - либо вы находите нужную запись по значению поля - например для нашей таблицы это будет выглядеть примерно так:

        "Найти пользователя [Вася] в первой колонке"

        В результате вы получите доступ ко всем полям записи для "Васи". Либо вы берёте все записи и перебираете их в цикле пока не найдёте нужный - это гораздо худший способ, так как работает на 2-3 порядка медленнее и имеет другие неприятные последствия (об этом позже), но он возможен и иногда применяется.
        With the best wishes, Vit
        I have done so much with so little for so long that I am now qualified to do anything with nothing
        Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
          После небольшого теоретизирования спустимся с небес на землю откроем Дельфи и напишем простейшую программу для баз данных. Напишем, это громко сказано, потому что писать ничего не прийдётся, только компоненты потыкаем.

          Открываем новый проект. Открываем форму. Ложим на форму компонент TTable (с закладки "Data Access" или "BDE" - у кого какая версия Дельфей). Оп! Не ожидали - вроде бы и таблица, а компонт не визуальный! Итак компонент TTable - это пока основной компонент для нашей базы - всё обращение к таблице идёт только через него. Теперь давай-те его подсоединим к базе данных.

          К Дельфи прилогается учебная база данных, её мы и будем пользовать. Найдите свойство DatabaseName и из выпадающего списка выберите "DBDEMOS" - это и есть учебная база данных. Теперь берём свойство TableName и в выпадающем списке обнаруживаем список имён всех таблиц в базе данных "DBDEMOS", выбираем например "biolife.db" - это таблица так называется (а в данном случае и название файла)

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

          Но все визуальные компоненты могут подсоединится к TTable только через вспомогательный компонент TDataSource - находящийся на той же закладке. Ставим и его на форму. Находим свойство DataSet у этого компонента и в выпадающем списке указываем на Table1. Теперь визуальные компоенты будут "видеть" инфу в таблице через TDataSource.

          Переходим на другую закладку компонентов - "Data Controls" и ставим компоент TDBGrid. В его свойстве DataSource указываем на DataSource1. Что видим? Пока ничего! Таблица то не открыта - кликаем на Table1 и устанавливаем свойство Active в True. Работает!

          Можно программу откомпиллировать и поиграться со своим первым приложением для баз данных. Неправда ли очень просто!
          With the best wishes, Vit
          I have done so much with so little for so long that I am now qualified to do anything with nothing
          Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
            Итак, мы не написав ни строчки кода получили простейшее приложение, работающее с базой данных. С помощью него мы можем просматривать и редактировать содержимое таблицы. Давайте теперь сделаем эту процедуру немного удобнее, на закладке "Data Control" есть компонент TDBNavigator. Положим его на форму и в инспекторе объектов поставим его свойство DataSource указывающим на тот же DataSource1, что и для DBGrid - собственно, теперь оба визуальных контрола(DBGrid и DBNavigator) привязаны к одному и тому же DataSource и через него к одной и той же таблицы. DBNavigator имеет несколько кнопок (вы можете настроить какие именно вы хотите видеть) дающие лёгкий контроль над следующими операциями:
            (перечисление в порядке расположения кнопок)
            1) Переход на первую запись
            2) Переход на предыдущую запись
            3) Переход на следующую запись
            4) Переход на последнюю запись
            5) Добавить запись
            6) Удалить запись
            7) Редактировать запись
            8) Сохранить изменения
            9) Отменить изменения
            10) Перечитать таблицу

            Обратите внимание, что запись (строка) таблицы есть как бы неделимый квант информации - т.е. отменяются действия произведенные для всей записи целиком, добавляется или удаляется тоже строка целиком.
            With the best wishes, Vit
            I have done so much with so little for so long that I am now qualified to do anything with nothing
            Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
              Разберём ещё несколько визуальных компонентов, чтобы покончить с визуализацией данных и перейти собственно к программированию.

              На закладке Data Controls есть ещё несколько важных компонентов, давайте поставим их на нашу форму: DBLabel, DBEdit, DBMemo и DBImage. Все их так же как и DBGrid соединим с DataSource1. Однако здесь мы обнаружим что этого недостаточно, эти компоненты работают с отдельной ячейкой в таблице, поэтому мы должны указать ещё поле (столбец) который они будут показывать.
              Давайте сделаем следуюшие - для каждого из этих компонентов укажем свойство DataField, например следующим образом:

              DBLabel - ассоциируем с полем Category
              DBEdit - ассоциируем с полем Common_name
              DBMemo - ассоциируем с полем Notes
              DBImage - ассоциируем с полем Graphic

              Можно откомпилировать программу и немного поиграться с ней. Итак что мы можем здесь увидеть? Что в каждый данный момент времени из всей таблицы у нас есть запись которая активная (текущая) - в DBGrid она показывается треугольничком слева. Именно с этой единственной записью мы и можем оперировать - удалять, добавлять, редактировать, именно её содержимое отображается в DBLabel, DBEdit, DBMemo, DBImage и именно она может быть изменена при помощи этих компонентов. Описанная только что структура позволяет работать только с одной записью в определённый момент времени, если вы переходите на другую запись то все изменения должны быть либо запомнены либо отменены! По умолчанию они запоминаются без всяких запросов, в чём вы можете убедиться меняя значения и переходя на другую запись.

              Пока мы рассмотрели самые простейшие и самые не эффективные операции над базами данных, которые нужны лишь в очень ограниченных случаях - их недостаток очевиден - операции роводятся только с одной записью и эти операции только визуальные. Чем это плохо? - это самый медленный способ работы с базами. Он годиться только для работы с данными в ручную, все остальные операции, которые не требуют визуализации не должны работать таким образом.
              With the best wishes, Vit
              I have done so much with so little for so long that I am now qualified to do anything with nothing
              Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
                Итак, начинаем разбирать способы работы с базами данных в коде.
                Прежде всего заметим, что работать мы будем только с компонентом
                Table1. Сразу предупреждаю - КАТЕГОРИЧЕСКИ НЕ СЛЕДУЕТ ПЫТАТЬСЯ ИЗ
                КОДА МЕНЯТЬ ЗНАЧЕНИЯ В ВИЗУАЛЬНЫХ КОМПОНЕНТАХ, не следует пытаться
                менять или читать значения из DBGrid, DBEdit и т.д. Эти компоненты
                существуют только для работы оператора "вручную". Для доступа к
                данным из кода надо использовать только невизуальные компоненты
                типа TTable (в дальнейшем мы разберём и другие компоненты для работы
                с данными - но в любом случае это будут не визуальные компоненты).

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

                1) Определить поле задача очень простая. Способов здесь 2:
                или по имени:

                ExpandedWrap disabled
                    Table1.FieldByName('Category')


                или по номеру столбца

                ExpandedWrap disabled
                    Table1.Fields[1]


                Оба выражения являются объектом наследованным от типа TField

                Я не буду разбирать этот объект подробно, только приведу пример
                как можно пользоваться этим объектом для доступа к содержимому
                ячейки таблицы. Содержимое может быть разных типов, поэтому можно
                использовать следующие методы в зависимости от типа данных:

                ExpandedWrap disabled
                    Table1.FieldByName('Category').AsString
                    Table1.FieldByName('Category').AsInteger
                    Table1.FieldByName('Category').AsBoolean
                    Table1.FieldByName('Category').AsDateTime
                    Table1.FieldByName('Category').AsFloat

                Например, поставте на форму кнопку, и на onClick напишите
                следующий код:

                ExpandedWrap disabled
                    Showmessage(Table1.FieldByName('Category').AsString);


                При нажатии на кнопку вы увидите содержимое столбца 'Category'
                для текущей записи. Аналогично для обращения по номеру:

                ExpandedWrap disabled
                    Showmessage(Table1.Fields[1].AsString);


                Обратите внимание, что на этапе компилляции компиллятор абсолютно
                не знает о реальном типе данных в поле таблицы. Это выяснится
                только при попытке выполнить строку. Что будет если типы не
                совпадают? Если тип можно конвертировать - то ничего страшного,
                например если у вас поле с целым числом 123, то обращение к полю
                через AsString выдаст результат - строку '123'. Но если типы
                не совместимы, то будет сгенерирована ошибка, например такая строка
                почти наверняка в нашем приложении приведёт к ошибке:

                ExpandedWrap disabled
                   var i:integer;
                    ...
                    i:=Table1.FieldByName('Category').AsInteger;
                    showmessage(inttostr(i));

                Потому что реальные данные не могут быть приведены к целому типу.
                With the best wishes, Vit
                I have done so much with so little for so long that I am now qualified to do anything with nothing
                Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
                  Теперь давайте разбираться как нам добраться до нужной строки,
                  другими словами, до нужной записи. Как я уже говорил мы можем
                  работать только с одной "активной" записью, поэтому задача сводится
                  к установке нужной записи "активной" (К знатокам баз данных - я упорно
                  и намеренно обхожу стороной понятие "курсор" и попытаюсь провести повествование
                  без его упоминания, с целью упрощения понимания материала и не хочу углублятся
                  в материал, без которого можно на первых порах обойтись). Итак, прежде всего
                  Table компонент имеет 4 метода которые помогут нам пройти через все строки
                  таблицы:

                  Table1.First - переход на первую запись
                  Table1.Last - переход на последнюю запись
                  Table1.Prior - переход на предыдущую запись
                  Table1.Next - переход на следующую запись

                  А так же 2 полезных свойства:

                  Table1.RecordCount - возвращает количество записей (строк) в таблице
                  Table1.Eof - возвращает TRUE если достигнута последняя запись, в остальных случаях FALSE


                  Давайте на нашу форму положим компонент Memo (на сей раз обычное, а не dbMemo).

                  Вот этот простейший код позволит пройти таблицу от начала до конца и считать
                  значения одного поля для всех записей в Memo:
                  CODE

                  Table1.First;//переход на первую запись
                  While not Table1.eof do //делать цикл пока таблица не закончится
                   begin
                     Memo1.lines.add(Table1.fieldbyname('Category').AsString); //заносим в Мемо значение поля для текущей записи
                     Table1.Next;//переходим на следующую запись
                   end;

                  Или это же самое можно сделать например так:
                  CODE

                  Table1.First;
                  For i=0 to Table1.recordcount-1 do
                   begin
                     Memo1.lines.add(Table1.fieldbyname('Category').AsString); //заносим в Мемо значение поля для текущей записи
                     Table1.Next;//переходим на следующую запись
                   end;

                  Второй способ гораздо хуже. Он имеет следующие недостатки:

                  1) Не для всех баз данных метод Table1.recordcount возвращает правильное
                  значение. Иногда Table1.recordcount устанавливается только после перехода на
                  последнюю запись(это не глюк, это вполне объяснимое поведение, например если у
                  вас есть хорошая табличка размером в несколько гигабайт на другом компьютере,
                  то Table вовсе не скачивает всю эту таблицу локально, а достаёт данные только
                  по мере необходимости). К счастью этот недостаток легко устраним, надо код
                  преобразовать до следующего вида:
                  CODE

                  Table1.Last;
                  Table1.First;
                  For i=0 to Table1.recordcount-1 do
                   begin
                     Memo1.lines.add(Table1.fieldbyname('Category').AsString); //заносим в Мемо значение поля для текущей записи
                     Table1.Next;//переходим на следующую запись
                   end;

                  Несмотря на кажущуюся бессмысленность это работает.

                  2) А вот другой аспект - всегда надо помнить о многопользовательском
                  доступе к таблицам - что случится, если во время прохода по записям другой пользователь
                  добавит или удалит запись?

                  В дальнейшем мы разберём более эффективные способы нахождения нужной записи
                  в таблице.
                  With the best wishes, Vit
                  I have done so much with so little for so long that I am now qualified to do anything with nothing
                  Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
                    А если нам надо перейти к вполне конкретной строке (записи)? Можно конечно
                    организовать такой цикл и найти нужную запись, но это громоздко, неудобно,
                    и главное очень медлено! Для этого можно использовать метод таблицы Locate.

                    Например в нашей задаче нам надо найти запись где в поле Category значение
                    "Cod". Этого можно добится примерно следующим кодом:

                    Table1.Locate('Category','Cod',[loCaseInsensitive]);

                    Можно "повесить" этот код на кнопку и убедится, что после выполнения этого
                    кода активная запись стала именно та которая нам и нужна. Итак что же за параметры
                    мы передаём этому методу? Первый параметер - это имя поля, второй параметер -
                    это значение поля, третий опции поиска (см. справку Дельфи). А что будет если
                    такого значения нет? Например:

                    Table1.Locate('Category','Cod123',[loCaseInsensitive]);

                    Ничего не будет, правда метод Locate - это функция и она возвращает значение Boolean
                    в зависимости от того, найдена запись или нет.
                    Преобразовав код как

                    if Table1.Locate('Category','Cod123',[loCaseInsensitive]) then
                    showmessage('Record is located seccessful!')
                    else
                    showmessage('Record is not found!');

                    можно убедится, что теперь мы знаем найдена запись или нет. Можно искать и по части
                    значения, например

                    Table1.Locate('Category','Co',[])

                    не сможет найти запись, а

                    Table1.Locate('Category','Co',[loPartialKey])

                    вполне правильно найдёт запись с значением 'Cod'.

                    А если нам надо найти значение по двум полям? В этой таблице искать так бесполезно,
                    так как все поля разные. Переключим таблицу на другую. Для этого удалим с формы
                    все визуальные компоненты кроме DBGrid и DBNavigator (так как у новой таблицы
                    будет совсем другой список полей). В коде напишем что-то
                    типа:

                    Table1.active:=false; //закрыли таблицу
                    Table1.tablename:='items.db';//ассоциируем с новой таблицей на диске
                    Table1.active:=true; //открыли таблицу

                    Откомпилируем код, убедимся, что теперь мы видим совсем другую таблицу.

                    Теперь давайте найдём такую запись, где ItemNo=1 и Discount=50, для этого нам надо
                    применить Locate следующим образом:


                    Table1.Locate('ItemNo;Discount',VarArrayOf([1,50]),[]);

                    Теперь несколько примечаний:

                    1) Для Дельфи 6/7 - добавьте "Uses Variants;"
                    2) Первый параметер - это список имён полей через ; без пробелов
                    3) Второй параметер - это массив вариант - значений полей. Почему вариант? Потому что
                    поля могут быть разных типов и в этом массиве вполне можно задать значения
                    разных типов: VarArrayOf([1,'Вася', True, 3.14])
                    With the best wishes, Vit
                    I have done so much with so little for so long that I am now qualified to do anything with nothing
                    Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
                      Теперь, после работы руками, попробуем разобрать несколько менее призёмлённых вещей. Для начала следует упомянуть что Вы наверное уже прочуствовали что такое таблица. Теперь немного остановимся на базе данных. Базу данных можно очень упрощённо представить как несколько разных таблиц. Они могут быть связаны между собой, а могут и нет. Как физически хранятся таблицы? В трёх видах:

                      1) Каждая таблица это отдельный файл. Так работают наиболее древние базы данных, например Парадокс (который мы пока используем в примерах), Dbase, FoxPro. Все файлы таблиц лежат в отдельном каталоге на диске. Этот каталог и называется базой данных.
                      2) Все таблицы хранятся в одном файле – например MS Access – именно этот файл и называется базой данных
                      3)Таблицы хранятся на специальном сервере – например MS SQL Server, Oracle. В данном случае нас вообще не интересует как сервер хранит эти таблицы – для нас прямой доступ к ним закрыт, мы можем лишь послать запрос на сервер и получить ответ.

                      Несмотря на значительную разницу в организации, работа с разными базами данных очень сходная (во всяком случае до углубления в дебри). В целом, Вам нет смысла копаться в реальных форматах файлов, нет смысла искать что в файле biolife.db означает 10й байт. Может показаться что всю работу над этим файлом делает компонент TTable в нашем примере. Но это не так! Я наверное удивлю многих если скажу, что компонент TTable реально является только интерфейсом, для лёгкого доступа к данным из Дельфи. Оказывается, что всю работу над таблицей делает специальный драйвер базы данных (или его ещё называют провайдер). Итак упрощённая схема общения с таблицей из программы выглядит примерно следующим образом(для нашего примера):

                      База Данных <-> Драйвер Базы Данных <-> TTable <-> наш код или др. компоненты

                      Итак драйвер БД «знает» тонкости и детали строения файла таблицы, или знает конкретные форматы запроса к серверу на «входе», а на выходе имеет некий универсальный «интерфейс» (Я имею ввиду широкое понятие слова «интерфейс», вне контекста с COM) к которому и подключается TTable. Естественно что каждая база данных, и даже каждая версия базы данных имеет свой уникальный формат, свои уникальные особенности, поэтому драйвер для каждой разновидности баз данных тоже уникальный и обычно создаётся производителем баз данных. Интерфейс на «выходе» тоже должен быть стандартизованным – тогда работа с разными базами данных будет значительно облегчена, конечно до истиной переносимости кода далеко (хотя для простейших програм можно легко перенести код для работы с другой базой данных) – сказываются очень большие различия в архитектуре баз данных, которые просто невозможно свести 100% к одинаковому интерфейсу, но в любом случае знакомство с одной базой данных позволяет с лёгкостью разобраться с другой... Как всегда существует несколько стандартов таких «выходных интерфейсов». Наиболее широкораспространены следующие «стандарты» или системы доступа к базам данных:

                      1)BDE – Borland Database Engine (или по-старому IDAPI). Мы как раз работали в наших примерах именно через эту систему. Эта система является «родной» для Дельфи и отличается весьма высокой производительностью при работе с локальными базами данных. С серверными базами данных её производительность гораздо скромнее. Она же является «родной» для Парадокса, что обусловливает очень высокую производительность и удобство работы связки Delphi-BDE-Paradox (конечно для небольших систем с малым количеством пользователей). BDE имеет в своём составе драйвера практически ко всем более или менее известным базам данных в среде Windows. Позже мы подробнее остановимся на настройке BDE.
                      2)ODBC – продукт был создан Microsoft как конкурент BDE. На большинстве баз данных он показывает меньшую производительность чем BDE, из Дельфи с ним работать не так удобно, но он так же имеет в своём составе драйвера практически ко всем более или менее известным базам данных в среде Windows. Его настройки можно найти в «Панели Управления» Windows. Есть бесплатная библиотека компонентов для работы с ODBC с исходными кодами, её можно взять с моего сайта: http://delphi.nevzorov.net. Для программиста на Дельфи представляет очень ограниченный интерес – большинство возможностей реализовано в BDE, причём BDE со многими базами работает быстрее и Дельфи имеет собственные компоненты для BDE.
                      3)DAO – это очень старая система для доступа к MS Access и MS Excel (она так же поддерживает ещё несколько баз данных), отличается высокой производительностью и богатым набором функций для работы именно с MS Access и MS Excel. Вообще не поддерживает работу с серверными базами данных. DAO можно использовать для работы с MS Access и MS Excel когда критична производительность приложений и/или требуется всё богатство возможностей доступа к MS Access и MS Excel. Есть бесплатная библиотека компонентов для работы с DAO с исходными кодами, её можно взять с моего сайта: http://delphi.nevzorov.net.
                      4)ADO (ActiveX Data Object) – новая система от MS ориентированная прежде всего на работу с серверными базами данных. Довольно удобна в использовании, Дельфи начиная с 4й версии в модификации Enterprise/Professional имеет линейку собственных компонентов для работы через ADO. Позднее мы рассмотрим работу с ADO компонентами.

                      Кроме перечисленных есть ещё по крайней мере десяток других широкоизвестных систем доступа к базам данных, и огромное количество "отдельностоящих" драйверов для конкретной базы данных.
                      With the best wishes, Vit
                      I have done so much with so little for so long that I am now qualified to do anything with nothing
                      Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
                        Те примеры с которыми мы работали использовали именно BDE. Давайте рассмотрим вопросы, напрямую связанные с BDE:

                        1) Где физически хранится моя база данных
                        2) Как создать базу данных
                        3) Как создать таблицу

                        Итак, где физически хранится моя база данных и собственно куда мы обращались в наших примерах? Если вы помните, в наших примерах мы свойство DatabaseName для Table установили в "DBDemos". Что же это такое "DBDemos"? - это название базы данных, или в терминологии BDE - Alias (перевод на русский язык "Псевдоним"). Alias - это некая "структура" BDE, которая указывает на физическое расположение файлов базы данных, а так же хранит некоторые свойства (параметры) доступа к базе данных. Эти параметры можно посмотреть, настроить, а также добавить или удалить Alias используя программу "BDE Administrator" которую можно найти в Control Panel (панель управления Windows). Запустите BDE Administrator и найдите в левом дереве DBDemos. Теперь на правой части можно увидеть его свойства, например там вы найдёте путь к базе данных. С помощью BDE можно удалить Alias или добавить новый.
                        With the best wishes, Vit
                        I have done so much with so little for so long that I am now qualified to do anything with nothing
                        Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
                          Итак, Как создать базу данных?

                          Пока мы рассматриваем Paradox осмелюсь заметить, что база данных ничто иное как папка (каталог) на диске. Надеюсь что читателю не составит труда создать пустой каталог, например "c:\MyDBExample". Теперь создадим Alias на этот каталог:

                          1) Открываем BDE Administrator, нажимаем menu->Object->New (или Ctrl-N)
                          2) В выскочившем окне выбираем Standard, жмём Ok
                          3) На левой панеле переименовываем название Alias во что-нибудь, например "MyDB"
                          4) На правой панеле, в разделе PATH указываем c:\MyDBExample
                          5) Сохраняем изменения

                          Закрываем BDE Administrator. Загружаем Дельфи с нашим примером, убеждаемся, что в свойстве DatabaseName у таблицы появился среди вариантов выбора и наш Alias - "MyDB".

                          А как создать базу данных программно? Забегаю вперёд, новички могут со спокойной совестью эту информацию пропустить.

                          С созданием базы данных програмно большие проблемы! Задача состоит из 2х этапов:

                          1) Создание самой базы данных
                          2) Создание Alias

                          Второй вопрос весьма прост - используются методы системного объекта Session:
                          session.AddAlias
                          Session.SaveConfigFile

                          Ответ же на первый не однозначен и вызвано это тем, что это целиком зависит от базы данных. Так как Dbase и Paradox базы данных это просто каталоги, то тут проблем нет, создаём каталог (ForceDirectories например) и дело с концом, для MS Access и MS Excel уже прийдётся использовать DAO низкоуровневые функции, серверные базы данных обычно имеют системные Stored Procedures для создания базы данных.
                          With the best wishes, Vit
                          I have done so much with so little for so long that I am now qualified to do anything with nothing
                          Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
                            Как создать таблицу ?

                            Вариантов несколько:

                            1) Сделать это с помошью менеджера соответствующей базы данных, например таблицу для Paradox создать в Paradox'e
                            2) С помощью Database Desktop - утилита , постовляемая с BDE и большинством борландовских продуктов. Я не думаю что вы встретите проблемы при создании таблицы - там всё очень просто.
                            3) Из программы.
                            Здесь 2 варианта, вариант первый, использовать метод CreateTable у таблицы, вот пример из справки по Дельфи как Борланд предлагает это делать:
                            CODE

                            with Table1 do begin
                             Active := False;  
                             DatabaseName := 'DBDEMOS';
                             TableType := ttParadox;
                             TableName := 'CustInfo';

                             { Don't overwrite an existing table }

                             if not Table1.Exists then begin
                               { The Table component must not be active }
                               { First, describe the type of table and give }
                               { it a name }
                               { Next, describe the fields in the table }
                               with FieldDefs do begin
                                 Clear;
                                 with AddFieldDef do begin
                                   Name := 'Field1';
                                   DataType := ftInteger;
                                   Required := True;
                                 end;
                                 with AddFieldDef do begin

                                   Name := 'Field2';
                                   DataType := ftString;
                                   Size := 30;
                                 end;
                               end;
                               { Next, describe any indexes }
                               with IndexDefs do begin
                                 Clear;
                                 { The 1st index has no name because it is
                                 { a Paradox primary key }
                                 with AddIndexDef do begin
                                   Name := '';
                                   Fields := 'Field1';
                                   Options := [ixPrimary];
                                 end;
                                 with AddIndexDef do begin

                                   Name := 'Fld2Indx';
                                   Fields := 'Field2';
                                   Options := [ixCaseInsensitive];
                                 end;
                               end;
                               { Call the CreateTable method to create the table }
                               CreateTable;
                             end;
                            end;


                            Есть другой метод, который нравится мне гораздо больше, он проще в реализации и работает стабильнее - выполнить Query типа "Create Table". Этот способ я разберу позже, когда мы будем рассматривать работу с запросами.
                            With the best wishes, Vit
                            I have done so much with so little for so long that I am now qualified to do anything with nothing
                            Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
                              Теперь последний штрих о работе с таблицами. Мы разобрали способы обратиться к нужному столбцу и нужной записи, их поиск и чтение значений. А как записать новое значение? Для этого есть методы Edit, Append, Insert, Post и Cancel.

                              Итак, возможные варианты:

                              1) Надо изменить текущую запись.
                              CODE
                               
                               Table1.edit; //переводим таблицу в режим редактирования
                               Table1.fieldbyname('Category').asString:='New value';//изменяем поле
                               Table1.post;//сохраняем изменения


                              2) Надо добавить новую запись.
                              CODE
                               
                               Table1.append; //переводим таблицу в режим добавления новой записи
                               Table1.fieldbyname('Category').asString:='New value';//присваиваем значение полей
                               Table1.post;//сохраняем изменения


                              Итого, как видим изменения данных производятся точно так же как и чтение, но перед изменением КАЖДОЙ записи таблица должна быть переведена в режим редактирования, а после изменения КАЖДОЙ записи изменения должны быть сохранены.

                              В режим редактирования таблицу переводят следующие методы:
                              Edit - редактирование текущей записи
                              Append - добавление записи в конец таблицы
                              Insert - вставка записи перед текущей

                              Для выхода из режима редактирования служат методы:
                              Post - запомнить изменения и выйти из режима редактирования
                              Cancel - отменить сделанные изменения и выйти из режима редактирования
                              With the best wishes, Vit
                              I have done so much with so little for so long that I am now qualified to do anything with nothing
                              Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
                                Итак, это пожалуй почти всё, что мы можем "выжать" из компонента TTable. Почуствовали мощь и удобство работы с базами данных? - Ой, вряд ли! Скорее всего ощущение заумности, убогости и неудобства в сочетании с крайней медлительностью операций... Действительно доступ к базе данных через TTable является самым прямым и самым неудобным, какие же основные недостатки? Наверное уже многие задались вопросами:

                                1) А если мне надо 1000 записей изменить, так мне надо в цикле крутить приведенный код? Так это ж как долго!

                                2) Ну хорошо, у меня есть табличка на сотню тысяч записей, и мне нужно из неё выбрать только, например, 1000 записей касательно "Иванова", так мне прийдётся всю таблицу в цикле крутить пока не найду то что мне нужно?

                                Все эти проблемы решены, и решены великолепно - просто, очень эффективно и с минимальными затратами.

                                Рассмотрим в кратце общий алгоритм доступа к информации который был рассмотрен:

                                1.1) Передать данные из таблицы в программу
                                1.2) Программа сама занимается поиском данных

                                А что если изменить схему:
                                2.1) Отдать команду драйверу на поиск нужной информации
                                3.2) Драйвер найдёт инфу
                                2.3) Найденная информация будет возвращена программе.


                                На первый взгляд разница только в том что работу, которую делает программный код в первом случае, мы пробуем свалить на драйвера базы данных. Ну и зачем? Оказывается есть зачем! В первой схеме - есть несколько моментов на которые я бы хотел обратить внимание:

                                1) В любом случае манипулирование базой производится драйвером, следовательно код драйвера в любом случае работает. Драйвер написан под конкретную базу данных, и "знает" каким образом манипулировать с базой самым быстрым способом, а програмный код неизбежно подвергается "транслированию", многочисленным преобразованиям данных для обеспечения совместимости.
                                2) А если база данных находится на другом компьютере? Тогда программа вынуждена "вытащить" все данные на локальный компьютер перед манипулированием данными, что есть совсем не быстрая операция. Кстати пока мы тащим гигабайтную таблицу к себе, ваш сосед Вася уже успел там что-то поменять, и что теперь? Тащим заново, или посылаем Васю подальше, и не даём ему работать с базой пока сами не закончим?

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

                                И как же это реализовано? Это реализовано с помощью языка запросов: SQL. Подробнее этот язык рассмотивается в разделе Базы данных, мы же не заостряя внимание на самих запросах, рассмотрим простейшие случаи как этот язык можно применить внутри программы на Дельфи и какие выгоды можем мы получить используя запросы.
                                With the best wishes, Vit
                                I have done so much with so little for so long that I am now qualified to do anything with nothing
                                Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
                                  Итак, из нашего тестового проекта удаляем компонент Table1. Вместо него ставим компонент TQuery. Устанавливаем Alias (DatabaseName) и связываем его с DataSource таким же образом как и таблицу.

                                  Пока вы найдёте 2 радикальных отличия от TTable:
                                  1) Нет свойства TableName
                                  2) Открытие (Active:=true) квери приводит к ошибке

                                  Query должна содержать запрос. Для этого есть свойство SQL, являющееся самым обыкновенным TStringList. Откроем это свойство и напишем примерно следующее:

                                  SQL
                                  Select * from biolife


                                  Теперь можно попытаться открыть квери (установить Active в True) и вы получите точно тоже что и в первом примере - грид заполненный данными из таблицы Biolife.db. Мало того, всё что мы проделывали с таблицей - позиционирование строки, чтение и запись полей и т.п. вы можете с успехом сделать и с Query - причём синтаксис тот же самый! Пока мы только сделали замену компоненту TTable и не более того.
                                  With the best wishes, Vit
                                  I have done so much with so little for so long that I am now qualified to do anything with nothing
                                  Самый большой Delphi FAQ на русском языке здесь: www.drkb.ru
                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                  0 пользователей:


                                  Рейтинг@Mail.ru
                                  [ Script Execution time: 0,1585 ]   [ 17 queries used ]   [ Generated: 21.10.18, 10:17 GMT ]