Как вставить в несколько таблиц с помощью таблицы перекрестных ссылок

  • Автор темы _Scorpio
  • 86
  • Обновлено
  • 13, May 2024
  • #1
Всем привет, У меня возникли проблемы с попыткой понять, как вставить данные в мои таблицы с помощью таблицы перекрестных ссылок.

Настройка у меня следующая: КАРТА card_id (первичный ключ) заголовок содержание ЯРЛЫК tag_id (первичный ключ) ярлык КАРТА_TAG card_id tag_id (оба первичные, ссылаются на CARD.card_id и TAG.tag_id соответственно) (Карточки могут иметь множество тегов.

Теги могут быть связаны со многими карточками)

Имея в таблицах фиктивные данные, я могу получить идентификаторы из CARD_TAG, а затем получить соответствующие данные из двух других таблиц, но я не могу понять (после долгих поисков), как ВСТАВИТЬ данные.

Единственный способ, который я могу сейчас придумать, как это сделать:

1. Сохраните карту в CARD.

2. Получите последний_id() этой карты из CARD.

3. Перебирать теги, сохраняя их в TAG.

Потом я немного запутался, поэтому все, что я мог думать, это:

4. Перебрать теги, получив идентификаторы.

5. Снова пройдитесь по тегам, сохраняя идентификатор карты вместе с каждым тегом.

Одновременно может храниться только одна карта, но она может иметь несколько тегов.

Будет ли это способ сделать это? Или есть лучший способ?

_Scorpio


Рег
01 Jan, 2011

Тем
1

Постов
3

Баллов
13
  • 21, May 2024
  • #2
Спасибо! Я понимаю, как это будет работать, и это действительно охватывает то, что мне нужно.

Это также хороший (меньший) шаг вперед по сравнению с использованием одной таблицы, дающий мне опыт работы с двумя таблицами.

Я думаю, это даст мне больше шансов понять, как несколько таблиц будут работать вместе, когда мне придет в голову идея, что воля нужна таблица перекрестных ссылок. Еще раз спасибо @JEET. Я отмечу ваш ответ как лучший, поскольку он определенно отвечает на мой вопрос.
 

nedilko


Рег
30 Oct, 2014

Тем
0

Постов
3

Баллов
3
  • 01, Jun 2024
  • #3
Почему бы вам не использовать такую структуру:

КАРТОЧНЫЙ стол

ID карты

заголовок

содержание

Таблица тегов

идентификатор тега

ID карты

ярлык

Итак, когда вы получаете новый ввод для «карточек», все, что вам нужно сделать, это следующее:

"вставить в CARD ( title, content ) значения ( '$title', '$content')";

$cardID= getLastInsertID();

$данные="";

foreach($теги как $v){

$data.="( '$catID', '$v'),";

}

$data= Trim($data, ",");

"вставить в TAG (catID, tag) значения $data";

Здесь нет необходимости в этой третьей таблице, в которой хранятся только tagID и cardID.

Сохраните cardID в самой таблице тегов.
 

tuirson


Рег
31 Aug, 2013

Тем
1

Постов
7

Баллов
17
  • 03, Jun 2024
  • #4
Используете ли вы LIKE или что-то еще, чтобы попытаться извлечь совпадающие теги? Я имею в виду, что если вы знаете идентификатор тега (который у вас будет на стороне клиента), какой у вас эквивалент:

ВЫБЕРИТЕ идентификатор карты

ИЗ card_tags

ГДЕ tag_id = ?

(на практике у меня было бы соединение, чтобы вытащить связанные карты)

-- изменить -- более конкретно:

ВЫБЕРИТЕ card.id, card.title

С карты

ПРИСОЕДИНЯЙТЕСЬ к card_tags ON card.id = card_tags.card_id

ГДЕ card_tags.tag_id = ?

Ваша единственная запись просто затруднит поиск по тегам, при этом эффективность индексации будет нулевой.

Весь смысл наличия тегов заключается в том, чтобы иметь возможность искать/классифицировать теги ПО. Я не понимаю, как вы могли бы сделать это так, чтобы это вообще стоило того.

Как бы вы извлекли список всех тегов из вашего подхода без повторов? Как бы вы извлекли все «карточки», имеющие один и тот же тег? Я имею в виду, именно поэтому существуют отношения «многие к одному» (как в реляционных базах данных).
 

Dantees


Рег
28 Feb, 2016

Тем
0

Постов
2

Баллов
2
  • 04, Jun 2024
  • #5
@смертельная тень

PDO работает намного медленнее, чем mysqli,

и нет никакого преимущества в безопасности при использовании PDO вместо mysqli.

Однако вы продолжаете говорить о mysqli так, как будто это какой-то древний устаревший метод.

Это процедурный подход «mysql», который не поддерживается PHP, а не mysqli.

