如何在MySQL中的某些条件下为对字符串生成唯一的id

时间:2013-03-21 20:16:02

标签: mysql sql database

我是SQL的新手,请帮我解决问题。

我有一个用于网站私人消息的表,我在引擎之间迁移后得到的(phpbb到drupal)

可以说,它有3列:

  • mid - 用于消息ID
  • 主题 - 用于主题ID
  • 收件人 - 用户ID,将收到该邮件。

每封邮件都显示在收件人和邮箱的邮箱中,因此每封邮件都有2个字符串。

问题是消息的主题 ID不正确(基本上,它们等于 mid ),因此,2个用户之间的对应关系显示为一百个单独的线程。

例如:

user 100 wrote message to user 101 
user 101 replied       to user 100
user 102 wrote message to user 100

表格如下:

 ________________________________
| mid    | thread    | recipient |
|        |           |           |
| 1      | 1         | 101       |  ← message 1 in recipient's mailbox    
| 1      | 1         | 100       |  ← message 1 in author's mailbox
| 2      | 2         | 100       |    ...
| 2      | 2         | 101       |
| 3      | 3         | 100       |
| 3      | 3         | 102       |
|________|___________|___________|

我的目标是为具有相同收件人对的每对配对行提供相同的线程ID:

 ________________________________
| mid    | thread    | recipient |
|        |           |           |
| 1      | 1         | 101       |  }
| 1      | 1         | 100       |  }    Correspondence between 100 and 101 must
| 2      | 1         | 100       |  }    have the same thread id (1)
| 2      | 1         | 101       |  }
| 3      | 2         | 100       |
| 3      | 2         | 102       |
|________|___________|___________|

UPDATE:

对于相同收件人对之间的所有当前对话,线程ID必须相同。 (不要担心进一步的对话,用户可以选择在编写消息时打开新线程,这将生成新的线程ID,或者在现有线程中回复,这将标记具有现有线程ID的消息。我想要的只是在线程中每2个用户之间收集大量现有消息)。

我想,就像某种循环一样,它会搜索每个中间的所有收件人id并在升序排序后将它们合并到数组中:

  • 1月中旬:(100,101)
  • 2月中旬:(100,101)
  • 3月中旬:(100,102)

然后给出相同的数组,这将是我想要的线程ID:

  • (100,101)= 1
  • (100,101)= 1
  • (100,102)= 2

不确定,如果我的算法只能用SQL查询

2 个答案:

答案 0 :(得分:0)

这种更正应该从你的应用程序中更好地处理,因为它比那个功能样式的Sql更容易处理逻辑。

以下是完成此任务的一种方法(这假设所有相关(线程)对话都是一个接一个地进行,因为您已经确认):

SELECT   mid, 
         thread, 
         recipient 
FROM     (  
          SELECT row, 
                 mid, 
                 recipient,
                 IF(row % 2 = 0, @evenThread := thread, NULL) AS tempThread,
                 IF(row % 2 = 1, @evenThread, thread) AS thread
          FROM   (
                  SELECT   @row := @row + 1 as row, 
                           mid, 
                           IF(@row = 1, @thread := thread, NULL) AS tempThread,                
                           IF(@row % 2 = 1, IF(@row = 1, @rec1 := recipient, @rec1 := @rec3), NULL) AS tempOddRow,
                           IF(@row % 2 = 1, @rec3 := recipient, recipient) AS recipient,         
                           IF(@row % 2 = 0 AND @row > 2, IF((recipient != @rec1 OR @rec3 != @rec2) AND (recipient != @rec2 OR @rec3 != @rec1), @isDifferent := true, @isDifferent := false), NULL) AS isDifferent,
                           IF(@row % 2 = 0, @rec2 := recipient, NULL) AS tempEvenRow,
                           IF(@row % 2 = 0, IF(@isDifferent, @thread := @thread + 1, @thread), @thread) AS thread
                  FROM     (SELECT @row := 0) AS r, 
                           (SELECT @thread := 0) as t,
                           (SELECT @isDifferent := false) as d,
                           (SELECT @rec1 := 0) AS r1,
                           (SELECT @rec2 := 0) AS r2, 
                           (SELECT @rec3 := 0) AS r3, 
                           messages --your table name
                  ORDER BY row DESC
                 ) AS temp, 
                 (SELECT @evenThread := 0) AS t
         ) AS corrected 
