MySQL запрос, лучший способ написать это? - PullRequest
0 голосов
/ 17 декабря 2009

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

Привет!

Итак, у меня есть этот запрос (ниже), он не закончен и становится длинным. Мне было интересно, есть ли способ сократить это вообще или есть лучший способ сделать это ..?

SELECT user.*,
cat1id.CategoryName as cat1,
cat2id.CategoryName as cat2,
cat3id.CategoryName as cat3,
cat4id.CategoryName as cat4,
cat5id.CategoryName as cat5,
cat6id.CategoryName as cat6,
cat7id.CategoryName as cat7,
cat8id.CategoryName as cat8,
cat9id.CategoryName as cat9,
cat10id.CategoryName as cat10
FROM users AS user
LEFT JOIN Category cat1id ON user.categoryid = cat1id.id
LEFT JOIN Category cat2id ON user.categoryid_2 = cat2id.id
LEFT JOIN Category cat3id ON user.categoryid_3 = cat3id.id
LEFT JOIN Category cat4id ON user.categoryid_4 = cat4id.id
LEFT JOIN Category cat5id ON user.categoryid_5 = cat5id.id
LEFT JOIN Category cat6id ON user.categoryid_6 = cat6id.id
LEFT JOIN Category cat7id ON user.categoryid_7 = cat7id.id
LEFT JOIN Category cat8id ON user.categoryid_8 = cat8id.id
LEFT JOIN Category cat9id ON user.categoryid_9 = cat9id.id
LEFT JOIN Category cat10id ON user.categoryid_10 = cat10id.id
WHERE user.id = 65447

Спасибо!

Ответы [ 8 ]

5 голосов
/ 17 декабря 2009

Если вы используете Mysql5, вы можете попробовать написать представление.

так

CREATE VIEW big_damn_query AS 
SELECT user.*,
cat1id.CategoryName as cat1,
cat2id.CategoryName as cat2,
cat3id.CategoryName as cat3,
cat4id.CategoryName as cat4,
cat5id.CategoryName as cat5,
cat6id.CategoryName as cat6,
cat7id.CategoryName as cat7,
cat8id.CategoryName as cat8,
cat9id.CategoryName as cat9,
cat10id.CategoryName as cat10
FROM users AS user
LEFT JOIN Category cat1id ON user.categoryid = cat1id.id
LEFT JOIN Category cat2id ON user.categoryid_2 = cat2id.id
LEFT JOIN Category cat3id ON user.categoryid_3 = cat3id.id
LEFT JOIN Category cat4id ON user.categoryid_4 = cat4id.id
LEFT JOIN Category cat5id ON user.categoryid_5 = cat5id.id
LEFT JOIN Category cat6id ON user.categoryid_6 = cat6id.id
LEFT JOIN Category cat7id ON user.categoryid_7 = cat7id.id
LEFT JOIN Category cat8id ON user.categoryid_8 = cat8id.id
LEFT JOIN Category cat9id ON user.categoryid_9 = cat9id.id
LEFT JOIN Category cat10id ON user.categoryid_10 = cat10id.id;

тогда ваш запрос будет

SELECT * FROM big_damn_query bdq WHERE bdq.id = 65447
3 голосов
/ 17 декабря 2009

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

РЕДАКТИРОВАТЬ: если вы хотите преобразовать это в представление, которое (почти) нормализовано, вы можете сделать что-то вроде:

CREATE VIEW user_category AS
SELECT users.id as user_id, Category.id as category_id
FROM users INNER JOIN Category ON users.categoryid = Category.id
UNION
SELECT users.id, Category.id
FROM users INNER JOIN Category ON users.categoryid_2 = Category.id
UNION
SELECT users.id, Category.id
FROM users INNER JOIN Category ON users.categoryid_3 = Category.id
....

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

1 голос
/ 17 декабря 2009

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

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

SELECT u.*, c.CategoryName
FROM users AS u
LEFT JOIN Category AS c
 ON (c.id IN (u.categoryid,   u.categoryid_2, u.categoryid_3, u.categoryid_4, 
              u.categoryid_5, u.categoryid_6, u.categoryid_7, u.categoryid_8,
              u.categoryid_9, u.categoryid_10))
WHERE u.id = 65447;

Еще один трюк, который вы можете сделать (учитывая, что вы пометили этот вопрос mysql):

SELECT u.*, GROUP_CONCAT(c.CategoryName) AS CatList
FROM users AS u
LEFT JOIN Category AS c
 ON (c.id IN (u.categoryid,   u.categoryid_2, u.categoryid_3, u.categoryid_4, 
              u.categoryid_5, u.categoryid_6, u.categoryid_7, u.categoryid_8,
              u.categoryid_9, u.categoryid_10))
WHERE u.id = 65447
GROUP BY u.id;

Это сокращает вывод до одной строки, и все строки CategoryName объединяются вместе, разделяя их запятыми. См GROUP_CONCAT().

1 голос
/ 17 декабря 2009

Подберите книгу по дизайну базы данных и прочитайте об отношениях ...

Редактировать: обобщено на "отношения".

1 голос
/ 17 декабря 2009

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

0 голосов
/ 18 декабря 2009

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

$tables = 10;
$query = "SELECT user.*;

for ( $i = 0; $i <= $tables; $i++) {
    $query += ", cat{$i}id.CategoryName as cat{$i} ";
}

$query += " FROM users AS user";

for ( $i = 0; $i <= $tables; $i++) {
    $query += " LEFT JOIN Category cat{$i}id ON user.categoryid = cat{$i}id.id ";
}

$query += "WHERE user.id = 65447";

(Пожалуйста, извините за мой PHP, я не знаком с ним, но, надеюсь, этого достаточно, чтобы дать вам идею)

Кроме того, не забудьте параметризовать свои входные данные!

0 голосов
/ 17 декабря 2009

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

  • убедитесь, что все поля, которые вы используете в своих объединениях, проиндексированы
  • сохранить этот запрос как просмотр в базе данных.
0 голосов
/ 17 декабря 2009

Вместо того, чтобы иметь столбец categoryid_x, ваша структура таблицы должна выглядеть примерно так: (Мой синтаксис может быть немного отключен, и это очень урезано, но это должно помочь вам начать)

CREATE TABLE user (
    user_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
);

CREATE TABLE category (
    category_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
);

CREATE TABLE user_category (
    user_id INT NOT NULL,
    category_id INT NOT NULL,
    PRIMARY KEY (user_id, category_id),
    FOREIGN KEY (user_id) REFERENCES user(user_id),
    FOREIGN KEY (category_id) REFERENCES category(category_id)
);

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

Чтобы получить категории для данного пользователя:

SELECT *
FROM category
WHERE user = 65447;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...