https://code.tutsplus.com/tutorials/pdo-vs-mysqli-which-should-you-use--net-24059

Запросы Mysqli выполняются намного быстрее, чем запросы PDO.

О ePowerPress,

Есть всего 5 функций, которые вам нужно изменить, чтобы использовать другой драйвер, PDO, ms-sql или что угодно.

Я не собираюсь использовать медленный PDO, если точно знаю, что мое программное обеспечение будет использоваться с my-sql в 99% случаев.

Вы говорите, что переменная в подходе запроса менее безопасна.

Покажите мне пример, где «экранированная строка в запросе» менее безопасна, чем подготовленный оператор.

Я прошу только один пример.

Мой код для «вставки»

"вставить в tagTable (cardID, tag) значения $data";

Ваш комментарий

Опять же, добавление переменных в строку запроса, где они не имеют НУЛЕВОГО значения.

Вы ведь прочитали строку над этим кодом, верно?

Что находится в $data?

Это:

('1', 'тег1'), ('1', 'тег2')

"вставить в таблицу (cardID, tag) значения

('1', 'тег1'), ('1', 'тег2')

";

Как это неправильно?

Как вы предлагаете делать вставку?

Приведите пример без передачи переменных

А еще, если вы забыли,

MySQL, требующий чтения 3 таблиц, увеличивает нагрузку на процессор и оперативную память.

Что дешевле? Жесткий диск или оперативная память?

Что влияет на производительность, потребление жесткого диска или оперативной памяти?

Таким образом, при использовании подхода с двумя таблицами мы использовали больше жесткого диска, но сэкономили на оперативной памяти.

ОЗУ остается свободной, насколько это возможно, для «нескольких процессов».

По вашему вопросу:

Как вы запрашиваете сообщения по тэгу?

Ответом на это является последний запрос в выбранном ответе.

"выберите c.*, group_concat(t.tag) в качестве тегов

из карточекТаблица как c

левые теги объединенияТаблица как т

на c.cardID = t.cardID

где c.cardID != '1' и

t.tag in('$tags')

группировать по c.cardID лимит 10";

Я знаю, что ты сейчас напишешь,

замена переменных в запросе.

На что мой ответ:

покажите мне хотя бы один пример, где

«экранированная переменная в запросе» менее безопасна.

Вместо того, чтобы позволить механизму базы данных выполнить экранирование, я делаю это вручную перед отправкой запроса в базу данных.

Что не так с этим?

Просто сказать, что это неправильно, меня не удовлетворяет.

Назовите мне причину, почему это неправильно.

Покажите мне пример, где менее безопасна «экранированная переменная в запросе».

10 лет назад люди предпочитали XHTML HTML.

Что случилось?

Я не собираюсь использовать PDO просто потому, что 20 человек кричали на меня за то, что я его не использую.

Mysqli намного быстрее, и мое программное обеспечение будет использоваться с движком my-sql, поэтому я выбираю mysqli, и так оно и останется.
 

Danil Sapegin1


Рег
01 Feb, 2013

Тем
0

Постов
2

Баллов
2
  • 04, Jun 2024
  • #6
@смертельная тень

Нет, это не то, что я делаю.

Я не выполняю все эти проверки «существует ли тег».

В этом преимущество двухтабличной структуры и уменьшения количества запросов.

В этой структуре

tagID основной автоматический

cardID целое число

тег varchar

Нет необходимости проверять, существует тег или нет.

При добавлении новой карточки в таблицу добавляются все теги вместе с ней.

$данные="";

foreach($теги как $v){

$v=addslashes($v);

$data.="('$cardID', '$v'),";

}//foreach заканчивается

$data= Trim($data, ",");

Этот код подготовит один ввод запроса следующим образом:

$data="( '1', 'тег1'),( '1', 'тег2')";

Который отправляется в базу данных одним запросом следующим образом:

"вставить в tagTable (cardID, tag) значения $data";

Во-вторых, мой код — это пример кода, который не предназначен для копирования.

Можно изменить его, чтобы использовать PDO или что-то еще, что они хотят.

Я использую mysqlI и буду продолжать использовать mysqli

Я не буду использовать PDO.

PDO — это драйвер, не зависящий от базы данных.

Это означает, что код можно импортировать в ms-sql, my-sql или другие поддерживаемые базы данных PDO.

Это также означает, что функциональность PDO ограничена.

Функции для ms-sql будут отличаться от функций my-sql.

Это означает, что если мне придется использовать PDO, мне придется прекратить использование определенных функций, предоставляемых my-sql, которые не поддерживаются PDO, но поддерживаются mysqli.

Итак, когда я знаю, что использую движок my-sql, тогда почему я должен выбирать драйвер, не предназначенный для конкретной базы данных?

