sql - 使用 Subselect 优化查询

标签 sql sql-server optimization

我正在尝试生成一份销售报告,其中列出每个产品 + 给定月份的总销售额。这有点棘手,因为产品价格可能会在整个月内发生变化。例如:

  • 在 1 月 1 日和 1 月 15 日之间,我的公司以每个 10 美元的成本销售了 50 个小部件
  • 在 1 月 15 日和 1 月 31 日之间,我的公司以每个 15 美元的价格销售了 50 个以上的 Widget
  • 1 月份 Widget 的总销售额 = (50 * 10) + (50 * 15) = 1250 美元

此设置在数据库中表示如下:

Sales table
  Sale_ID    ProductID    Sale_Date
  1          1            2009-01-01
  2          1            2009-01-01
  3          1            2009-01-02
             ...
  50         1            2009-01-15
  51         1            2009-01-16
  52         1            2009-01-17
             ...
  100        1            2009-01-31

Prices table
  Product_ID    Sale_Date    Price
  1             2009-01-01   10.00
  1             2009-01-16   15.00

When a price is defined in the prices table, it is applied to all products sold with the given ProductID from the given SaleDate going forward.

Basically, I'm looking for a query which returns data as follows:

Desired output
  Sale_ID    ProductID    Sale_Date     Price
  1          1            2009-01-01    10.00
  2          1            2009-01-01    10.00
  3          1            2009-01-02    10.00
             ...
  50         1            2009-01-15    10.00
  51         1            2009-01-16    15.00
  52         1            2009-01-17    15.00
             ...
  100        1            2009-01-31    15.00

I have the following query:

SELECT
    Sale_ID,
    Product_ID,
    Sale_Date,
    (
        SELECT TOP 1 Price
        FROM Prices
        WHERE
            Prices.Product_ID = Sales.Product_ID
            AND Prices.Sale_Date < Sales.Sale_Date 
        ORDER BY Prices.Sale_Date DESC
    ) as Price
FROM Sales

这可行,但是有比嵌套子选择更有效的查询吗?

在您指出在 Sales 表中包含“价格”会更容易之前,我应该提到该架构由另一个供应商维护,我无法更改它。以防万一,我使用的是 SQL Server 2000。

最佳答案

如果您开始存储开始日期和结束日期,或者创建一个包含开始日期和结束日期的 View (您甚至可以创建一个索引 View ),那么您可以大大简化您的查询。 (前提是你确定没有范围重叠)

SELECT
    Sale_ID,
    Product_ID,
    Sale_Date,
    Price
FROM Sales
JOIN Prices on Sale_date > StartDate and Sale_Date <= EndDate  
-- careful not to use between it includes both ends 

注意:

沿着这些思路的技术将允许您使用 View 来执行此操作。请注意,如果您需要为 View 编制索引,则必须花很多功夫......

create table t (d datetime)

insert t values(getdate())
insert t values(getdate()+1)
insert t values(getdate()+2)

go
create view myview 
as
select start = isnull(max(t2.d), '1975-1-1'), finish = t1.d  from t t1
left join t t2 on t1.d > t2.d
group by t1.d

select * from myview 

start                   finish
----------------------- -----------------------
1975-01-01 00:00:00.000 2009-01-27 11:12:57.383
2009-01-27 11:12:57.383 2009-01-28 11:12:57.383
2009-01-28 11:12:57.383 2009-01-29 11:12:57.383

关于sql - 使用 Subselect 优化查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/481645/

相关文章:

sql - 如何从表中选择唯一年份

php - SQL 查询从大量字符串列表中获取数据

java - 在 mssql 的情况下,metadata.getTables 结果集为空

sql-server - SQL Server - 获取所有连接的服务器名称

javascript - 查找相对于字符串中给定位置左侧第一次出现的空格

java - 如何对SQL结果进行排序

sql - 主键数据类型会影响性能吗? SQL Server 2008

java - 带有最终变量的 Android 内联监听器

java - "conditional"是否被 "int i = flag ? 1 : 0;"中的 JIT 删除了?

PHP array_push() 因来自 SQL 的文本而失败