Создать матрицу / таблицу из LEFT JOIN в SQL - PullRequest
1 голос
/ 20 июля 2009

Мне бы хотелось узнать хорошее решение для преобразования LEFT JOIN в таблицу / матрицу.

Например, для данной схемы:

objects
   id (integer)
   name (string)

attributes
   id (integer)
   object_id (integer)
   name (string)
   value (string)

И эти значения:

1,ball
2,box

1,1,colour,red
2,1,shape,sphere
3,1,material,rubber
4,2,colour,brown
5,2,shape,cube

Я бы хотел получить это:

object_id | object_name | colour | shape  | material

1         | ball        | red    | sphere | rubber
2         | box         | brown  | cube   | NULL

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

Ответы [ 4 ]

1 голос
/ 20 июля 2009

С RDBMS s дело в том, что их цель - хранить и представлять то, что у вас уже есть. Динамическое создание столбцов никогда не предполагалось.

Это случай, который должен быть обработан на клиенте, который должен представлять данные.

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

1 голос
/ 20 июля 2009

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

Любой набор SQL имеет дело с фиксированным числом столбцов с фиксированными именами.

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

Например, представьте представление, созданное по запросу, который вы запрашиваете (если бы это было возможно):

SELECT  object_id, colour
FROM    myquery

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

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

Если у вас есть таблица attribute_names, которая содержит все возможные имена ваших атрибутов, вы можете сделать что-то вроде этого:

SELECT  o.name, an.name, a.value
FROM    objects o
CROSS JOIN
        attribute_names an
LEFT JOIN
        attributes a
ON      a.object = o.id
        AND a.name = an.name

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

0 голосов
/ 26 марта 2011

Хм, возможно, вы просто пропустили 2 логических шага, чтобы это произошло.

Вам нужна таблица AttributeTypes и таблица AttributeValues.

objects
   id (integer)
   name (string)

attribute_types
   id (integer)
   name (string)
   description (string)
   enabled (bit)

attribute_values
   id (integer)
   attribute_type_id (integer)
   value (string)
   enabled (bit)

attributes
   id (integer)
   object_id (integer)
   attribute_type_id (integer)
   attribute_value_id (integer)

Таким образом, объект может иметь атрибуты, эти атрибуты указываются посредством attribute_type_id и attribute_value_id.

Это позволяет вам иметь объект с несколькими атрибутами.

1010 * например *

object 
-> 1, ball

attribute_types
-> 10, Colour, null, enabled
-> 20, Shape, null, enabled
-> 30, Material, null, enabled

attribute_values 
-> 100, 10, blue, enabled
-> 200, 10, red, enabled
-> 300, 10, green, enabled

-> 400, 20, round, enabled
-> 500, 20, square, enabled
-> 600, 20, triangle, enabled

Таким образом, атрибут будет выглядеть так:

attributes
-> 1000, 1, 10, 100 // this item has a color and it is blue
-> 1001, 1, 20, 400 // this item has a shape and it is round
-> 1002, 1, 10, 200 // this item has a color and it is red

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

@attribute_type_id = select Id from attribute_types where name = 'Color' // 10

select * from objects 
inner join attributes on objects.id = attributes.object_id
inner join attribute_values on objects.attribute_value_id = attribute_values.id
where attribute_type_id = @attribute_type_id
and attribute_values.value= 'blue'

И вот, у вас это есть, вы должны вернуть каждый объект, у которого есть attribute_type цвета и attribute_value синего цвета.

Мой Sql не так силен, но вы должны иметь возможность выполнить более одного предложения, если вы хотите искать несколько атрибутов одновременно. По моему мнению, attribute_type_id в таблице атрибутов не объединен с таблицей attribute_type, но это может облегчить выполнение запроса за 1 попадание, с точки зрения производительности, хотя он у меня будет, поэтому он ускорит запросы, не присоединяясь к таблица, но разница может быть незначительной в зависимости от того, насколько большой все становится.

Примечание: я обычно работаю с msssql, а не с mysql, поэтому, если типы баз данных не совпадают, вот почему.

0 голосов
/ 20 июля 2009

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

insert into merged (object_id, object_name) select id, name from objects;
update merged m inner join attributes a on a.object_id = m.object_id and a.name = 'colour' set m.colour = a.value;
update merged m inner join attributes a on a.object_id = m.object_id and a.name = 'material' set m.material = a.value;
update merged m inner join attributes a on a.object_id = m.object_id and a.name = 'shape' set m.shape = a.value;
...