SQL 组合多个 SELECT 语句

Posted

技术标签:

【中文标题】SQL 组合多个 SELECT 语句【英文标题】:SQL Combining Multiple SELECT Statements 【发布时间】:2018-02-16 13:21:20 【问题描述】:

我正在尝试构建一个 SQLite 查询,该查询将从单个表中收集统计信息。

该表包含一个日志,每天有几个条目。我需要在搜索参数中为每一天获取一个单独的行,然后使用某些布尔值编译这些日期内的行总数。

这是我目前的查询:

SELECT DATE(DateTime) AS SearchDate,
     (SELECT COUNT() AS Total
                FROM CallRecords
                WHERE DATE(DateTime)
                BETWEEN '2017-08-27' AND '2017-09-02'
                GROUP BY DATE(DateTime)
                ORDER BY Total DESC) AS Total,
    (SELECT COUNT() AS Total
                FROM CallRecords
                WHERE NoMarket = 1
                AND DATE(DateTime)
                BETWEEN '2017-08-27' AND '2017-09-02'
                GROUP BY DATE(DateTime)
                ORDER BY Total DESC) AS NoMarkets,
    (SELECT COUNT() AS Total
                FROM CallRecords
                WHERE Complaint = 1
                AND DATE(DateTime)
                BETWEEN '2017-08-27' AND '2017-09-02'
                GROUP BY DATE(DateTime)
                ORDER BY Total DESC) AS Complaints,
    (SELECT COUNT() AS Total
                FROM CallRecords
                WHERE Voicemail = 1
                AND DATE(DateTime)
                BETWEEN '2017-08-27' AND '2017-09-02'
                GROUP BY DATE(DateTime)
                ORDER BY Total DESC) AS Voicemails
FROM CallRecords
WHERE DATE(DateTime) BETWEEN '2017-08-27' AND '2017-09-02'
GROUP BY SearchDate

还有输出:

8/28/2017   175 27      11
8/29/2017   175 27      11
8/30/2017   175 27      11
8/31/2017   175 27      11
9/1/2017    175 27      11

如您所见,它正确获取了每个单独的日期,但列的总数不正确。

显然,我在查询中遗漏了一些内容,但我不确定在哪里。有没有更好的方法来执行这个查询?

编辑:我在这里查看了其他几个标题几乎相同的问题,但我没有找到与我正在寻找的类似的东西。大多数似乎比我想要完成的要复杂得多。

【问题讨论】:

请提供minimal reproducible example。 meta.***.com/questions/333952/… @Yunnosch 在不提供实际数据库的情况下如何做到这一点? 通过提供来自 SQLite 命令行工具的.dump 用于适当定制的玩具数据库。 【参考方案1】:

您的CallRecords 表中似乎有一堆乱七八糟的列,名称如ComplaintVoicemail,每个列都对调用进行分类。

看起来这些列在相关时的值为 1。

所以这个查询应该会对你有所帮助。

SELECT DATE(DateTime) AS SearchDate,
       COUNT(*) AS Total,
       SUM(NoMarket = 1) AS NoMarkets,
       SUM(Complaint = 1) AS Complaints,
       SUM(Voicemail = 1) AS Voicemails
  FROM CallRecords
 WHERE DateTime >=  '2017-08-27'
   AND DateTime <   '2017-09-02' + INTERVAL 1 DAY
 GROUP BY DATE(DateTime)

为什么会这样?因为在 mysql 中,像 Voicemail = 1 这样的布尔表达式在其为真时具有值 1,而在其为假时具有 0。您可以很好地总结这些值。

为什么它比你拥有的更快?因为DATE(DateTime) BETWEEN this AND that 不能利用DateTime 上的索引。

为什么您的日期范围结束时正确?因为DateTime &lt; '2017-09-02' + INTERVAL 1 DAY 提取所有记录,直到(但不包括)午夜,在您的日期范围之后

如果您使用的是 Sqlite,则需要 AND DateTime &lt; date('2017-09-02', '+1 day')+ INTERVAL 1 DAY 的内容略有不同。

【讨论】:

BETWEEN 不是日期范围过滤运算符的最佳选择,因为它可以在日期范围结束时减一。 太棒了。我不知道为什么我试图让它变得如此复杂。但是,我使用的是 SQLite,而不是 MySQL,所以我不能使用 INTERVAL 部分。我将从调用应用程序调整查询中的日期。谢谢!【参考方案2】:
SELECT DATE(DateTime) AS SearchDate, Total, NoMarkets, Complaints, Voicemails FROM
 (SELECT COUNT() AS Total FROM CallRecords) CR
 JOIN
(SELECT COUNT() AS NoMarkets FROM CallRecords WHERE NoMarket = 1) NM
 ON CR.DateTime = NM.DateTime
 JOIN
(SELECT COUNT() AS Complaints FROM CallRecords WHERE Complaint = 1) C
 ON NM.DateTime = C.DateTime
 JOIN
(SELECT COUNT() AS Voicemails FROM CallRecords WHERE Voicemail = 1) VM
 ON C.DateTime = VM.DateTime
 JOIN CallRecords CLR ON VM.DateTime=CLR.DateTime WHERE DATE(CLR.DateTime) >= '2017-08-27' AND DATE(CLR.DateTime) <= '2017-09-02'GROUP BY SearchDate;

这可能会正确输出。

【讨论】:

名为NM 的虚拟表没有DateTime 列。其他人也是如此。所以 JOIN 不起作用。 比数据库表中的记录如何按日期存储?【参考方案3】:

你可以这样做,虽然我是用 SQL server 写的

SELECT DATE(DateTime) AS SearchDate,
    COUNT() AS TOTAL,
    SUM(CASE WHEN NoMarket = 1 THEN 1 ELSE 0 END) AS NoMarkets,
    SUM(CASE WHEN Complaint = 1 THEN 1 ELSE 0 END) AS Complaints,
    SUM(CASE WHEN Voicemail = 1 THEN 1 ELSE 0 END) AS Voicemails
FROM CallRecords
WHERE DATE(DateTime) BETWEEN '2017-08-27' AND '2017-09-02'
GROUP BY SearchDate

【讨论】:

以上是关于SQL 组合多个 SELECT 语句的主要内容,如果未能解决你的问题,请参考以下文章

SQL学习之组合查询(UNION)

如何让多个不同的SQL语句一起执行?

在存储过程中组合多个语句

第十七章 组合查询

mysql的查询语句union是啥意思

SQL笔记SQL语法SELECT语句DISTINCT语句LIMITLIMIT和OFFSET组合使用WHERE 子句