3

私はSQLに非常に慣れていません。問題の解決を手伝ってください。

エンジン間の移行 (phpbb から drupal へ) 後に取得した、サイトのプライベート メッセージのテーブルがあります。

たとえば、3 つの列があるとします。

  • mid - メッセージ ID 用
  • thread - スレッド ID
  • 受信者- メッセージを受け取るユーザー ID。

すべてのメッセージは受信者と作成者のメールボックスに表示されるため、メッセージごとに 2 つの文字列があります。

問題は、メッセージのスレッドID が正しくないことです (基本的に、それらはmidに等しい)。そのため、2 人のユーザー間の通信は、100 の個別のスレッドとして表示されます。

例えば:

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       |
|________|___________|___________|

アップデート:

スレッド ID は、同じ受信者のペア間で現在行われているすべての会話で同じでなければなりません。(それ以上の会話について心配する必要はありません。ユーザーは、メッセージを書き込むときに新しいスレッドを開くオプションがあり、新しいスレッド ID を生成するか、既存のスレッドで返信し、既存のスレッド ID でメッセージをマークします。私が望むのは、収集することだけですスレッド内の各 2 ユーザー間の既存メッセージのトン)。

ある種のサイクルのように、すべての受信者 ID を mid ごとに検索し、昇順で並べ替えた後にそれらを配列にマージすることを想像します。

  • 中間 1 の場合: (100, 101)
  • ミッド 2 の場合: (100, 101)
  • ミッド 3 の場合: (100, 102)

次に、同じ配列に、目的のスレッド ID となる同じ ID を指定します。

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

私のアルゴリズムがSQLクエリのみで可能かどうかはわかりません

4

2 に答える 2

0

この種の修正は、この関数型の Sql よりもアプリケーションでロジックを処理する方が簡単であるため、アプリケーションからより適切に処理する必要があります。

これを行う 1 つの方法を次に示します (これは、関連するすべての (スレッド化された) 会話が次々に行われることを前提としています。確認済みです):

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
于 2013-03-23T20:23:22.830 に答える
0

これを SQL Fiddle に入れました: 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 には 2 ではなくスレッド 3 があるため、出力と正確には一致しませんが、同じ考えだと思います...

于 2013-03-23T22:52:09.730 に答える