2013-12-14 5 views
0

У меня есть приложение для рельсов. в этом приложении я использую модуль globalize3 для i18n. У меня есть таблица news и news_translations с этими рядами locale, description и title. Я использую команду соединения, чтобы проверить текущую локаль. Это правильная работа для текущей локали. Например:Приоритетный выбор в Postgres

WHERE "news_tranlations"."locale" = 'it' 

Но я хочу сделать еще одну логику. Если пользователь от 'de', например, я показываю ему все новости с locale 'de' и все новости, которые не имеют 'de' перевод, но имеют 'en'. Когда я пытаюсь сделать это с заявлением OR, я получаю одну новость в двух переводах 'de' и 'en'. Могу ли я сделать правильно, используя что-то вроде приоритетов.

+1

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

ответ

1

Рассмотрите серьезные комментарии Дениса о производительности и изменении схемы. Тем не менее, следующее решение вашей проблемы и может быть применимо, если вы не позволяете weighted_tables стать слишком большими. Обратите внимание, в частности, что Common Table Expressions (таблицы WITH генерирует) не имеют на них индексов.

SQL Fiddle

1

Это неудобный запрос. Одним словом, вам нужно ИЛИ потенциальных строк, а затем вычислить верхнюю строку наборов результатов, упорядоченных по case when locale = 'it' then 1 when ... end. Есть много способов получить правильный результат (в частности, функции окна), но, честно говоря, вы действительно не хотите идти туда по соображениям производительности.

Methinks пересмотреть свои предположения или изменить схему.

Одним из способов сделать это достаточно быстро является добавление столбца массива к новостям, например. languages, который поддерживается триггером. Отфильтруйте верхние новости (что я предполагаю, это то, что вы извлекаете), используя это вместо объединения с переводами. (Примечание: в зависимости от вашей версии Postgres избегайте добавления индекса GIST в этот столбец, поскольку избирательность оператора && была жестко запрограммирована и превзошла бы порядок заказа/limit/offset, используя btree за пределами определенной строки.)

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

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

1

Вы можете использовать DISTINCT и ORDER BY, чтобы обмануть его.

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

SELECT 
    DISTINCT ON (n.news_id), 
    n.news_id, 
    nt.title, 
    nt.description 
FROM 
    news n INNER JOIN news_translation nt 
ON 
    n.news_id = nt.news_id 
ORDER BY 
    n.news_id, 
    nt.locale != 'de', 
    nt.locale != 'en', 
    nt.locale; 

Этот запрос всегда будет возвращать вам новостные статьи раз (без дубликатов и множественных переводов), и желательно дать вам перевод de (если он существует), если он не попадет в «en», и, наконец, если оба они не существуют, это даст вам первый перевод по заказу «locale».

+0

'ОШИБКА: недействительный UNION/INTERSECT/ЗА ИСКЛЮЧЕНИЕМ ЗАКАЗА BY статья LINE 191: locale!= 'de'' Получить ошибку в инструкции 'ORDER BY' – itdxer

Смежные вопросы