2010-03-10 85 views
4

我使用的是SQL Server 2005中SQL查詢來獲取產品,最頂級的1最新價格變化

比方說,我有一個產品表與另一個表價格,使我可以跟蹤一段時間的價格變化。我需要一個查詢來獲取不同的產品(簡單部分)以及每個產品的最新價格和更改的日期。

產品表:

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 

什麼是更好的方法做這個?

回答

4

它執行2的時間比[OMG小馬]比你的速度更快之一,在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 
+0

+1:更快,因爲使用'ROW_NUMBER()'意味着解析'dbo.PRICECHANGES'中的所有記錄 – 2010-03-11 00:25:14

4

用途:

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 
+0

就像一個魅力更快。 – 2010-03-10 23:53:42

+0

+1這很酷,但舊的風格工作更快(當然這個數據)。 ;) – garik 2010-03-11 00:20:24