用于获取最近价格变化最多的前 1 个产品的 SQL 查询

发布于 2024-08-24 06:36:59 字数 2834 浏览 10 评论 0原文

我使用的是 SQL Server 2005。

假设我有一个产品表和另一个价格表,以便我可以跟踪价格随时间的变化。我需要一个查询来获取不同的产品(简单部分)加上每个产品的最新价格及其更改日期。

产品表:

CREATE TABLE [dbo].[Products](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](50) NOT NULL,
    [Price] [money] NOT NULL,
 CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED 
( [ID] ASC )
) ON [PRIMARY]
GO

INSERT INTO Products (Name, Price) VALUES ('Hat', 10);
INSERT INTO Products (Name, Price) VALUES ('Shirt', 15);
INSERT INTO Products (Name, Price) VALUES ('Pants', 20);
INSERT INTO Products (Name, Price) VALUES ('Coat', 25);
INSERT INTO Products (Name, Price) VALUES ('Shoes', 30);

PriceChanges 表:

CREATE TABLE [dbo].[PriceChanges](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [ProductId] [int] NOT NULL,
    [Price] [money] NOT NULL,
    [PriceChanged] [datetime] NOT NULL,
 CONSTRAINT [PK_PriceChanges] PRIMARY KEY CLUSTERED 
( [ID] ASC )
) ON [PRIMARY]
GO

INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (1, 9.65, '1/1/2010');
INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (1, 10.10, '1/2/2010');
INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (1, 11.50, '1/3/2010');
INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (2, 15.50, '1/4/2010');
INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (2, 15.65, '1/5/2010');
INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (3, 19.95, '1/6/2010');
INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (4, 24.95, '1/7/2010');

这是一个返回太多的查询:

SELECT     
    p.ID ProductId, 
    p.Name, 
    COALESCE(c.Price, p.Price) Price, 
    c.PriceChanged
FROM dbo.Products AS p LEFT JOIN 
        dbo.PriceChanges AS c ON c.ProductId = p.ID

返回:

1   Hat     9.65    2010-01-01 00:00:00.000
1   Hat     10.10   2010-01-02 00:00:00.000
1   Hat     11.50   2010-01-03 00:00:00.000
2   Shirt   15.50   2010-01-04 00:00:00.000
2   Shirt   15.65   2010-01-05 00:00:00.000
3   Pants   19.95   2010-01-06 00:00:00.000
4   Coat    24.95   2010-01-07 00:00:00.000
5   Shoes   30.00   NULL

我需要它返回的是:

1   Hat     11.50   2010-01-03 00:00:00.000
2   Shirt   15.65   2010-01-05 00:00:00.000
3   Pants   19.95   2010-01-06 00:00:00.000
4   Coat    24.95   2010-01-07 00:00:00.000
5   Shoes   30.00   NULL

这个查询有效,但它有两个嵌套选择,这会让世界各地的 DBA 哭泣:

SELECT     
    p.ID ProductId, 
    p.Name, 
    COALESCE((SELECT TOP 1 Price FROM dbo.PriceChanges WHERE ProductId = p.ID ORDER BY PriceChanged DESC), p.Price) Price, 
    (SELECT TOP 1 PriceChanged FROM dbo.PriceChanges WHERE ProductId = p.ID ORDER BY PriceChanged DESC) PriceChanged
FROM dbo.Products AS p 

有什么更好的方法吗?这?

I'm using SQL Server 2005.

Let's say I have a table for products and another table for prices so that I can track price changes over time. I need a query that fetches distinct products (easy part) plus each product's most recent price and the date it changed.

Products Table:

CREATE TABLE [dbo].[Products](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](50) NOT NULL,
    [Price] [money] NOT NULL,
 CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED 
( [ID] ASC )
) ON [PRIMARY]
GO

INSERT INTO Products (Name, Price) VALUES ('Hat', 10);
INSERT INTO Products (Name, Price) VALUES ('Shirt', 15);
INSERT INTO Products (Name, Price) VALUES ('Pants', 20);
INSERT INTO Products (Name, Price) VALUES ('Coat', 25);
INSERT INTO Products (Name, Price) VALUES ('Shoes', 30);

PriceChanges Table:

CREATE TABLE [dbo].[PriceChanges](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [ProductId] [int] NOT NULL,
    [Price] [money] NOT NULL,
    [PriceChanged] [datetime] NOT NULL,
 CONSTRAINT [PK_PriceChanges] PRIMARY KEY CLUSTERED 
( [ID] ASC )
) ON [PRIMARY]
GO

INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (1, 9.65, '1/1/2010');
INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (1, 10.10, '1/2/2010');
INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (1, 11.50, '1/3/2010');
INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (2, 15.50, '1/4/2010');
INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (2, 15.65, '1/5/2010');
INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (3, 19.95, '1/6/2010');
INSERT INTO PriceChanges (ProductId, Price, PriceChanged) VALUES (4, 24.95, '1/7/2010');

Here's a query that returns too much:

SELECT     
    p.ID ProductId, 
    p.Name, 
    COALESCE(c.Price, p.Price) Price, 
    c.PriceChanged
FROM dbo.Products AS p LEFT JOIN 
        dbo.PriceChanges AS c ON c.ProductId = p.ID

Returns:

1   Hat     9.65    2010-01-01 00:00:00.000
1   Hat     10.10   2010-01-02 00:00:00.000
1   Hat     11.50   2010-01-03 00:00:00.000
2   Shirt   15.50   2010-01-04 00:00:00.000
2   Shirt   15.65   2010-01-05 00:00:00.000
3   Pants   19.95   2010-01-06 00:00:00.000
4   Coat    24.95   2010-01-07 00:00:00.000
5   Shoes   30.00   NULL

What I need it to return is:

1   Hat     11.50   2010-01-03 00:00:00.000
2   Shirt   15.65   2010-01-05 00:00:00.000
3   Pants   19.95   2010-01-06 00:00:00.000
4   Coat    24.95   2010-01-07 00:00:00.000
5   Shoes   30.00   NULL

This query works, but it's got two nested selects and it will make DBA's around the world weep:

SELECT     
    p.ID ProductId, 
    p.Name, 
    COALESCE((SELECT TOP 1 Price FROM dbo.PriceChanges WHERE ProductId = p.ID ORDER BY PriceChanged DESC), p.Price) Price, 
    (SELECT TOP 1 PriceChanged FROM dbo.PriceChanges WHERE ProductId = p.ID ORDER BY PriceChanged DESC) PriceChanged
FROM dbo.Products AS p 

What's a better way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

唯憾梦倾城 2024-08-31 06:36:59

它的执行速度比 [OMG Ponies] 快 2 倍,比你的快 20 倍(根据此数据)

select
    p.ID ProductId
    ,p.Name
    ,COALESCE(b.Price, p.Price) Price
    ,b.PriceChanged
from dbo.Products AS p 
LEFT JOIN 
(
    select
      a.ProductId
      ,a.PriceChanged
      ,pc2.Price     
    from
    (
        select 
           pc1.ProductId
           ,MAX(pc1.PriceChanged) as PriceChanged
        from dbo.PriceChanges pc1 
        group by pc1.ProductId 
    ) a         
    inner join dbo.PriceChanges pc2 
    on (a.PriceChanged = pc2.PriceChanged and a.ProductId = pc2.ProductId)
) b
ON b.ProductId = p.ID  

It executes 2 time faster than [OMG Ponies] one and in 20 times faster than your one (on this data)

select
    p.ID ProductId
    ,p.Name
    ,COALESCE(b.Price, p.Price) Price
    ,b.PriceChanged
from dbo.Products AS p 
LEFT JOIN 
(
    select
      a.ProductId
      ,a.PriceChanged
      ,pc2.Price     
    from
    (
        select 
           pc1.ProductId
           ,MAX(pc1.PriceChanged) as PriceChanged
        from dbo.PriceChanges pc1 
        group by pc1.ProductId 
    ) a         
    inner join dbo.PriceChanges pc2 
    on (a.PriceChanged = pc2.PriceChanged and a.ProductId = pc2.ProductId)
) b
ON b.ProductId = p.ID  
青巷忧颜 2024-08-31 06:36:59

使用:

   SELECT p.id AS productid,
          p.name,
          COALESCE(x.price, p.price) AS price,
          x.pricechanged
     FROM dbo.PRODUCTS p
LEFT JOIN (SELECT pc.productid,
                  pc.price,
                  pc.pricechanged,
                  ROW_NUMBER() OVER(PARTITION BY pc.productid 
                                        ORDER BY pc.pricechanged DESC) AS rownum
             FROM dbo.PRICECHANGES pc) x ON x.productid = p.id
                                        AND x.rownum = 1

Use:

   SELECT p.id AS productid,
          p.name,
          COALESCE(x.price, p.price) AS price,
          x.pricechanged
     FROM dbo.PRODUCTS p
LEFT JOIN (SELECT pc.productid,
                  pc.price,
                  pc.pricechanged,
                  ROW_NUMBER() OVER(PARTITION BY pc.productid 
                                        ORDER BY pc.pricechanged DESC) AS rownum
             FROM dbo.PRICECHANGES pc) x ON x.productid = p.id
                                        AND x.rownum = 1
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文