ORDER BY row

这只是选择查询。在此测试http://sqlfiddle.com/#!9/61247/2。您可以将其复制到临时表中,并首先确认所有数据是否正确,而不是更新原始表,这将使调试更加困难。有点像:

CREATE TABLE messages_new LIKE messages; --new table name given
INSERT INTO  messages_new (mid, thread, recipient)
SELECT       mid, 
             thread, 
             recipient 
FROM         (  
              SELECT row, 
                     mid, 
                     recipient,
                     IF(row % 2 = 0, @evenThread := thread, NULL) AS tempThread,
                     IF(row % 2 = 1, @evenThread, thread) AS thread
              FROM   (
                      SELECT   @row := @row + 1 as row, 
                               mid, 
                               IF(@row = 1, @thread := thread, NULL) AS tempThread,                
                               IF(@row % 2 = 1, IF(@row = 1, @rec1 := recipient, @rec1 := @rec3), NULL) AS tempOddRow,
                               IF(@row % 2 = 1, @rec3 := recipient, recipient) AS recipient,         
                               IF(@row % 2 = 0 AND @row > 2, IF((recipient != @rec1 OR @rec3 != @rec2) AND (recipient != @rec2 OR @rec3 != @rec1), @isDifferent := true, @isDifferent := false), NULL) AS isDifferent,
                               IF(@row % 2 = 0, @rec2 := recipient, NULL) AS tempEvenRow,
                               IF(@row % 2 = 0, IF(@isDifferent, @thread := @thread + 1, @thread), @thread) AS thread
                      FROM     (SELECT @row := 0) AS r, 
                               (SELECT @thread := 0) as t,
                               (SELECT @isDifferent := false) as d,
                               (SELECT @rec1 := 0) AS r1,
                               (SELECT @rec2 := 0) AS r2, 
                               (SELECT @rec3 := 0) AS r3, 
                               messages
                      ORDER BY row DESC
                     ) AS temp, 
                     (SELECT @evenThread := 0) AS t
             ) AS corrected 
ORDER BY     row;
DROP TABLE   messages;
ALTER TABLE  messages_new RENAME TO messages; --back to old name

答案 1 :(得分:0)

我把它放在一个SQL小提琴中:http://sqlfiddle.com/#!2/83bdc/25

假设您的表名是messages,那么我就是这样做的:

Select messages.*, FirstThread 
From messages

Inner Join

(
-- Find a pair of dudes for each message and show the earliest thread of each
Select ThreadsForPairs.*, FirstThread From

(

Select mid
, Min(recipient) AS FirstDude
, Max(recipient) AS SecondDude
, thread

From messages

Group By mid, thread

) ThreadsForPairs

Left Join

(
-- Find the earliest thread for every pair of dudes
Select FirstDude, SecondDude, Min(thread) AS FirstThread

From

-- For every message, get the dudes involved
(
Select mid
, Min(recipient) AS FirstDude
, Max(recipient) AS SecondDude
, thread

From messages

Group By mid, thread
) PairsForMessages

Group By FirstDude, SecondDude

) FirstThreadForPairs

ON ThreadsForPairs.FirstDude = FirstThreadForPairs.FirstDude
AND ThreadsForPairs.SecondDude = FirstThreadForPairs.SecondDude

) FirstThreadForEveryMessage

On messages.mid = FirstThreadForEveryMessage.mid

正如您将看到的,我不完全匹配您的输出,因为消息ID 3将具有线程3而不是2,但我认为它是相同的想法......