Как использовать строки как поля в базе данных SQL - PullRequest
1 голос
/ 07 октября 2010

У меня вопрос, связанный с SQL, относительно общей структуры базы данных, которая кажется довольно распространенной.Однажды я придумал это, пытаясь решить проблему, и (позже) я видел, как другие люди делают то же самое (или что-то удивительно похожее), поэтому я думаю, что сама структура имеет смысл.У меня просто возникают проблемы при попытке сформировать определенные запросы к нему.

Идея состоит в том, что у вас есть таблица с "элементами" в ней, и вы хотите сохранить набор полей и их значений для каждого элемента.Обычно это можно сделать, просто добавив столбцы в таблицу элементов, проблема в том, что сами поля (а не только значения) меняются от элемента к элементу.Например, у меня может быть два элемента:

Статья 1
product_id = aproductid
hidden_key = ahiddenkeyvalue
Статья 2
product_id = anotherproductid
address = anaddress

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

Структура в базе данных заканчивается примерно так:

ItemsTable
id
itemdata_1
itemdata_2
...

FieldsTable
id
field_name
...

Итаблица, которая связывает их и заставляет работать

FieldsItemRelationsTable
field_id
item_id
value


Хорошо, когда я пытаюсь сделать что-то, чтовключает в себя только одно значение "динамического поля", нет проблем.Я обычно делаю что-то похожее на:
SELECT i.* FROM ItemsTable i
INNER JOIN FieldsItemRelationsTable v ON v.item_id = i.id
INNER JOIN FieldsTable f ON f.id = v.field_id
WHERE v.value = 50 AND f.name = 'product_id';

, который выбирает все элементы, где product_id = 50

Проблема возникает, когда мне нужно сделать что-то с несколькими значениями «динамического поля».Скажем, я хочу выбрать все элементы, где product_id = 50 AND hidden_key = 30. Возможно ли это с помощью одного оператора SQL?Я пытался:

SELECT i.* FROM ItemsTable i
INNER JOIN FieldsItemRelationsTable v ON v.item_id = i.id
INNER JOIN FieldsTable f ON f.id = v.field_id
WHERE (v.value = 50 AND f.name = 'product_id')
AND (v.value = 30 AND f.name = 'hidden_key');

Но он просто возвращает ноль строк.

Ответы [ 3 ]

2 голосов
/ 07 октября 2010

Вам нужно будет выполнить отдельное объединение для каждого возвращаемого вами значения ...

SELECT i.* FROM ItemsTable i 
INNER JOIN FieldsItemRelationsTable v ON v.item_id = i.id 
INNER JOIN FieldsTable f ON f.id = v.field_id 
INNER JOIN FieldsItemRelationsTable v2 ON v2.item_id = i.id 
INNER JOIN FieldsTable f2 ON f2.id = v2.field_id 
WHERE v.value = 50 AND f.name = 'product_id'
AND (v2.value = 30 AND f2.name = 'hidden_key'); 

э-э ... этот запрос может не работать (немного работы копирования / вставки шламас моей стороны), но вы поняли ... вам понадобится второе значение, хранящееся во втором экземпляре таблиц (v2 и f2 в моем примере здесь), которое отделено от первого экземпляра.v1.value = 30 и v2.value = 50. v1.value = 50 и v1.value = 30 никогда не должны возвращать строки, так как ничто не будет равняться 30 и 50 одновременно

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

SELECT i.* FROM ItemsTable i 
INNER JOIN FieldsItemRelationsTable v ON v.item_id = i.id and v.value = 50 
INNER JOIN FieldsTable f ON f.id = v.field_id and f.name = 'product_id'
INNER JOIN FieldsItemRelationsTable v2 ON v2.item_id = i.id and v2.value = 30 
INNER JOIN FieldsTable f2 ON f2.id = v2.field_id and f2.name = 'hidden_key'

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

1 голос
/ 07 октября 2010

Извините, что расплывчато, но я бы изучил ваши варианты подробнее.

0 голосов
/ 30 октября 2010

Попробуйте сделать несколько левых или правых объединений, чтобы увидеть, если вы получите какие-либо результаты.Внутренние объединения не будут возвращать результаты иногда, если есть пустые поля.

это начало.

Не забывайте, внешнее соединение = декартово произведение

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