これは少し長ったらしい質問で、申し訳ありません。私の SQL スキルは著しく不足しています (できるだけ早く修正したいものです)。その結果、私が遭遇したこの問題にどのように取り組むことができるか、私は本当に理解できません.
基本的に、私たちのプロジェクトはユーザー通知を単一のテーブルに保存していますnotifications
。テーブル構造は次のようになります。
+-----------+-----------+----------------+------------+
| user_id | subject | action | date |
+-----------+-----------+----------------+------------+
| 1 | 2 | started_follow | 1371034287 |
| 1 | 2 | stopped_follow | 1371034287 |
| 2 | 5 | added_item | 1371034287 |
+-----------+-----------+----------------+------------+
user_id
アクションを実行したユーザーの ID が常に含まれており、date
明らかに通知が登録された日付です。注意が必要なのは、別のテーブルの ID への参照であり、そのテーブルは列subject
の値に大きく依存していることです。action
たとえば、サンプル データの最初の 2 つのレコードではsubject
、テーブル内の ID users
(つまり、フォローされてからフォロー解除されたユーザー) への参照があります。3 番目のレコードは、テーブルsubject
内の ID への参照です。items
JOIN
の条件に応じて、いくつかのステートメントも実行する必要がありaction
ます。したがって、added_item
たとえば、JOIN
他のいくつかのテーブルが必要です (設定やその他の要件を確認するため)。
指定された日付以降、特定のユーザーのテーブルに通知がいくつ存在するかを本質的にチェックするコード内のレガシー関数に出くわしました。以前の開発者は一連のクエリを単純に使用し、次のようにいくつかのステートメントの合計数を返しました(これはすべて PHPクラスSELECT COUNT(*)
内にあることに注意してください)。User
// Get the number of notifications since the specified time (or of all time):
public function countNotifications($since = '')
{
$sinceString = ($since == '') ? '' : "AND `date` > '$since'";
// Notifications when someone follows $this:
$started_following = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
WHERE `action` = 'started_following'
AND `subject` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when someone stops following $this:
$stopped_following = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
WHERE `action` = 'stopped_following'
AND `subject` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when someone sends $this a message:
$sent_message = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
WHERE `action` = 'sent_message'
AND `subject` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when someone favorites $this' items:
$favorited_item = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
WHERE `notifications`.`action` = 'favorited_item'
AND `categories`.`owner` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when someone adds a comment to $this' items:
$comments = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
WHERE `notifications`.`action` = 'added_comment'
AND `categories`.`owner` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when a follower of $this adds a new item:
$new_items = $this->_database->query("SELECT COUNT(*) AS `total`
FROM `notifications`
INNER JOIN `categories` ON `notifications`.`subject` = `categories`.`id`
INNER JOIN (SELECT `followee` FROM `user_followers` WHERE `follower` = '{$this->id}') `followers`
WHERE `notifications`.`action` = 'added_item'
AND `followee` = `user_id`
$sinceString
AND `user_id` != '{$this->id}'")->fetchObject();
// Notifications when a follower of $this adds a new collection:
$new_collections = $this->_database->query("SELECT COUNT(*) AS `total`
FROM `notifications`
INNER JOIN `categories` ON `notifications`.`subject` = `categories`.`id`
INNER JOIN (SELECT `followee` FROM `user_followers` WHERE `follower` = '{$this->id}') `followers`
WHERE `notifications`.`action` = 'added-collection'
AND `followee` = `user_id`
$sinceString
AND `user_id` != '{$this->id}'")->fetchObject();
// Notifications when a follower of $this adds a new category:
$new_categories = $this->_database->query("SELECT COUNT(*) AS `total`
FROM `notifications`
INNER JOIN `categories` ON `notifications`.`subject` = `categories`.`id`
INNER JOIN (SELECT `followee` FROM `user_followers` WHERE `follower` = '{$this->id}') `followers`
WHERE `notifications`.`action` = 'added-category'
AND `followee` = `user_id`
$sinceString
AND `user_id` != '{$this->id}'")->fetchObject();
// Selling Notifications:
// Notifications when someone makes an offer for an item $this is selling:
$offers = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
WHERE `notifications`.`action` = 'made_offer'
AND `categories`.`owner` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when someone purchases an item $this is selling:
$purchases = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
INNER JOIN (SELECT COUNT(*) AS `count`, `item_id`
FROM `user_favorite_items`
WHERE `user_id` = '{$this->id}') `following` ON `items`.`id` = `following`.`item_id`
WHERE `notifications`.`action` = 'bought_item'
AND `following`.`count` = 1
AND `categories`.`owner` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Notifications when an item that $this favorited is listed for sale:
$item_sales = $this->_database->query("SELECT COUNT(*) AS `count`
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN (SELECT COUNT(*) AS `count`, `item_id`
FROM `user_favorite_items`
WHERE `user_id` = '{$this->id}'
) `following` ON `items`.`id` = `following`.`item_id`
WHERE `notifications`.`action` = 'selling_item'
AND `following`.`count` = 1
$sinceString
AND `notifications`.`user_id` != '{$this->id}'")->fetchObject();
// Return the counts:
return ($started_following->count +
$stopped_following->count +
$sent_message->count +
$favorited_item->count +
$comments->count +
$new_items->count +
$new_collections->count +
$new_categories->count +
$offers->count +
$purchases->count +
$item_sales->count);
}
これは問題なく機能しますが、特定の日付からすべてのレコードをフェッチすること、または特定のユーザー ID に関連するすべてのレコードをフェッチすることは非常に困難です。
私の質問は、提供された多数のSQLステートメントを組み合わせる最良の方法は何ですか? を試してみましLEFT JOIN
たが、ご覧のとおり、 の値に応じて、テーブルを別の列に結合する必要がありますnotifications
。action
. テーブル エイリアスを使用してこれを行うことはできますが、多くの冗長なデータが返される傾向があります。
基本的に、上記のクエリを組み合わせて、特定のユーザー ID や期間のCOUNT(*)
すべてを簡単に返すことができるようにしたいと考えています。notifications.*
また、可能な限り使用を避けたいと思いUNION
ます(明らかな理由により)。
長い質問で申し訳ありませんが、すべてをできるだけ明確にしようとしました。これは既存のサイト用であるため、だれかが尋ねる前に、データの構造または DB スキーマを変更することはできません。
もう少し明確にするために、 SQLFiddleをまとめました。