gpt4 book ai didi

mysql - 在 MySQL 中组合多个查询

转载 作者:行者123 更新时间:2023-11-29 03:04:49 25 4
gpt4 key购买 nike

这个问题有点啰嗦,对此我深表歉意。我的 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 显然是通知注册的日期。棘手的部分是 subject 是对另一个表的 ID 的引用,而该表在很大程度上取决于 action 列的值。

因此,例如,在示例数据的前两条记录中,subject 是对 users 表中 ID 的引用(即被关注的用户,然后取消关注)。在第三条记录中,subject 是对 items 表中 ID 的引用。

我们还需要执行多个JOIN 语句,具体取决于action 的条件。因此,例如,如果它是 added_item,我们需要 JOIN 其他几个表(以检查设置和其他要求)。

我在代码中遇到了一个遗留函数,它主要检查自指定日期以来表中存在给定用户的通知数量。之前的开发者只是简单的使用了一系列的查询,然后返回了几个SELECT COUNT(*)语句的总数如下(注意,这都是在PHP的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。虽然我可以使用表别名来做到这一点,但它往往会返回很多的冗余数据。

基本上,我想结合上面给出的 COUNT(*) 查询,这样我们就可以简单地返回给定用户 ID 和/的所有 notifications.*或时间段。

我还想尽可能避免使用 UNION(出于显而易见的原因)。

很抱歉这个冗长的问题,但我已尽力让所有内容都尽可能清楚。在有人询问之前,我无法更改数据结构或数据库模式,因为这是针对现有站点的。

我整理了一个 SQLFiddle让事情更清楚一点。

最佳答案

这些查询的复杂性和它们正在做的事情各不相同。

前 3 个可以组合成一个返回(最多)3 行的查询:-

SELECT action, COUNT(*) AS `count`
FROM `notifications`
WHERE `action` IN ( 'started_following', 'stopped_following', 'sent_message')
AND `subject` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'
GROUP BY action

要强制返回 3 行,您可以这样做:-

SELECT WantedActions.WantedAction, COUNT(*) AS `count`
FROM (SELECT 'started_following' AS WantedAction UNION SELECT 'stopped_following' UNION SELECT 'sent_message') AS WantedActions
LEFT OUTER JOIN `notifications`
ON WantedActions.WantedAction = notifications.action
WHERE `subject` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'
GROUP BY WantedActions.WantedAction

你或许可以为其他人做类似的事情

编辑

SELECT started_following, stopped_following, sent_message, favorited_item, comments, new_items, new_collections, new_categories, offers, purchases, item_sales
FROM (SELECT SUM(IF(`action` = 'started_following', 1, 0) AS started_following,
SUM(IF(`action` = 'stopped_following', 1, 0) AS stopped_following,
SUM(IF(`action` = 'sent_message', 1, 0) AS sent_message
FROM `notifications`
WHERE `subject` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}') Sub1
CROSS JOIN (SELECT SUM(IF(`action` = 'favorited_item', 1, 0) AS favorited_item,
SUM(IF(`action` = 'added_comment', 1, 0) AS comments,
SUM(IF(`action` = 'made_offer', 1, 0) AS offers
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
WHERE `categories`.`owner` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}') Sub2
CROSS JOIN (SELECT SUM(IF(`action` = 'added_item', 1, 0) AS new_items,
SUM(IF(`action` = 'added-collection', 1, 0) AS new_collections,
SUM(IF(`action` = 'added-category', 1, 0) AS new_categories
FROM `notifications`
INNER JOIN `categories` ON `notifications`.`subject` = `categories`.`id`
INNER JOIN (SELECT `followee` FROM `user_followers` WHERE `follower` = '{$this->id}') `followers`
WHERE `followee` = `user_id`
$sinceString
AND `user_id` != '{$this->id}') Sub3
CROSS JOIN (SELECT COUNT(*) AS purchases
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}') Sub4
CROSS JOIN (SELECT COUNT(*) AS item_sales
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}') Sub5

编辑 - 使用联合

SELECT action, COUNT(*)  AS action_count
FROM `notifications`
WHERE `subject` = '{$this->id}'
AND action IN ('started_following', 'stopped_following', 'sent_message')
$sinceString
AND `notifications`.`user_id` != '{$this->id}'
GROUP BY action
UNION
SELECT action, COUNT(*) AS action_count
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
WHERE `categories`.`owner` = '{$this->id}'
AND action IN ('favorited_item', 'added_comment', 'made_offer')
$sinceString
AND `notifications`.`user_id` != '{$this->id}'
GROUP BY action
UNION
SELECT action, COUNT(*) AS action_count
FROM `notifications`
INNER JOIN `categories` ON `notifications`.`subject` = `categories`.`id`
INNER JOIN (SELECT `followee` FROM `user_followers` WHERE `follower` = '{$this->id}') `followers`
WHERE `followee` = `user_id`
AND action IN ('added_item', 'added-collection', 'added-category')
$sinceString
AND `user_id` != '{$this->id}'
GROUP BY action
UNION
SELECT 'purchases' AS action, COUNT(*) AS action_count
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN `categories` ON `items`.`category` = `categories`.`id`
INNER JOIN (SELECT user_id, COUNT(*) AS `count`, `item_id`
FROM `user_favorite_items`
GROUP BY `user_id`, item_id
) `following` ON `items`.`id` = `following`.`item_id` AND `notifications`.`user_id` = `following`.`user_id`
WHERE `notifications`.`action` = 'bought_item'
AND `following`.`count` = 1
AND `categories`.`owner` = '{$this->id}'
$sinceString
AND `notifications`.`user_id` != '{$this->id}'
UNION
SELECT 'item_sales' AS action, COUNT(*) AS action_count
FROM `notifications`
INNER JOIN `items` ON `notifications`.`subject` = `items`.`id`
INNER JOIN (SELECT user_id, COUNT(*) AS `count`, `item_id`
FROM `user_favorite_items`
GROUP BY `user_id`, item_id
) `following` ON `items`.`id` = `following`.`item_id` AND `notifications`.`user_id` = `following`.`user_id`
WHERE `notifications`.`action` = 'selling_item'
AND `following`.`count` = 1
$sinceString
AND `notifications`.`user_id` != '{$this->id}'

关于mysql - 在 MySQL 中组合多个查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17409400/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com