2009-09-30 7 views
3

Le but de cette requête est de ramener les produits et leurs prix pour les produits en vente et le prix devrait être à la date la plus proche mais pas la date passée, essentiellement le prix le plus récent disponible. Il n'y a pas de relevés de prix pour chaque jour. Quelque chose ne va pas dans le fait d'avoir l'instruction select globale dans la clause where. Y a-t-il une meilleure manière de faire cela? Peut-être dans les critères de jointure?Amélioration de SQL Requête avec la fonction max() dans la clause where

 select 
     p.ProductName, 
     pp.Price, 
     pp.Date, 
     from product p 
     inner join productprice pp on p.productid = pp.productid 
     where 
     pp.evaluationdate = (select max(Date) from productprice 
          where productid = p.productid 
          and date < @DateIn) 
     and p.producttype = 'OnSale' 

La requête en cours est un peu plus compliquée mais c'est essentiellement le problème. Merci pour votre contribution.

EDIT Il y aura plus d'un produit retourné

EDIT J'expérimente à la fois de @Remus Rusanu et @ suggestions de km (bien que @Remus Rusanu a enlevé son) tous les trois, y compris mon d'origine, semblent être à peu près les mêmes en termes de performance. J'essaie de décider si l'un offre un avantage sur les autres d'une autre manière intangible, c'est-à-dire la maintenance, l'auto-documentation, etc., car cela sera maintenu par quelqu'un d'autre. Merci encore.

Répondre

5

essayez ceci:

;WITH CurrentPrice AS 
(
SELECT productid,max(Date) AS Date 
    FROM productprice 
    WHERE date < @DateIn 
    GROUP BY productid 
) 

select 
    p.ProductName, 
    pp.Price, 
    pp.Date, 
    from product p 
     inner join CurrentPrice pa on p.productid = pa.productid 
     inner join productprice pp on pa.productid = pp.productid AND pa.Date=pp.Date 
    where p.producttype = 'OnSale' 

EDIT basé sur le commentaire OP:

Je pense que la requête ci-dessus avec CTE aura le même plan de requête comme l'derived table version from @Remus Rusanu

Toutefois, si la table productprice est grande, vous souhaiterez peut-être la réduire en filtrant le ""."comme ici:

;WITH CurrentPrice AS 
(
select 
    p.productid, 
    MAX(pp.Date) AS Date 
    from product p 
     inner join productprice pp on pa.productid = pp.productid 
    where p.producttype = 'OnSale' AND pp.date < @DateIn 
    GROUP BY productid 
) 
select 
    p.ProductName, 
    pp.Price, 
    pp.Date, 
    from CurrentPrice   pa 
     inner join product  p on pa.productid = p.productid 
     inner join productprice pp on pa.productid = pp.productid AND pa.Date=pp.Date 
    where p.producttype = 'OnSale' 
+0

Je pense que cela fonctionnerait probablement, bien que je limiterais le CTE pour filtrer les produits pour les critères de "onsale", mais cela semble être essentiellement la même chose. La performance serait-elle différente avec le CTE sur la sous-requête? ProductPrice est une grande table – Gratzy

+0

Ma réponse était fondamentalement identique à la vôtre, donc j'ai enlevé la mienne. –

0
SELECT TOP 1 p.ProductName, pp.Price, pp.Date, 
FROM product p 
INNER JOIN productprice pp on ... 
WHERE pp.date < @DateIn 
ORDER BY pp.date DESC 
+0

Désolé Il y aura plus d'un produit retourné, tous les produits en vente, donc top 1 n'apportera moi le premier record pour le premier prodcut – Gratzy

1

Est-ce un travail pour les fonctions de la fenêtre?

SELECT * FROM (select 
      p.ProductName, 
      pp.Price, 
      pp.Date, 
      RANK() OVER(PARTITION BY p.ProductId ORDER BY pp.Date DESC) as row_rank 
      from product p 
       join productprice pp on p.productid = pp.productid 
      where 
       pp.date < @DateIn 
       and p.producttype = 'OnSale' 
    ) saleprice 
    where row_rank = 1 

EDIT partitions par id (en supposant que votre clé primaire est le plus rapide), partitionner le prix retiré

+0

J'ai pensé à une solution comme celle-ci, mais je suis allé avec le CTE. Je pense que le RANK() devrait être: _RANK() OVER (PARTITION PAR p.Productid ORDER BY p.Productid, pp.Date DESC) en tant que row_rank_ –

+0

Vous avez raison, j'ai fait goof le RANK(), il a seulement besoin de partiton sur l'id de produit mais l'ordre par n'en a pas besoin, je pense. édité – Damon

Questions connexes