Я не вижу никакого вреда в отправке переменных в самом запросе, если переменная экранирована.

Весь смысл экранирования переменных состоит в том, чтобы хакер не смог вставить запрос в данные формы, которые отправляются в базу данных.

$form_data=

имя пользователя» (хакерский запрос здесь)

sql=

выберите * из таблицы, где username='$form_data'

Без побега это становится

выберите * из таблицы, где username='username' (хакерский запрос здесь)

запрос хакера выполнен

с экранированными $form_data то же самое становится

выберите * из таблицы, где username='username\' (хакерский запрос здесь)'

хакерский запрос не выполняется

Если кто-то использует подход «переменная в запросе» и не использует методы экранирования, то это проблема,

иначе нет.

В течение очень долгого времени я пытался найти хоть один пример, где

PDO-запрос более безопасен, чем

mysqli экранировал запрос переменной,

и я пока не нашел.
 

bAnzZzAi_4iK


Рег
04 Mar, 2014

Тем
1

Постов
2

Баллов
12
  • 04, Jun 2024
  • #7
Думаю, я понимаю, к чему вы пришли, но, чтобы убедиться, что я правильно понял, я изложу то, что, по моему мнению, вы имеете в виду.

1. Сохраните название и описание карты в таблице карточек.

2. Сохраните идентификатор карты вместе с массивом тегов в таблице тегов.

Затем отобразить их;

а. Найдите в таблице тегов определенный тег и сохраните идентификатор карты в массиве.

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

Надеюсь, это поможет объяснить ситуацию немного лучше.

Раньше я использовал только отдельные таблицы.

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

Я могу понять теорию нормализации, но не имея возможности применить ее на практике, у меня не может быть этого «Ага!» момент, чтобы увидеть, что я делаю правильно или неправильно.
 

AlexeyVas


Рег
08 Aug, 2014

Тем
1

Постов
3

Баллов
13
  • 06, Jun 2024
  • #8
Это классическая ситуация HABTM (has_and_belongs_to_many). Большинство систем удаляют все записи из таблицы CARD_TAG перед их запуском, поскольку поиск удаленных тегов затруднителен, и быстрее просто удалить партию и вставить те, которые, как мы знаем, существуют.
  • сохраните карту, сохраните номер card_id
  • удалить все записи в CARD_TAG для этой карты
  • для каждого card_tag

    • выполните поиск, чтобы получить идентификатор из таблицы TAG
    • если нет, то вставьте, используйте Last_id(), чтобы получить tag_id
    • вставьте в CARD_TAG, используя card_id и tag_id


 

doob21


Рег
18 May, 2015

Тем
1

Постов
3

Баллов
13
  • 08, Jun 2024
  • #9
@смертельная тень прочитай это Почему 14 лет назад вам посоветовали использовать подготовленные утверждения и действительно ли это полезно...
https://stackoverflow.com/questions...-statements-for-mysql-in-php-performance-wise

Обратите внимание на комментарий после этого, который я скопировал ниже: PDO не кэширует подготовленные операторы. Кто-то написал: «Использование подготовленных операторов никогда не бывает плохой идеей» Дан ответ: Не правда.

Вы можете легко заполнить кэш подготовленных операторов и превысить max_prepared_stmt_count, если не знаете, что делаете, что сделает ваше приложение бесполезным до тех пор, пока соединения, использующие подготовленные операторы, не будут закрыты.

Подготовленные операторы специально разработаны для узких внутренних циклов вашей бизнес-логики, когда вы будете вызывать один и тот же базовый запрос снова и снова.

Хорошим примером является параметризованный запрос, например: ВЫБЕРИТЕ имя, адрес, телефон из таблицы WHERE id = ? и у вас разные идентификаторы при каждом звонке.

Таким образом, стоит дополнительно обратиться к базе данных для подготовки, потому что вам, вероятно, придется вызывать ее сотни или тысячи раз и просто менять параметр.

Но вы должны удалить подготовленный оператор из кеша или закрыть соединение в конце, скажем, вашего сценария без сохранения состояния (php, perl, jsp, Ruby и т. д.).

Если вы не удалите подготовленный оператор и используете пул соединений, вы неизбежно заполните кеш со временем и получите неприятную ошибку «Невозможно создать больше, чем операторов max_prepared_stmt_count».

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

Если нет, то вы, вероятно, ищете, чтобы позволить mysql использовать свой базовый кеш запросов, который представляет собой механизм, отличный от подготовленного списка операторов, и который, насколько я понимаю, ведет себя как настоящий кеш LRU.

делиться
 

esc cancel


Рег
18 Jul, 2012

Тем
0

Постов
1

Баллов
1
  • 12, Jun 2024
  • #10
@JEET, сейчас 2020 год, а не 2006 год.

