2016-10-04 2 views
1

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

dbo.Products 
ProductID | Description 
1   | An amazing product 
2   | An even more amazing product 
3   | Don't buy this one 

dbo.ProductTranslations 
ProductID | Language | Description 
1   | EN-US | null 
1   | FR-CA | Un produit étonnant 
2   | EN-US | null 
2   | FR-CA | Un produit encore plus étonnant 
3   | EN-US | null 
3   | FR-CA | Ne pas acheter celui-ci 

То, что я хотел бы сделать, это в основном сглаживаться, что так, все продукты и переводы находятся в одной таблице и конденсируются в одну строку для каждого продукта, как это:

dbo.FlattenedProducts 
ProductID | EN-US_Description   | FR-CA_Description 
1   | An amazing product   | Un produit étonnant 
2   | An even more amazing product | Un produit encore plus étonnant 
3   | Don't buy this one   | Ne pas acheter celui-ci 

Я порылся примеров, как this one о повороте и this one где лучшее предложение (производительность мудрая), кажется, использует убивание случае заявления, но я изо всех сил, чтобы применить их к моей ситуации. Использование операторов case, подобных этой второй ссылке, позволяет мне сделать переводы линейными, но это не уменьшает общее количество элементов. Я работаю с 40 миллионами строк (и, в конечном счете, с дюжиной или около того), поэтому скорость критическая, и использование выделенного, отличного от всех этих данных, просто убивает производительность, мне нужно, чтобы данные уже были дезинфицированы прямо из оператора select.

Есть ли какой-то трюк в этом, я не хватает?

Редактировать: Я должен отметить, что иногда в переводе есть реальные значения, когда это «EN-US» (не спрашивайте, почему, я не проектировал это), и им необходимо переопределить оригинал поэтому я не могу просто SELECT WHERE Language != 'EN-US' или тому подобное. Также есть больше языков, чем только английский и французский, я просто упростил его для демонстрационных целей.

ответ

1

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

SELECT 
    p.ProductID, 
    MAX(CASE WHEN pt.Language = 'EN-US' THEN COALESCE(pt.Description, p.Description) END) AS ENUS_Description, 
    MAX(CASE WHEN pt.Language = 'FR-CA' THEN pt.Description END) AS FRCA_Description 
FROM dbo.Products p 
LEFT JOIN dbo.ProductTranslations pt ON p.ProoductID = pt.ProductID 
GROUP BY p.ProductID 

Edit: Добавлен COALESCE() согласно вашему редактированию, чтобы дать более высокий приоритет английского переводу из таблицы переводов - если это нуль, то возьмите оригинальное описание из таблицы продуктов.

Для других языков просто добавьте соответствующие строки, которые будут выглядеть как один для FR-CA, но с другим языковым значением.

+0

Из любопытства, в чем заключается цель заявления GROUP BY? Если я оставлю это, я получаю сообщение об ошибке, но я не уверен, зачем это нужно начинать. – thanby

+1

Он вернет одну строку для каждой группы (здесь: ProductID). Затем вы просто используете агрегированные функции, такие как MAX(), чтобы указать, что вы хотите максимальное значение для данной группы (для каждого языка есть только один). –

1

Самый простой и быстрый либо условной агрегации или присоединиться:

select pt.productid, 
     max(case when language = 'EN-US' then description end) as en_us, 
     max(case when language = 'CA-FR' then description end) as ca_fr 
from ProductTranslations pt 
group by productid; 

Вы можете добавить into FlattenedProducts, если вы хотите, чтобы создать таблицу.

Метод join является:

select coalesce(pte.productid, ptf.productid) as productid, 
     pte.description as us_en, 
     ptf.description as ca_fr 
from ProductTranslations pte full join 
    ProductTranslations ptf 
    on pte.productid = ptf.productid and 
     pte.language = 'EN-US' and ptf.language = 'CA-FR'; 

Это возвращает все продукты. Если вы знаете, что каждый продукт имеет по крайней мере один из каждого перевода, используйте inner join, а не full join - он более эффективен.

+0

Оба этих ответа велики, мне жаль, что я не мог принять их обоих. Спасибо за вашу помощь. – thanby

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

  • Нет связанных вопросов^_^