Выбор отдельных пар значений в EAV - PullRequest
1 голос
/ 24 января 2012

Я работаю над базой данных пользователей, в которой данные профиля были изменены из простой таблицы в таблицу Entity-Attribute-Value.

Где, как и прежде, структура была вдоль этих линий:

userid (int)
address 1 (varchar)   
city (varchar)
country (varchar)

Теперь это так:

userid (int)
key (varchar)  
value (varchar) 

например

userid key      value
150    city     London
150    country  UK
151    city     New York
151    country  USA
152    country  Mexico   

Мне нужно получить отдельный список пар город / страна и количество пользователей в каждой стране:

city      country  count
London    UK       18
New York  USA      25

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

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

Ответы [ 2 ]

2 голосов
/ 24 января 2012

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

Города и страны для каждого идентификатора пользователя:

SELECT a.userID, a.value AS city, b.value AS country
  FROM EAV AS a
  JOIN EAV AS b ON a.UserID = b.UserID
 WHERE a.key = 'city'
   AND b.key = 'country';

Итак, вы получите:

SELECT city, country, count(*)
  FROM (SELECT a.userID, a.value AS city, b.value AS country
          FROM EAV AS a
          JOIN EAV AS b ON a.UserID = b.UserID
         WHERE a.key = 'city'
           AND b.key = 'country'
       ) AS c
 GROUP BY city, country;

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

Это совершенно сознательно и сознательно игнорирует пользователей, у которых есть город, и нет страны, или страны, и города (не говоря уже о тех, у кого их нет).Расширение решения для решения этих проблем является лишь умеренно болезненным - я полагаю, что в конечном итоге вы получите трехсторонний UNION, хотя, возможно, вам удастся придумать что-то с помощью нескольких левых внешних объединений.Но тот факт, что данные могут быть введены в систему EAV без необходимых ограничений для обеспечения наличия города и страны для пользователя, является просто одной из многих причин отказа от EAV.

Извинитеты навязал это тебе.Я рекомендую смотреть на http://careers.stackoverflow.com/ как на выход из вашей боли, потому что это только начало.


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

SELECT a.userID, b.value AS city, c.value AS country
  FROM (SELECT DISTINCT UserID FROM EAV) AS a
  LEFT JOIN EAV AS b ON a.UserID = b.UserID
  LEFT JOIN EAV AS c ON a.UserID = c.UserID
 WHERE b.key = 'city'
   AND c.key = 'country';

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

0 голосов
/ 24 января 2012

re: Мне нужен отдельный список пар город / страна

SELECT DISTINCT country,city
FROM
(SELECT DISTINCT userid, VALUE AS country FROM TABLE WHERE KEY = 'country') country INNER JOIN
(SELECT DISTINCT userid, VALUE AS city FROM TABLE WHERE KEY = 'city') city ON
country.userid = city.userid

--count of all users for each country
SELECT VALUE AS country, 
COUNT(DISTINCT userid) AS user_count 
FROM TABLE 
WHERE KEY = 'country'
GROUP BY 
VALUE
...