以复杂的方式组合两个表

时间:2013-07-03 16:35:32

标签: mysql sql

情况:

我有主表,我们称之为MainTable

+---------+----------+----------+----------+ 
|  Id (PK)| Title    | Text     | Type     |
+---------+----------+----------+----------+ 
|   1     | Some Text|More Stuff| A        | 
|   2     | Another  | Example  | B        | 
+---------+----------+----------+----------+ 

我有一个名为TranslationsTable的第二个表,其中Id字段是MainTable行Id的表示(没有外键,因为它可以引用不同的表),ObjType是ObjectType(与表相同),FieldName是ObjecType中字段的名称,值具有ObjType表中FieldName值的转换值。

+---------+-----------+-----------+------------+----------+
|   Id    | ObjType   | FieldName | Value      | Language |
+---------+-----------+-----------+------------+----------+
|   1     | MainTable | Title     | Algum Texto| PT       |
|   1     | MainTable | Text      | Mais Coisas| PT       |
+---------+-----------+-----------+------------+----------+

因为我需要在翻译的字段中搜索,我想我可以使用TEMPORARY TABLE这样做,但后来出现了“我应该使用哪个SELECT查询?”的问题。我读了一些关于数据透视表查询的帖子,但我真的不知道我如何构建一个查询,所以我的临时表类似于

+---------+------------+------------+----------+ 
|  Id (PK)| Field_1    | Field_2    | Field_3  |
+---------+------------+------------+----------+ 
|   1     | Algum Texto| Mais Coisas| A        |  
+---------+------------+------------+----------+ 

谢谢。

编辑:

我接受了AD7six的答案,因为在MainTable中有500.000个条目,在翻译中有1.500.000个条目,它大约是另一个条目的30倍。

2 个答案:

答案 0 :(得分:2)

SELECT
  orig.Id,
  COALESCE(xlate.Field_1, orig.Field_1) AS Field_1,
  COALESCE(xlate.Field_2, orig.Field_2) AS Field_2,
  COALESCE(xlate.Field_3, orig.Field_3) AS Field_3
FROM MainTable orig
INNER JOIN (
  SELECT
    Id,Field_1,Field_2,Field_3
  FROM TranslationsTable
  PIVOT(MIN(Value) FOR FieldName IN (Field_1,Field_2,Field_3)) p
  WHERE ObjType = 'MainTable'
) xlate ON (orig.Id = xlate.Id)

如果要在MainTable中包含TranslationsTable中没有匹配项的(未翻译的)行,请将INNER JOIN更改为LEFT OUTER JOIN

另一种方法是手动执行转轴:

SELECT
  orig.Id,
  COALESCE(xlate.Field_1, orig.Field_1) AS Field_1,
  COALESCE(xlate.Field_2, orig.Field_2) AS Field_2,
  COALESCE(xlate.Field_3, orig.Field_3) AS Field_3
FROM MainTable orig
INNER JOIN (
  SELECT
    Id,
    MIN(CASE FieldName WHEN 'Field_1' THEN Value END) AS Field_1,
    MIN(CASE FieldName WHEN 'Field_2' THEN Value END) AS Field_2,
    MIN(CASE FieldName WHEN 'Field_3' THEN Value END) AS Field_3
  FROM TranslationsTable 
  WHERE ObjType = 'MainTable'
  GROUP BY Id
) xlate ON (orig.Id = xlate.Id)

如其他人建议的那样更改MainTable架构,您将不需要重复(Field_1,Field_2,Field_3)。它使代码更易于维护和修改。

答案 1 :(得分:1)

那不复杂

这只是一个每个翻译字段有一个连接的查询。

这意味着您可以查询/排序/任何其他任何其他内容,例如(使用一些真实姓名,以便更容易阅读):

SELECT
    products.id,
    COALESCE(product_name.value, products.name) as name,
    COALESCE(product_description.value, products.description) as description
FROM
    products
LEFT JOIN
    TranslationsTable AS product_name
    ON (
        product_name.Language = 'PT' AND
        product_name.ObjectType = 'products' AND
        product_name.FieldName = 'name' AND
        product_name.id = products.id
    )
LEFT JOIN
    TranslationsTable AS product_description
    ON (
        product_description.Language = 'PT' AND
        product_description.ObjectType = 'products' AND
        product_description.FieldName = 'description' AND
        product_description.id = products.id
    )
WHERE
    product_name.value = "Algum Texto" // Find all products named "Algum Texto"

您不需要临时表

但是如果你想创建一个,使用查询本身很容易:

CREATE TABLE
    products_pt
AS
SELECT
    products.id,
    COALESCE(product_name.value, products.name) as name,
    COALESCE(product_description.value, products.description) as description
...

这将创建一个与查询结构匹配的表(无索引)。如果您的数据不经常更改,则可以使查询多语言数据更容易管理,但有一些缺点,例如(显然)如果源表数据发生更改,您的特定于翻译的表将不是最新的。