Можете ли вы использовать «рыцарские ходы» для запроса одной базы данных и присоединения ее к себе? - PullRequest
1 голос
/ 01 марта 2020

Я работаю над проектом, включающим код на Прологе и SQL для решения одной и той же проблемы. Проблема, с которой я столкнулся, заключается в том, что я не могу использовать одну базу данных для формирования иерархии. В этом списке фактов пролога вы видите, что детали «сборки» связаны друг с другом.

basicpart(spoke).
basicpart(rearframe).
basicpart(handles).
basicpart(gears).
basicpart(bolt).
basicpart(nut).
basicpart(fork).

assembly(bike,[wheel,wheel,frame]).
assembly(wheel,[spoke,rim,hub]).
assembly(frame,[rearframe,frontframe]).
assembly(frontframe,[fork,handles]).
assembly(hub,[gears,axle]).
assembly(axle,[bolt,nut]).

Если я соберу все эти определения «сборки» в одну базу данных SQL, могу ли я использовать Рыцарь движется (присоединяя таблицу к себе на 2 разных столбцах), чтобы построить эту иерархию в SQL только в 2 таблицах?

1 Ответ

0 голосов
/ 02 марта 2020

Если я правильно понял этот вопрос. Вы не можете построить свой велосипед только одним запросом (я не знаком с термином "ход рыцаря"). На самом деле, вы можете - но это должен быть рекурсивный SQL запрос . Потому что вы будете вычислять транзитивное замыкание отношения часть-часть.

К сожалению, я не сразу знаю, как их написать. Синтаксис SQL откровенно ужасен и рекурсивен SQL выглядит даже ужаснее, поэтому ниже приведен пример кода с использованием al oop.

На самом деле вам нужна только одна таблица для представления данных, поскольку отношение basicpart/1 ничего не вносит в таблицу, кроме как помечает определенные «вещи» как basi c. Но это также вещи, которые не появляются в assembly/2 на первой позиции.

Примечания:

  • Не используется ENUMS, которые на самом деле не являются " типы "в MySQL / MariaDB, но просто ограничение на поле определенной таблицы c. (Например, WTF!)
  • Представление мультисета кода Пролога («велосипед имеет два колеса») сведено в несколько рядов, отдельно обозначаемых числовым идентификатором c суррогата. Это связано с догмой «Первая нормальная форма » практики RDBMS. Нет ничего плохого в том, чтобы иметь мультимножества в качестве значений, если язык запросов и механизм СУБД могут его поддерживать. Например, вы можете иметь XML значений в PostgreSQL, заполненных запросами к его содержимому, насколько я помню 1 .
DELIMITER //

DROP PROCEDURE IF EXISTS prepare;

CREATE PROCEDURE prepare() 
BEGIN

   DROP TABLE IF EXISTS assembly;

   CREATE TABLE assembly 
      (id INT AUTO_INCREMENT KEY,    -- surrogate key because a bike may have several wheels
       part VARCHAR(10) NOT NULL, 
       subpart VARCHAR(10) NOT NULL);

   INSERT INTO assembly(part,subpart) VALUES
      ("bike","wheel"),
      ("bike","wheel"),
      ("bike","frame"),
      ("wheel","spoke"),
      ("wheel","rim"),
      ("wheel","hub"),
      ("frame","rearframe"),
      ("frame","frontframe"),
      ("frontframe","fork"),
      ("frontframe","handles"),
      ("hub","gears"),
      ("hub","axle"),
      ("axle","bolt"),
      ("axle","nut");
END;

DROP PROCEDURE IF EXISTS compute_transitive_closure;

