6

次のようなスキーマがあるとします。

group
-----
id

site
----
id
group_id (optional)

person
------
id
group_id (one of these two must exist 
site_id   and the other must be null)

device
------
id 
group_id  (one of these three must exist 
site_id    and the others must be null)
person_id  

この表現は好きではありませんが、より良い表現を見つけるのに苦労しています。

私が考えた2つの選択肢は次のとおりです。

device
------
id 
parent_table_name
parent_id

(しかし、これ以上外部キーを持つことができないので、これは悪いことです)

と:

entity
------
id

group
-----
entity_id

site
----
entity_id
link_entity_id (optional)

person
------
entity_id
link_entity_id (optional)

device
------
entity_id
link_entity_id

これも完璧とは言えません。これは実際には Django ORM の継承方法であり、エンティティは他のすべてのクラスの親です。

データを構造化するためのより良い方法はありますか?それとも SQL は DAG と対立しているのでしょうか?

CONSTRAINTperson テーブルと device テーブルに s を追加する方法はありますか?

4

3 に答える 3

1

これは典型的なタイプ/サブタイプの状況です。2 番目のオプションの方が優れており、さらに一歩進めることができます。これらの概念に精通している場合は、OO プログラミングの観点から考えてみてください。

これが私があなたのエンティティを分類する方法です。「抽象」エンティティは括弧内にあります。

             (所有者) デバイス
               | |
         +---------+
         | | | |
   (所属) 人
         | |
     +------+
     | | | |
   グループサイト

読み方はこうです。

  • 所有者のタイプは次のとおりです。人、または所属 (申し訳ありませんが、より適切な名前が見つかりません)。個人は「所有者」であり、所属は「所有者」です。
  • アフィリエーションのタイプ: グループ、またはサイト
  • 個人は、グループまたはサイトのいずれかのアフィリエーションに所属しています
  • デバイスには、グループ、サイト、または個人のいずれかの所有者がいます。

これを表に変換する方法:

EER図

これで、最初のオプションに固執することができます。MySQL は任意の制約を宣言するための構文をサポートしていませんCHECK()が、トリガーを使用して同じ効果を達成できます。ただし、構文が面倒で、パフォーマンスが疑わしいです。

于 2013-06-07T17:44:03.933 に答える
1

次の MySQL 構造は問題なく正規化されるはずです。場合によっては、クエリの記述が少し複雑になりますが、アプリケーションがより強力になり、パフォーマンスに影響を与えることなく指数関数的に成長できるようになります。私たちは、さまざまなインタビュー、メモ、その他のデータへの外部キーを保持する多くの関連テーブルを備えた大規模な MySQL データベースを持っています。グループをテーブル名として使用する場合は、次のような `` マークを忘れずに使用してください。

`group`

INNER JOIN group ON (foo=bar)そうすれば、MySQL は aと expectを無効にしようとしませんGROUP BY。また、アプリケーションのフロント エンドに制限を設けて、親なしでデバイスが追加されるのを防ぐ必要があります。しかし、それを行うのはそれほど難しいことではありません。とにかく、例を見て、実験/プログラミングを楽しんでください!

オンライン デモ: http://www.sqlfiddle.com/#!2/e9e94/2/0

質問から必要な各ケースの 1 つのインスタンスを説明する最小量のデータを含む提案された MySQL テーブル構造を次に示します。コピーして .sql ファイルに貼り付け、phpMyAdmin を使用して空のデータベースにインポートします。

-- phpMyAdmin SQL Dump
-- version 3.5.2.2
-- http://www.phpmyadmin.net
--
-- Host: 127.0.0.1
-- Generation Time: Jun 07, 2013 at 08:14 PM
-- Server version: 5.5.27
-- PHP Version: 5.4.7

SET FOREIGN_KEY_CHECKS=0;
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Database: `stackoverflow`
--

-- --------------------------------------------------------

--
-- Table structure for table `device`
--

CREATE TABLE IF NOT EXISTS `device` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;

--
-- Dumping data for table `device`
--

INSERT INTO `device` (`id`) VALUES
(1),
(2),
(3),
(4),
(5),
(6);

-- --------------------------------------------------------

--
-- Table structure for table `group`
--

CREATE TABLE IF NOT EXISTS `group` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ;

--
-- Dumping data for table `group`
--

INSERT INTO `group` (`id`) VALUES
(1),
(2),
(3),
(4),
(5),
(6),
(7),
(8);

-- --------------------------------------------------------

--
-- Table structure for table `groups_have_devices`
--

