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
表中似乎有一堆乱七八糟的列,名称如Complaint
和Voicemail
,每个列都对调用进行分类。
看起来这些列在相关时的值为 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 < '2017-09-02' + INTERVAL 1 DAY
提取所有记录,直到(但不包括)午夜,在您的日期范围之后。
如果您使用的是 Sqlite,则需要 AND DateTime < 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 语句的主要内容,如果未能解决你的问题,请参考以下文章