4

データベースに次のテーブルがあります。

メッセージ表

sentByおよびテーブルsentToへの FKです。User

このテーブルには、ユーザー間のメッセージがあります。

sentBy |  sentTo  |     dateSent     |     body
-------+----------+------------------+-----------------
  1    |    2     | 11/21/2010 10:00 | Hey!
-------+----------+------------------+-----------------
  2    |    1     | 11/21/2010 10:50 | Hi!
-------+----------+------------------+-----------------
  1    |    2     | 11/21/2010 10:51 | msg body 1
-------+----------+------------------+-----------------
  2    |    1     | 11/21/2010 11:05 | msg body 2
-------+----------+------------------+-----------------
  1    |    3     | 11/21/2010 11:51 | msg body 3
-------+----------+------------------+-----------------
  3    |    1     | 11/21/2010 12:05 | msg body 4
-------+----------+------------------+-----------------
  1    |    3     | 11/21/2010 12:16 | msg body 5
-------+----------+------------------+-----------------
  4    |    1     | 11/21/2010 12:25 | msg body 6
-------+----------+------------------+-----------------

user 1 が会話したユーザーと、 user 1 と会話したユーザーを知る必要があります。この場合、ユーザー 2、3、および 4 (ユーザー 4 はユーザー 1 にメッセージを送信しましたが、ユーザー 1 はまだメッセージを送信していないことに注意してください)。

2 番目の質問は、各ユーザーとの最後のメッセージを取得するにはどうすればよいかということです。ユーザーに送信された最新のメッセージを取得するよう求めています。

たとえば、ユーザー 1 について尋ねている場合、ユーザー 2 の最新のメッセージはメッセージ本文 2 です。ユーザー 3 の最新のメッセージはメッセージ本文 5 です。

1 つの SQL SELECT ステートメントでその情報を取得するにはどうすればよいですか? または、2つの選択が必要になるかもしれません。

私はWhatsAppのようなことをしようとしています。会話したユーザーのリスト (私の最初の質問) と、彼らとの最後のメッセージ (私の 2 番目の質問) を含むチャット画面があります。

という名前の別のテーブルを作成して、そのテーブルConversationに移動sentBysentTo、日付が送信された最後のメッセージを送信することもできますが、これは良い設計ではないと思います。

私の2つの質問の結果は次のとおりです。

sentBy |  sentTo  |     dateSent     |     body
-------+----------+------------------+-----------------
  2    |    1     | 11/21/2010 11:05 | msg body 2
-------+----------+------------------+-----------------
  1    |    3     | 11/21/2010 12:16 | msg body 5
-------+----------+------------------+-----------------
  4    |    1     | 11/21/2010 12:25 | msg body 6
-------+----------+------------------+-----------------
4

2 に答える 2

4

次のクエリは、ユーザー 1 の予想される結果を示します。

select m.* from messages m
join (
  select auser,withuser,max(datesent) datesent from (
    select sentby as auser,sentto as withuser,datesent from messages 
    union
    select sentto as auser,sentby as withuser,datesent from messages 
    ) as ud
  group by auser,withuser
  ) maxud 
  on (m.datesent=maxud.datesent and maxud.auser in (m.sentBy,m.sentTo))
where auser=1

言うまでもなく、where句の条件を変更して、任意のユーザーに対して同様の結果を得ることができます。

ただし、私のアプローチは、次のようにビューを作成し、後でそこから選択することです。

create view conversation_stuff as
select m.sentBy,m.sentTo,m.dateSent,m.body,maxud.auser,maxud.withuser
from messages m
join (
  select auser,withuser,max(datesent) datesent from (
    select sentby as auser,sentto as withuser,datesent from messages 
    union
    select sentto as auser,sentby as withuser,datesent from messages 
    ) as ud
  group by auser,withuser
  ) maxud 
  on (m.datesent=maxud.datesent and maxud.auser in (m.sentBy,m.sentTo))

select sentBy,sentTo,dateSent,body from conversation_stuff where auser=1;

これは、他の用途にも役立つ可能性があると思います。

編集: sqlserverが文句言うのをやめてsを避けるために、どこにでも変更userされました...auser[]

于 2013-10-29T08:04:39.757 に答える
0

sentBy でフィルタリングされ、sentTo でグループ化された最大の dateSent を選択し、この結果を元のテーブルに結合します。

編集:問題が発生しました。ユーザーが送受信したメッセージの最大メッセージが必要ですか?

SELECT
    Messages.*
FROM
    Messages
    INNER JOIN
    (
        SELECT
            CombinedKey,
            MAX(dateSent) AS dateSent
        FROM
        (
            SELECT
                CombinedKey = CASE WHEN sentBy > sentTo
                    THEN CAST(sentBy AS nvarchar(10)) + '_' 
                        + CAST(sentTo AS nvarchar(10))
                    ELSE CAST(sentTo AS nvarchar(10)) + '_'
                        + CAST(sentBy AS nvarchar(10))
                    END,
                MAX(dateSent) AS dateSent
            FROM
                Messages
            WHERE
                sentBy = @user
                OR sentTo = @user
            GROUP BY
                sentBy,
                sentTo
        ) AS MaxMessagesBoth
        GROUP BY
            CombinedKey
    ) AS MaxMessages    
        ON MaxMessages.CombinedKey = CASE WHEN sentBy > sentTo
            THEN CAST(sentBy AS nvarchar(10)) + '_'
                + CAST(sentTo AS nvarchar(10))
            ELSE CAST(sentTo AS nvarchar(10)) + '_'
                + CAST(sentBy AS nvarchar(10))
            END
        AND MaxMessages.dateSent = Messages.dateSent
于 2013-10-29T07:16:48.070 に答える