2016-05-01 10 views
1

私は、主に学習目的のために、* ampシステムを使って内部Webベースのメッセージシステムを作ろうとしています。私はこれが些細な話題なのかどうかはわかりませんが、私は困難を抱えていますので、私に同行してください。多対多テーブルからmysqliをソート

目的は、最後に送受信されたメッセージによって注文された連絡先をすべて一覧表示することです。 SQLは、この

$query = "SELECT username, user.id as user_id, 

(SELECT COUNT(message_read) 
FROM message_user 
WHERE message_read = 0 
AND sent_id = user_id 
AND receive_id = {$userId}) as unread 

FROM user 
WHERE user.id IN 
(SELECT contact_id FROM allowed_contact WHERE user_id = {$userId}) 
;"; 

テーブルの構造のように見える、それをソートせずに現在 は以下のとおりです。
userテーブルはsent_idreceive_id
を持ってmessage_userテーブルにリンクid
を持っています message_usermessage.idに対応するmessage_idを持ち、
messageテーブルはtimestampです。

私はこれをSQLで行いたいと思っていますが、PHPになった場合、私はそれに頼って辞任します。 (未テスト)DISTINCT

+0

**警告**:mysqliを使用する場合は、パラメータ化されたクエリと['bind_param'](http://php.net/manual/en/mysqli-stmt.bind-param.php)を使用する必要がありますユーザーデータをクエリに追加します。 **重大な[SQLインジェクションのバグ](http://bobby-tables.com/)を作成したため、文字列の補間または連結を使用してこれを実行しないでください。 ** '$ _POST'や' $ _GET'データを直接クエリに入れないでください。誰かがあなたのミスを悪用しようとすると、非常に危険です。 – tadman

+0

'$ userId'は、mysqlがデータベースから作成した、自動生成されたIDです。この値はユーザーが指定しません。 – yak27

+0

あなたはそれを言っていますが、あなたのコードのどこかでお金を賭けることは '$ userId = $ _ GET ['userId']'です。チャンスを取らないでください。 – tadman

答えて

0

使用2 LEFT JOIN

SELECT DISTINCT `u`.`id` 
FROM `user` AS `u` 
LEFT JOIN `message_user` AS `mu` ON `u`.`id` = `mu`.`sent_id` OR `u`.`id` = `mu`.`receive_id` 
LEFT JOIN `message` AS `m` ON `m`.`id` = `mu`.`message_id` 
ORDER BY `m`.`timestamp` DESC; 
+0

'timestamp'を' SELECT DISTINCT'に追加すると、正しく順序付けされません。順序は同じですが重複しています。 – yak27

1

これは動作します。

SELECT `u`.`id` AS user_id, username, 
(SELECT COUNT(message_user.message_read) 
FROM message_user 
WHERE message_user.message_read = 0 
AND sent_id = user_id 
AND receive_id = {$userId}) as unread 

FROM `user` AS `u` 
LEFT JOIN `message_user` AS `mu` 
ON 
    (CASE WHEN `u`.`id` != {$userId} 
     THEN `u`.`id` = `mu`.`sent_id` 
     WHEN `mu`.`sent_id` = {$userId} AND `mu`.`receive_id` = {$userId} 
     THEN `u`.`id` = `mu`.`sent_id` 
    END) 
OR 
    (CASE WHEN `u`.`id` != {$userId} 
     THEN `u`.`id` = `mu`.`receive_id` 
    END) 

LEFT JOIN `message` AS `m` ON `m`.`id` = `mu`.`message_id` 

WHERE u.id IN 
(SELECT contact_id FROM allowed_contact WHERE user_id = {$userId}) 
GROUP BY u.id 
ORDER BY MAX(`m`.`timestamp`) DESC; 

This問題が発生しました。

@アンドレアス時間と助けてくれてありがとう。

+0

これはあまりにも複雑に思えますが、それはあなたが採用した珍しいスキーマによって必要とされています。この種のクエリを簡単にするためにテーブルを調整できると思います。このような規模でテストすることを忘れないでください。必要に応じて数万から数百万のダミーメッセージを読み込んで、適切に索引を付けるようにしてください。 – tadman

+0

スキーマを見てみるようになったので、 'message_user'にタイムスタンプをつけることができました。それはまだまだ複雑ですが、2番目のLEFT JOINを削除することでパフォーマンスが向上します。メッセージが2回送信された場合は、作成された時間ではなく受信した時間までに表示する必要があると言って、それを正当化することができます。私は細部にも関わって、全体像を見て忘れてしまいました、ありがとう。 – yak27

関連する問題