2

私は MySQL があまり得意ではないので、タイプとフィールドに基づいて、ユーザーによって送信されたメッセージをカウントするクエリを作成します。is_auto

メッセージのタイプは、「小さなテキスト メッセージ」または「ニュースレター」です。いくつかのフィールドが異なる 2 つのエンティティを作成しました。重要なのは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私はクエリで終わりました。唯一の違いはに対して常に 1 である必要があるため、このクエリを短縮または最適化できますか?messages_countnewsletter

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 操作があり、これら 2 つのクエリが同一の行を生成する方法はありません。)

それ以外の場合、クエリは書かれているとおりに問題ないように見えます。

(質問を検討することは常に良いことです。より良い方法があるのではないでしょうか? 求めている結果セットを取得するには、持っているスキーマから、クエリは取得するのと同じくらい良いように見えます。)

于 2012-07-06T14:02:54.710 に答える
2

より一般的なDBのアドバイスを探している場合は、テーブルを再構築して、共通の要素を1つのテーブルに分解することをお勧めoutbound_communicationします.そのタイプに固有のフィールド。必要なすべてのフィールドを選択するには、単純な JOIN が必要であることを意味しますが、正規化されているため、このような状況が実際に簡単になります (1 つのテーブルに対象のエンティティがすべて保持されます)。さらに、その JOIN を「ビュー」として 1 回だけ記述するオプションがあり、既存のコードを変更する必要さえなく、2 つのテーブルが変更されていないかのように表示されます。

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 クエリが唯一の現実的な定式化です。たとえば、2 つのテーブル間に関連性の結合はありません。

ですから、あなたの質問は非常に正しいと思います。

なぜUNIONを心配しているのですか?

于 2012-07-06T14:02:06.853 に答える