SQL查询以替换多对多表中模板中的多个值

时间:2019-01-25 14:38:14

标签: sql postgresql replace many-to-many

我想在sql查询中翻译模板。假设有以下四个表:state,stateProperty,state_stateproperty和translation:

state_state属性

|---------------------|--------------------|
|      state_id       | stateproperties_id |
|---------------------|--------------------|
|          1          |        2           |
|---------------------|--------------------|
|          1          |        3           |
|---------------------|--------------------|

状态属性

|---------------------|------------------|
|  id  |     key      |      value       |
|------|--------------|------------------|
|  2   | ${firstName} |      John        |
|------|--------------|------------------|
|  3   | ${lastName}  |      Doe         |
|------|--------------|------------------|

状态

|---------------------|
|  id  |  template    |
|------|--------------|
|  1   |  template    |
|------|--------------|

翻译

|------------|--------------|---------------------------------|
|  language  |  messageId   |             value               |
|------------|--------------|---------------------------------|
|  en        |  template    | ${lastName}, ${firstName} alarm |
|------------|--------------|---------------------------------|

目标是获得一个名为translationstate的新实体,其中包括该状态的转换后的模板。在此示例中,翻译后的模板看起来像:“ Doe,John警报”。如何在本机sql中联接多对多表,并使用其相关状态属性的值转换状态模板?

1 个答案:

答案 0 :(得分:1)

说实话,我会创建一个小函数,在其中遍历您的state_property并用文本将找到的通配符字符串替换为原来的文本。


但是我有一些乐趣可以在查询中解决它。我不确定它是否与所有特殊情况都匹配,但对于您的示例来说,它可以工作:

demo:db<>fiddle

SELECT
    string_agg(                                                           -- 8
        regexp_replace(split_key, '^.*\}', value),                        -- 7
        '' ORDER BY row_number
    )
FROM (
    SELECT
        s.id,
        sp.value,
        substring(key, 3) as s_key,                                       -- 5
        split_table.*
    FROM translation t
    JOIN statechange sc ON t.messageid = sc.completemessagetemplateid     -- 1
    JOIN state s ON s.id = sc.state_id
    JOIN state_stateproperty ssp ON s.id = ssp.state_id
    JOIN stateproperty sp ON ssp.stateproperties_id = sp.id
    JOIN translation stnme ON s.nameid = stnme.messageid
    CROSS JOIN                                        
        regexp_split_to_table(                                            -- 3   
            -- 2
            replace(t.messagetranslation, '${state}', stnme.messagetranslation),
            '\$\{'
        ) WITH ORDINALITY as split_table(split_key, row_number)           -- 4
    WHERE t.language = 'en'
) s
WHERE position(s_key in split_key) = 0 and split_key != ''                -- 6
GROUP BY id                                                               -- 8
  1. 简单地将表连接在一起(下一次,您可以稍微简化一下示例,以免我们不必创建这些不同的表。我确定您知道如何连接)
  2. 几乎不将${state}变量替换为状态nameid
  3. 每次找到${字符串时,都会拆分模板字符串。因此,它将创建一个新行,该行以某个通配符开头。请注意,${firstName}将成为firstName},因为正在删除字符串定界符。
  4. 添加行数以获取准则,以便以后在汇总行时如何对行进行排序(8)。 WITH ORDINALITY仅作为FROM子句的一部分,因此它的全部功能已通过联接添加到此处。
  5. 由于(3),我也从键中剥离了${部分。这样可以更好地解析和比较(在6中)
  6. 因为(3)创建的行过多(交叉连接),所以我只需要key是我的拆分字符串的第一个通配符的行。其他所有人都是错误的。
  7. 现在我用此密钥替换通配符
  8. 由于每行只有一个通配符,因此我们需要将它们再次合并为一个字符串(按state_id分组)。为了实现正确的顺序,我们使用的是(5)中的行号