分组替换

时间:2014-04-17 09:57:16

标签: mysql sql replace group-by group-concat

图像这些表

Table sentence
--------------------------------------------------
| id    | value         | 
--------------------------------------------------
| 1     | I own a $1 $3.|
--------------------------------------------------

Table sentence_word_relations
--------------------------------------------------
| sentence_id   | word_id            
--------------------------------------------------
| 1             | 1                 
--------------------------------------------------
| 1             | 3                 
--------------------------------------------------

Table word
--------------------------------------------------
| id            | value              
--------------------------------------------------
| 1             | red                   
--------------------------------------------------
| 2             | blue                  
--------------------------------------------------
| 3             | bike                  
--------------------------------------------------
| 4             | house                 
--------------------------------------------------

一个人应该可以创建多个句子:我拥有一个红色/蓝色的自行车/房子。这取决于句子包含的单词变量。一旦更新了句子并且美元符号后面的值发生变化,关系表就会相应地更新。以下查询...

SELECT
    REPLACE(sentence.value, CONCAT('$', word.id), word.value) AS sentence
FROM sentence
JOIN sentence_word_relations
ON sentence.id = sentence_word_relations.sentence_id
JOIN word
ON sentence_word_relations.word_id = word.id

...自然地返回两行:

- I own a red $3.
- I own a $1 bike.

我想知道是否有可能返回一行,在这种情况下即:我拥有一辆红色自行车。

1 个答案:

答案 0 :(得分:1)

如果你只有2个单词,那么你可以使用它: -

SELECT REPLACE( REPLACE(sentence.value, CONCAT('$', word1.id), word1.value), CONCAT('$', word2.id), word2.value) AS sentence
FROM sentence
JOIN sentence_word_relations AS swr1 ON sentence.id = swr1.sentence_id
JOIN word AS word1 ON swr1.word_id = word1.id
JOIN sentence_word_relations AS swr2 ON sentence.id = swr2.sentence_id
JOIN word AS word2 ON swr2.word_id = word2.id

但这是非常有限的。如果替换的最大数量相当小,这可能是可行的(当替换次数少于最大值时,可以使用LEFT OUTER JOIN来处理表格)

您可以对替换进行分组,然后使用您选择的编程语言进行处理: -

SELECT sentence, GROUP_CONCAT(CONCAT_WS('~', word1.id, word1.value))
FROM sentence
JOIN sentence_word_relations AS swr ON sentence.id = swr.sentence_id
JOIN word AS word ON swr.word_id = word.id
GROUP BY sentence

您也可以这样做,但调用MySQL自定义函数来进行替换。这可能是最优雅的解决方案。

编辑 - 只是玩游戏,但是如果你使用的是php并且可以忍受一些没有人想要编辑的可怕的SQL你可以试试这个: -

SELECT sentence, 
    CONCAT('a:', COUNT( word.id), ':{', 
    GROUP_CONCAT(
    CONCAT(
    'i:',
    word.id,
    ';a:2:{',
    CONCAT('s:', LENGTH('word.id'), ':\"', 'word.id', '\";s:', LENGTH(word.id), ':\"', word.id, '\";'),
    CONCAT('s:', LENGTH('word.value'), ':\"', 'word.value', '\";s:', LENGTH(word.value), ':\"', word.value, '\";'),
    '}'
    )
    SEPARATOR ''),
    '}'
    ) AS replacement_details
FROM sentence
JOIN sentence_word_relations AS swr ON sentence.id = swr.sentence_id
JOIN word AS word ON swr.word_id = word.id
GROUP BY sentence

即将替换值格式化为php序列化数组。您可以从表中读取行,反序列化第二个字段并循环执行替换的元素。你可以做类似的事情来构建一个可以用更多种语言处理的JSON编码数组。

除非在特殊情况下,否则说这更多是为了娱乐而非严肃的建议。

顺便说一句,如果您的替换单词可以包含任何字符,那么您也有一个潜在的问题,替换是不同值的标记(即,说单词1实际上是'$ 3',那么句子中的$ 1将是更改为$ 3,然后当下一次更换完成后将更改为自行车,给出一串'我拥有一辆自行车。'