CREATE PROCEDURE compute_transitive_closure()
BEGIN

   DROP TABLE IF EXISTS pieces;

   CREATE TABLE pieces
      (id      INT AUTO_INCREMENT KEY,
       part    VARCHAR(10) NOT NULL,
       subpart VARCHAR(10) NOT NULL,
       path    VARCHAR(500) NOT NULl DEFAULT "",
       depth   INT NOT NULL DEFAULT 0);

   INSERT INTO pieces(part,subpart,path,depth) VALUES
      ("ROOT","bike","/bike",0);

   SET @depth=0;

   l: LOOP
      INSERT INTO pieces(part,subpart,path,depth)
      SELECT
         p.subpart,
         a.subpart,
         CONCAT(p.path,'/',a.subpart),
         @depth+1
      FROM
         pieces   p,
         assembly a
      WHERE
         p.depth = @depth AND p.subpart = a.part;

      IF ROW_COUNT() <= 0 THEN
         LEAVE l;
      ELSE
         SELECT * FROM pieces;
      END IF;

      SET @depth=@depth+1;
   END LOOP;

END; //

DELIMITER ;

Поместить вышеприведенное в файл SQL.txt, а затем в базе данных testme:

MariaDB [testme]> source SQL.txt;
MariaDB [testme]> CALL prepare;
MariaDB [testme]> CALL compute_transitive_closure;

Затем через 4 прохода через l oop вы получите:

+----+------------+------------+--------------------------------+-------+
| id | part       | subpart    | path                           | depth |
+----+------------+------------+--------------------------------+-------+
|  1 | ROOT       | bike       | /bike                          |     0 |
|  2 | bike       | wheel      | /bike/wheel                    |     1 |
|  3 | bike       | wheel      | /bike/wheel                    |     1 |
|  4 | bike       | frame      | /bike/frame                    |     1 |
|  5 | wheel      | spoke      | /bike/wheel/spoke              |     2 |
|  6 | wheel      | spoke      | /bike/wheel/spoke              |     2 |
|  7 | wheel      | rim        | /bike/wheel/rim                |     2 |
|  8 | wheel      | rim        | /bike/wheel/rim                |     2 |
|  9 | wheel      | hub        | /bike/wheel/hub                |     2 |
| 10 | wheel      | hub        | /bike/wheel/hub                |     2 |
| 11 | frame      | rearframe  | /bike/frame/rearframe          |     2 |
| 12 | frame      | frontframe | /bike/frame/frontframe         |     2 |
| 20 | frontframe | fork       | /bike/frame/frontframe/fork    |     3 |
| 21 | frontframe | handles    | /bike/frame/frontframe/handles |     3 |
| 22 | hub        | gears      | /bike/wheel/hub/gears          |     3 |
| 23 | hub        | gears      | /bike/wheel/hub/gears          |     3 |
| 24 | hub        | axle       | /bike/wheel/hub/axle           |     3 |
| 25 | hub        | axle       | /bike/wheel/hub/axle           |     3 |
| 27 | axle       | bolt       | /bike/wheel/hub/axle/bolt      |     4 |
| 28 | axle       | nut        | /bike/wheel/hub/axle/nut       |     4 |
| 29 | axle       | bolt       | /bike/wheel/hub/axle/bolt      |     4 |
| 30 | axle       | nut        | /bike/wheel/hub/axle/nut       |     4 |
+----+------------+------------+--------------------------------+-------+

1 : Это заставило меня выкопать «Глубина базы данных: теория отношений для практиков» , O'Reilly 2005, Chris Date , отличное введение в реляционную модель. На странице 30 Date рассматривает «наборы как значения» (но не рассматривает «мультимножества»):

Второй (и независимо от того, что вы думаете о моем первом аргументе), факт в том, что набор, подобный {P2,P4,P5}, не более и не менее разложим в СУБД, чем символьная строка. Как строки символов, наборы имеют некоторую внутреннюю структуру; однако, как и со строками символов, удобно игнорировать эту структуру для определенных целей. Другими словами, если символьная строка совместима с требованиями 1NF, то есть если символьные строки имеют атоми c, то наборы также должны быть. Реальная точка зрения, к которой я прихожу, заключается в том, что понятие атомарности не имеет абсолютного значения; это зависит только от того, что мы хотим сделать с данными. Иногда мы хотим иметь дело с целым набором номеров деталей как с одной вещью, а иногда мы хотим иметь дело с отдельными номерами деталей в этом наборе - но затем мы опускаемся до более низкого уровня детализации (более низкого уровня абстракции).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...