что за вставка переменных в строки запроса и все такое, что добавляет мусор? Допустим, вы пришли из такой формы:
 

if (

empty($_POST['title']) ||

empty($_POST['content'])

) {

// resend form as invalid

} else { // form data valid

$stmtInsertCard = $db->prepare('

INSERT INTO card {

title, content

} VALUES (

?, ?

}

');

$stmtInsertCard->execute[$_POST['title'], $_POST['content']);

if (!empty($_POST['tags'])) {

$card_id = $db->lastInsertId();

$tags = explode($_POST['tags'], ',');

$stmtFindTagId = $db->prepare('

SELECT id

FROM tags

WHERE name = ?

');

$stmtInsertTag = $db->prepare('

INSERT INTO tags (

name

) VALUES (

?

)

');

$stmtHookTagToCard = $db->prepare('

INSERT INTO card_tags (

card_id, tag_id

) VALUES (

?, ?

)

');

foreach ($tags as $tagName) {

$tagName = trim($tagName);

$stmtFindTagId->execute([$tagName]);

if (!($tag_id = $stmtFindTagId->fetchColumn())) {

$stmtInsertTag->execute([$tagName]);

$tag_id = $db->lastInsertId();

}

$stmtHookTagToCard->execute([$card_id, $tag_id]);

} // foreach $tags

} // if $_POST['tags']

} // form data valid

Код (разметка): Предположим, $db — это подключенный объект PDO.

Я буду использовать PDO, нигде я не вижу, какой механизм API или SQL используется.

и почему все наоборот?!? Предположим также, что все ваши идентификаторы являются правильным индексом/автоинкрементом для такой структуры:
  CREATE TABLE cards { id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, title VARCHAR(128), content BLOB } CREATE TABLE tags { id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(32) INDEX (name) } CREATE TABLE card_tags { card_id BIGINT UNSIGNED, tag_id BIGINT UNSIGNED INDEX (card_id) }
Код (разметка): PHP будет выглядеть примерно так:
  <form action="addCard.php" method="post"> <h2>Add Card</h2> <fieldset> <label> Title:<br> <input type="text" name="title" required><br> </label><label> Content:<br> <textarea name="content" required><br> </label><label> Tags: <em>(comma delimited)</em><br> <input type="text" name="tags" placeholder="тег1, тег2 и т. д."><br> </label> <button>Create Card</button> </fieldset> </form> 
Код (разметка): Внимание, код непроверенный, поэтому могут быть опечатки. Тем не менее, дает вам общее представление. Если вы работаете с массивом одинаковых значений/индексов, просто добавьте цикл for вокруг приведенного выше и замените $_POST именем вашего внутреннего массива. Чтобы разобраться в этом, сначала используйте подготовленные запросы, чтобы логика внутри ваших циклов была чище/проще.

Он также выполняет автоматическую очистку, поэтому в строках запроса нет никаких устаревших переменных, вносящих дерьмо, с продолжающимся мусором с косыми чертами.

И снова это 2020 год, НИКТО этот идиотизм присутствует в любом коде, написанном примерно после 2006 года. Сначала добавьте новую карту. Если есть теги, мы берем идентификатор новой карты, разделяем теги запятой, затем PDO-> подготавливаем три запроса, которые нам понадобятся для тегов.

Один, чтобы проверить, существует ли тег, и если да, получить его идентификатор, один, если он не существует, чтобы добавить новый тег, а затем один, чтобы связать тег с карточкой. Прокрутите теги, удалите из них лишние пробелы, а затем посмотрите, сможем ли мы найти, существует ли оно уже.

Если он не существует, создайте новый и получите его идентификатор, а затем, получив идентификатор тега, мы подключаем его к таблице «один ко многим». Это то, что вы пытаетесь сделать? Опять дикие догадки, поскольку вы не сказали ни API, ни механизма SQL.
 

advaction


Рег
12 Oct, 2012

Тем
0

Постов
3

Баллов
3
  • 13, Jun 2024
  • #11
Теги по-прежнему находятся в отдельной таблице, только cardID является дополнительным столбцом в таблице тегов.

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

В программном обеспечении ePowerPress, которое есть в моей подписи, у меня есть структура из трех таблиц, но мне это было нужно, потому что тег сохраняется только «один раз» в таблице тегов.

И различные сообщения, использующие один и тот же тег, просто создают ссылку, используя postID и tagID в этой третьей таблице.

В случае этого пользователя они не сохраняют тег только один раз.

Они просто хотят хранить теги карточек в легкодоступном виде.

Для этого очень хорошо подходит структура из 2 таблиц, ею гораздо проще управлять, чем структурой из 3 таблиц.
 

CalmPay


Рег
09 Dec, 2015

Тем
1

Постов
3

Баллов
13
Тем
49554
Комментарии
57426
Опыт
552966