2

我不太擅长 MySQL,我将编写一个查询来计算用户发送的消息,基于它的类型和is_auto字段。

消息可以是“小文本消息”或“时事通讯”类型。我创建了两个实体,它们之间有一些不同的字段。重要的是messages_count它在表中不存在,newsletter并且在查询中使用

CREATE TABLE IF NOT EXISTS `small_text_message` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `messages_count` int(11) NOT NULL,
  `username` varchar(255) NOT NULL,
  `method` varchar(255) NOT NULL,
  `content` longtext,
  `sent_at` datetime DEFAULT NULL,
  `status` varchar(255) NOT NULL,
  `recipients_count` int(11) NOT NULL,
  `customers_count` int(11) NOT NULL,
  `sheduled_at` datetime DEFAULT NULL,
  `sheduled_for` datetime DEFAULT NULL,
  `is_auto` tinyint(1) NOT NULL,
  `user_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

和:

CREATE TABLE `newsletter` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `subject` varchar(78) DEFAULT NULL,
  `content` longtext,
  `sent_at` datetime DEFAULT NULL,
  `status` varchar(255) NOT NULL,
  `recipients_count` int(11) NOT NULL,
  `customers_count` int(11) NOT NULL,
  `sheduled_at` datetime DEFAULT NULL,
  `sheduled_for` datetime DEFAULT NULL,
  `is_auto` tinyint(1) NOT NULL,
  `user_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

我结束了一个UNION查询。可以缩短或优化此查询,因为唯一的区别是messages_count应该始终为 1newsletter吗?

SELECT
CONCAT('sms_', IF(is_auto = 0, 'user' , 'auto')) AS subtype,
SUM(messages_count * (customers_count + recipients_count)) AS count
FROM small_text_message WHERE status <> 'pending' AND user_id = 1
GROUP BY is_auto
UNION
SELECT
CONCAT('newsletter_', IF(is_auto = 0, 'user' , 'auto')) AS subtype,
SUM(customers_count + recipients_count) AS count
FROM newsletter WHERE status <> 'pending' AND user_id = 1
GROUP BY is_auto
4

3 回答 3

5

我没有看到任何简单的方法来避免 UNION(或 UNION ALL)操作,这将返回指定的结果集。

我建议您使用UNION ALL运算符代替UNION运算符。那么执行计划将不包括消除重复行的步骤。(您已经对每个查询进行了 GROUP BY 操作,这两个查询不可能产生相同的行。)

否则,您的查询看起来就像写的一样。

(考虑这个问题总是一件好事,可能有更好的方法吗?为了得到你所要求的结果集,从你拥有的模式中,你的查询看起来和它会得到的一样好。)

于 2012-07-06T14:02:54.710 回答
2

如果您正在寻找更一般的数据库建议,我建议重组表以将常见元素分解为一个表,可能称为outbound_communication或其他表,其中包含所有常见字段,然后可能有特定类型的“子表”来托管该类型独有的字段。这确实意味着需要一个简单的 JOIN 来选择您想要的所有字段,但同样,它已标准化并且实际上使这种情况更容易(一个表包含所有感兴趣的实体)。此外,您可以选择只将 JOIN 作为“视图”编写一次,然后您现有的代码甚至不需要更改即可查看这两个表,就好像它们从未更改过一样。

CREATE TABLE IF NOT EXISTS `outbound_communicaton` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `content` longtext,
  `sent_at` datetime DEFAULT NULL,
  `status` varchar(255) NOT NULL,
  `recipients_count` int(11) NOT NULL,
  `customers_count` int(11) NOT NULL,
  `sheduled_at` datetime DEFAULT NULL,
  `sheduled_for` datetime DEFAULT NULL,
  `is_auto` tinyint(1) NOT NULL,
  `user_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

CREATE TABLE `small_text_message` (
  `oubound_communication_id` int(11) NOT NULL,
  `messages_count` int(11) NOT NULL,
  `username` varchar(255) NOT NULL,
  `method` varchar(255) NOT NULL,
  PRIMARY KEY (`outbound_communication_id`),
  FOREIGN KEY (outbound_communication_id) 
    REFERENCES outbound_communicaton(id)
) ENGINE=InnoDB;

CREATE TABLE `newsletter` (
  `oubound_communication_id` int(11) NOT NULL,
  `subject` varchar(78) DEFAULT NULL,
  PRIMARY KEY (`outbound_communication_id`),
  FOREIGN KEY (outbound_communication_id) 
    REFERENCES outbound_communicaton(id)
) ENGINE=InnoDB;

然后选择一个文本消息是这样的:

SELECT * 
FROM outbound_communication AS parent
  JOIN small_text_message 
    ON parent.id = small_text_message.outbound_communication_id
WHERE parent.id = 1234;
于 2012-07-06T14:06:24.493 回答
1

查询的性质本质上是来自小文本消息和时事通讯表的数据的联合,因此 UNION 查询是唯一现实的公式。例如,这两个表之间没有关联。

所以,我认为你的查询非常正确。

你为什么担心UNION?

于 2012-07-06T14:02:06.853 回答