如何编写涉及多个选择的 Oracle SQL 查询
Posted
技术标签:
【中文标题】如何编写涉及多个选择的 Oracle SQL 查询【英文标题】:How to write an oracle SQL query that involves multiple selects 【发布时间】:2019-09-22 20:17:47 【问题描述】:我有这个查询,它提供了商品名称、平均价格和特定年份的计数,如下所示。
name Avg_price_2019 count
---------------------------------
X 23.9 234
Y 21.8 59
SQL:
SELECT
AVG(Amount) Avg_price_2019, name
FROM
(SELECT
name, SUM(price_amount) Amount, COUNT(*)
FROM
myTable
WHERE
(To_date("Activity Date", 'mm-dd-yyyy') >= TO_DATE('09/01/2019', 'mm/dd/yyyy'))
AND (To_date("Activity Date", 'mm-dd-yyyy') <= TO_DATE('09/17/2019','mm/dd/yyyy'))
GROUP BY
name)
GROUP BY
name;
我希望它返回更多年,如下所示
name | Avg price 2018 | count | Avg price 2019 | count
对于 2018 年的结果,我需要相同的查询,只是更改年份。
如何在同一个查询中组合这两个选择以产生上述结果?
【问题讨论】:
到底为什么要将日期值存储在 VARCHAR 列中?这是一个非常糟糕的主意。 您显示的查询不计算平均值。子查询(派生表)为每个名称提供一行,其中包含总量和计数。主要查询再次按名称分组,所以AVG(Amount)
只是Amount
,因为一个值(一行)的平均值当然是值本身。话虽如此,您的主要查询毫无意义。
附注:您可以使用日期文字,例如DATE '2019-09-01'
,因此您不必使用TO_DATE
转换字符串。
【参考方案1】:
您似乎想要条件聚合。您的查询很可能简化如下:
SELECT
name
AVG(CASE WHEN EXTRACT(YEAR FROM Activity_Date) = 2019 THEN Amount END) avg_price_2019,
SUM(CASE WHEN EXTRACT(YEAR FROM Activity_Date) = 2019 THEN 1 ELSE 0 END) count_2019,
AVG(CASE WHEN EXTRACT(YEAR FROM Activity_Date) = 2018 THEN Amount END) avg_price_2018,
SUM(CASE WHEN EXTRACT(YEAR FROM Activity_Date) = 2018 THEN 1 ELSE 0 END) count_2018
FROM myTable
GROUP BY name
您似乎将日期存储为字符串,格式为mm-dd-yyyy
。您可以使用SUBSTR()
提取年份部分,例如:
SELECT
name
AVG(CASE WHEN SUBSTR(Activity_Date, -4) = '2019' THEN Amount END) avg_price_2019,
SUM(CASE WHEN SUBSTR(Activity_Date, -4) = '2019' THEN 1 ELSE 0 END) count_2019,
AVG(CASE WHEN SUBSTR(Activity_Date, -4) = '2018' THEN Amount END) avg_price_2018,
SUM(CASE WHEN SUBSTR(Activity_Date, -4) = '2018' THEN 1 ELSE 0 END) count_2018
FROM myTable
GROUP BY name
最后,如果要过滤一年中的特定时间段(9 月 1 日至 9 月 17 日),则可以在查询中添加 WHERE
子句。仍然假设日期存储为字符串,这可能是:
WHERE SUBSTR(Activity_Date, 1, 5) BETWEEN '09-01' AND '09-17'
【讨论】:
您错过了使用 Oracle 透视语法的机会。 ***.com/a/23939719/119477【参考方案2】:在这种情况下,我会使用“假地图列”
select a.NAME, a.AVG. a.CNT, b.AVG, b.CNT from
(
select '1' as MAP, NAME, AVG, CNT from ... your query [2018 table] ...
) a
left join
(
select '1' as MAP, NAME, AVG, CNT from ... your query [2019 table] ...
) b
on a.MAP = b.MAP
我没有测试代码,但我想说的是,您可以在每个表中创建一个虚拟列,然后将它们留在该列上以将它们并排放置。
为了获得更好的性能,我建议在过滤日期时间时使用“BETWEEN” 例如:DATE BETWEEN date1 和 date2
【讨论】:
【参考方案3】:这是where子句:
Create Table myTable
(
myTableID int,
amount int,
price_amount int,
to_date DateTime,
activity_date DateTime
)
Insert Into myTable (myTableID, amount, price_amount, activity_date) values (1, 1, 2, '1/1/2019')
Insert Into myTable (myTableID, amount, price_amount, activity_date) values (1, 1, 4, '1/1/2018')
select * from myTable
Select AVG(amount) as Avg_price_2019,
(SELECT SUM(price_amount) FROM myTable) as test from myTable
where activity_date >= Convert(DateTime, '09/01/2019')
and activity_date <= Convert(DateTime, '09/17/2019')
【讨论】:
您似乎发布了对错误请求的回答。以上是关于如何编写涉及多个选择的 Oracle SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章