CREATE TABLE IF NOT EXISTS `groups_have_devices` (
  `group_id` int(11) NOT NULL,
  `device_id` int(11) NOT NULL,
  PRIMARY KEY (`group_id`,`device_id`),
  KEY `device_id` (`device_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Dumping data for table `groups_have_devices`
--

INSERT INTO `groups_have_devices` (`group_id`, `device_id`) VALUES
(4, 6);

-- --------------------------------------------------------

--
-- Table structure for table `groups_have_people`
--

CREATE TABLE IF NOT EXISTS `groups_have_people` (
  `group_id` int(11) NOT NULL,
  `person_id` int(11) NOT NULL,
  PRIMARY KEY (`group_id`,`person_id`),
  KEY `person_id` (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Dumping data for table `groups_have_people`
--

INSERT INTO `groups_have_people` (`group_id`, `person_id`) VALUES
(1, 2),
(5, 5);

-- --------------------------------------------------------

--
-- Table structure for table `groups_have_sites`
--

CREATE TABLE IF NOT EXISTS `groups_have_sites` (
  `group_id` int(11) NOT NULL,
  `site_id` int(11) NOT NULL,
  PRIMARY KEY (`group_id`,`site_id`),
  KEY `site_id` (`site_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Dumping data for table `groups_have_sites`
--

INSERT INTO `groups_have_sites` (`group_id`, `site_id`) VALUES
(2, 2),
(3, 4),
(6, 6),
(7, 8);

-- --------------------------------------------------------

--
-- Table structure for table `people_have_devices`
--

CREATE TABLE IF NOT EXISTS `people_have_devices` (
  `person_id` int(11) NOT NULL,
  `device_id` int(11) NOT NULL,
  PRIMARY KEY (`person_id`,`device_id`),
  KEY `device_id` (`device_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Dumping data for table `people_have_devices`
--

INSERT INTO `people_have_devices` (`person_id`, `device_id`) VALUES
(1, 1),
(2, 2),
(3, 3);

-- --------------------------------------------------------

--
-- Table structure for table `person`
--

CREATE TABLE IF NOT EXISTS `person` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;

--
-- Dumping data for table `person`
--

INSERT INTO `person` (`id`) VALUES
(1),
(2),
(3),
(4),
(5),
(6);

-- --------------------------------------------------------

--
-- Table structure for table `site`
--

CREATE TABLE IF NOT EXISTS `site` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ;

--
-- Dumping data for table `site`
--

INSERT INTO `site` (`id`) VALUES
(1),
(2),
(3),
(4),
(5),
(6),
(7),
(8);

-- --------------------------------------------------------

--
-- Table structure for table `sites_have_devices`
--

CREATE TABLE IF NOT EXISTS `sites_have_devices` (
  `site_id` int(11) NOT NULL,
  `device_id` int(11) NOT NULL,
  PRIMARY KEY (`site_id`,`device_id`),
  KEY `device_id` (`device_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Dumping data for table `sites_have_devices`
--

INSERT INTO `sites_have_devices` (`site_id`, `device_id`) VALUES
(3, 4),
(4, 5);

-- --------------------------------------------------------

--
-- Table structure for table `sites_have_people`
--

CREATE TABLE IF NOT EXISTS `sites_have_people` (
  `site_id` int(11) NOT NULL,
  `person_id` int(11) NOT NULL,
  PRIMARY KEY (`site_id`,`person_id`),
  KEY `person_id` (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Dumping data for table `sites_have_people`
--

INSERT INTO `sites_have_people` (`site_id`, `person_id`) VALUES
(1, 1),
(2, 3),
(5, 4),
(6, 6);

--
-- Constraints for dumped tables
--

--
-- Constraints for table `groups_have_devices`
--
ALTER TABLE `groups_have_devices`
  ADD CONSTRAINT `groups_have_devices_ibfk_2` FOREIGN KEY (`device_id`) REFERENCES `device` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `groups_have_devices_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `group` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

--
-- Constraints for table `groups_have_people`
--
ALTER TABLE `groups_have_people`
  ADD CONSTRAINT `groups_have_people_ibfk_2` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `groups_have_people_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `group` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

--
-- Constraints for table `groups_have_sites`
--
ALTER TABLE `groups_have_sites`
  ADD CONSTRAINT `groups_have_sites_ibfk_2` FOREIGN KEY (`site_id`) REFERENCES `site` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `groups_have_sites_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `group` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

--
-- Constraints for table `people_have_devices`
--
ALTER TABLE `people_have_devices`
  ADD CONSTRAINT `people_have_devices_ibfk_2` FOREIGN KEY (`device_id`) REFERENCES `device` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `people_have_devices_ibfk_1` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

--
-- Constraints for table `sites_have_devices`
--
ALTER TABLE `sites_have_devices`
  ADD CONSTRAINT `sites_have_devices_ibfk_2` FOREIGN KEY (`device_id`) REFERENCES `device` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `sites_have_devices_ibfk_1` FOREIGN KEY (`site_id`) REFERENCES `site` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;

--
-- Constraints for table `sites_have_people`
--
ALTER TABLE `sites_have_people`
  ADD CONSTRAINT `sites_have_people_ibfk_2` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  ADD CONSTRAINT `sites_have_people_ibfk_1` FOREIGN KEY (`site_id`) REFERENCES `site` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION;
SET FOREIGN_KEY_CHECKS=1;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

すべてのグループのすべての子デバイスを検索するクエリを次に示します。

SELECT
  `group`.`id` AS `group_id`,
  `device`.`id` AS `device_id`
FROM
  `group`
  INNER JOIN groups_have_devices
    ON (group.id=groups_have_devices.group_id)
  INNER JOIN device
    ON (groups_have_devices.device_id=device.id)

UNION ALL

SELECT
  `group`.`id` AS `group_id`,
  `device`.`id` AS `device_id`
FROM
  `group`
  INNER JOIN groups_have_people
    ON (group.id=groups_have_people.group_id)
  INNER JOIN person
    ON (groups_have_people.person_id=person.id)
  INNER JOIN people_have_devices
    ON (person.id=people_have_devices.person_id)
  INNER JOIN device
    ON (people_have_devices.device_id=device.id)

UNION ALL

SELECT
  `group`.`id` AS `group_id`,
  `device`.`id` AS `device_id`
FROM
  `group`
  INNER JOIN groups_have_sites
    ON (group.id=groups_have_sites.group_id)
  INNER JOIN site
    ON (groups_have_sites.site_id=site.id)
  INNER JOIN sites_have_devices
    ON (site.id=sites_have_devices.site_id)
  INNER JOIN device
    ON (sites_have_devices.device_id=device.id)

UNION ALL

SELECT
  `group`.`id` AS `group_id`,
  `device`.`id` AS `device_id`
FROM
  `group`
  INNER JOIN groups_have_sites
    ON (group.id=groups_have_sites.group_id)
  INNER JOIN site
    ON (groups_have_sites.site_id=site.id)
  INNER JOIN sites_have_people
    ON (site.id=sites_have_people.site_id)
  INNER JOIN person
    ON (sites_have_people.person_id=person.id)
  INNER JOIN people_have_devices
    ON (person.id=people_have_devices.person_id)
  INNER JOIN device
    ON (people_have_devices.device_id=device.id)
ORDER BY
  group_id

次に、すべてのデバイスとその直接の親を取得するクエリを示します。

SELECT
  device.id AS device_id,
  person.id AS person_id,
  NULL AS site_id,
  NULL AS group_id
FROM
  device
  INNER JOIN people_have_devices
    ON (device.id=people_have_devices.device_id)
  INNER JOIN person
    ON (people_have_devices.person_id=person.id)

UNION ALL

SELECT
  device.id AS device_id,
  NULL AS person_id,
  site.id AS site_id,
  NULL AS group_id
FROM
  device
  INNER JOIN sites_have_devices
    ON (device.id=sites_have_devices.device_id)
  INNER JOIN site
    ON (sites_have_devices.site_id=site.id)

UNION ALL

SELECT
  device.id AS device_id,
  NULL AS person_id,
  NULL AS site_id,
  group.id AS group_id
FROM
  device
  INNER JOIN groups_have_devices
    ON (device.id=groups_have_devices.device_id)
  INNER JOIN `group`
    ON (groups_have_devices.group_id=group.id)

このように、特定の人、グループ、またはサイトの直接の子であるデバイスをさらに取得できます

SELECT
  device_id
FROM (
  SELECT
    device.id AS device_id,
    NULL AS person_id,
    site.id AS site_id,
    NULL AS group_id
  FROM
    device
    INNER JOIN sites_have_devices
      ON (device.id=sites_have_devices.device_id)
    INNER JOIN site
      ON (sites_have_devices.site_id=site.id)
) sub_query
WHERE
  sub_query.site_id='3'
于 2013-06-07T18:30:42.177 に答える
0

これにアプローチするもう 1 つの方法は、いくつかのテーブルを複数のテーブルに分割し、UNION ALL を一緒に戻すことです。

これは少し複雑ですが、より正確性を保証できます。

(@ amaster507 からの回答を 1 週間受け入れませんでした。うまくいけば、この解決策について意見を得ることができます。)

要件:

group
-----
id

site
----
id
group_id (optional)

person
------
id
group_id (one of these two must exist 
site_id   and the other must be null)

device
------
id 
group_id  (one of these three must exist 
site_id    and the others must be null)
person_id  

提案されたスキーマ:

group
-----
id

site
----
id
group_id (optional)

person_in_group
---------------
id
group_id  

person_at_site
--------------
id
site_id   

device_in_group
---------------
id 
group_id   

device_at_site
--------------
id 
site_id   

device_with_person
------------------
id 
person_id 

UNION ALLperson テーブルに対して行われるクエリは、person_in_group および person_at_site テーブルに対して行う必要があります。

同様に、device テーブルに対して行われるクエリUNION ALLは、device_in_group、device_at_site、および device_with_person テーブルに対して行う必要があります。

于 2013-10-03T07:36:29.193 に答える