Я новичок в SQL, и я прыгаю в голове, пытаясь как можно больше узнать, как я кодирую, что сложно, поскольку я разрабатываю базу данных, с которой мне придется жить в то время как я хочу убедиться, что я делаю это правильно. Я узнал основы таблиц моста "Множество ко многим", но что, если два поля одного типа? Скажем, социальная сеть с тысячами пользователей, и как бы вы создали таблицу, чтобы отслеживать, кто с кем знаком? Что делать, если есть дополнительные данные о каждой связи, например... например, "date friended". Зная, что будут такие запросы, как "показать всех друзей пользователяX, связанных между датой и датой". У моей базы данных было бы несколько ситуаций, подобных этому, и я не могу найти эффективный способ сделать это. Поскольку для меня это очень важно, я полагаю, что другие выяснили, как лучше всего создавать таблицы, не так ли?
Как сделать таблицу взаимосвязей SQL-кода многими другими для разных типов
Ответ 1
Создайте таблицу User
, затем таблицу Relationships
, в которой вы храните id
двух друзей и любую информацию об их отношении.
Диаграмма SQL
Код MySQL
CREATE TABLE `Users` (
`id` TINYINT NOT NULL AUTO_INCREMENT DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `Relationships` (
`id` TINYINT NOT NULL AUTO_INCREMENT DEFAULT NULL,
`userid` TINYINT NULL DEFAULT NULL,
`friendid` TINYINT NULL DEFAULT NULL,
`friended` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
);
ALTER TABLE `Relationships` ADD FOREIGN KEY (userid) REFERENCES `Users` (`id`);
ALTER TABLE `Relationships` ADD FOREIGN KEY (friendid) REFERENCES `Users` (`id`);
Выбор SQL
После заполнения таблиц данными вы можете создать запрос SQL SELECT
, чтобы получить всех своих друзей. Вашими друзьями являются те, чей id
находится на одной стороне, а ваш идентификатор находится на другой стороне. Вы проверяете обе стороны для id
, поэтому вам не нужно сохранять отношения дважды. Также вы должны исключить свой id
, потому что вы не можете быть вашим собственным другом (в нормальном, здоровом мире).
SELECT *
FROM Users u
INNER JOIN Relationships r ON u.id = r.userid
INNER JOIN Relationships r ON u.id = r.friendid
WHERE
(r.userid = $myid OR r.friendid = $myid)
AND r.friended >= $startdate
AND r.friended <= $enddate
AND u.id != $myid;
Где $myid
, $startdate
и $enddate
могут быть переменными PHP, поэтому в двойных кавычках вы можете передать этот код непосредственно в свою базу данных.
Ответ 2
Достаточно одной таблицы ссылок, например:
People( PersonId bigint, Name nvarchar, etc )
Friends( FromPersonId bigint, ToPersonId bigint, DateAdded datetime )
Пример запросов:
Кто со мной дружит? (т.е. люди, которые добавили меня как друга, но не обязательно ответили)
SELECT
People.Name
FROM
Friends
INNER JOIN People ON Friends.FromPersonId = People.PersonId
WHERE
Friends.ToPersonId = @myPersonId
Кто добавил меня между двумя датами?
SELECT
People.Name
FROM
Friends
INNER JOIN People ON Friends.FromPersonId = People.PersonId
WHERE
Friends.ToPersonId = @myPersonId
AND
Friends.DateAdded >= @startDate
AND
Friends.DateAdded <= @endDate
Ответ 3
Модель
Модель, растягивающаяся на три таблицы, будет вариантом. У вас будет очевидная таблица user
со всеми параметрами пользователя (Имя, Дата рождения,...).
CREATE TABLE `user` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45),
`dob` DATE,
PRIMARY KEY (`id`)
);
Во-вторых, таблица connection
пользователя может содержать привилегии, предоставляемые соединению (может ли это соединение увидеть мой фотоальбом), и, что важно, относится к таблице friendship
. Нам нужна таблица connection
между ними, потому что один пользователь может быть подключен во многие дружеские отношения.
CREATE TABLE `connection` (
`id` INT NOT NULL AUTO_INCREMENT,
`user_id` INT NOT NULL,
`friendship_id` INT NOT NULL,
`privilege_mask` TINYINT,
PRIMARY KEY (`id`)
);
friendship
, в свою очередь, может включать общие данные, например, когда эта дружба была установлена. Пользователи, которые подключены к тому же friendship
, являются друзьями.
CREATE TABLE `friendship` (
`id` INT NOT NULL AUTO_INCREMENT,
`met_first_time` DATE,
PRIMARY KEY (`id`)
);
Этот путь был бы более реалистичной моделью, чем другие решения, опубликованные до сих пор, поскольку избегает направленности (невзаимная дружба - которая не должна существовать!), но было бы немного больше работы для реализации.
Друзья запросов
Пример, который должен запрашивать имена ваших друзей, может быть (хотя и не протестирован):
SELECT B.name FROM user A
INNER JOIN connection conn_A ON conn_A.user_id = A.id
INNER JOIN connection conn_B ON conn_A.friendship_id = conn_B.friendship_id
INNER JOIN user B ON conn_B.user_id = B.id
INNER JOIN friendship ON friendship.id = conn_A.friendship_id
WHERE A.name = 'Dan' AND A.id <> B.id AND
friendship.met_first_time BETWEEN '2013-4-1' AND '2013-6-30';
Вы можете заметить, что если вам не нужна дата, когда вы подружились, вам не нужно JOIN
в таблице friendship
, поскольку соединения уже разделяют ключи friendship_id
. Суть любого такого запроса заключалась бы в JOIN
между conn_A
и conn_B
на conn_A.friendship_id = conn_B.friendship_id
.
Ответ 4
Вы должны использовать идентификатор двух пользователей как PRIMARY KEY в таблице отношений (отношение будет уникальным, даже если оно не двунаправлено). Что-то вроде этого
CREATE TABLE
Users
(id
int (9) NOT NULL AUTO_INCREMENT,
ПЕРВИЧНЫЙ КЛЮЧ (id
));CREATE TABLE
Relationships
(id1
int (9) NOT NULL,id2
int (9) NOT NULL,friended
TIMESTAMP NOT NULL, ПЕРВИЧНЫЙ КЛЮЧ (id1
,id2
));
Обратите внимание:
- id1 и ссылка id2 Таблица пользователей (код выше был очень упрощен)
- даже если отношение не является "двунаправленным", вы можете думать
что если у вас есть id1 - id2, кажется, что id1 пользователь добавляет id2 пользователя как
друг, но не обязательно наоборот - THEN id2 пользователь может добавить
id1 пользователь как друг - в таблице отношений вы можете
эти возможные комбинации:
- id1-id2, (только 1 добавить 2 в качестве друга)
- id2-id1, (only2 добавить 1 в качестве друга)
- id1-id2 И id2-id1 (оба - это 2 строки в таблице отношений, и оба являются ВЗАИМНОМ друзья)