每个产品返回一个SQL行,包含价格和最新日期

时间:2016-11-29 09:40:51

标签: sql sql-server

我不是一个SQL人,我过去曾经使用它,很少有一个问题无法通过谷歌解决......但这次我需要问社区。

我有一个名为'Transactions'的数据库,它有这样的数据:

ProdNo    | Price | TransactionDate | PurchasedBy | etc.....
----------------------------------------------------------
3STRFLEX  | 13.02 | 20162911        | AWC         | .....
3STRFLEX  | 15.02 | 20162011        | DWC         | .....
3STRFLEX  | 15.02 | 20160101        | AWC         | .....
AFTV2     | 35.49 | 20162708        | AWC         | .....
AFTV2     | 29.99 | 20160106        | DWC         | .....
AFTV2     | 29.99 | 20160205        | AWC         | .....

所需的输出是:

ProdNo    | Price | TransactionDate 
-----------------------------------
3STRFLEX  | 13.02 | 20162911        
AFTV2     | 35.49 | 20162708        

我已经尝试过自己写这个,我最终得到了这样的SQL:

select t.ProdNo, t.TransactionDate as 'LastPurchaseDate', t.Price
from Transactions t
inner join (
     select ProdNo, max(TransactionDate) as 'LastPurchaseDate'
     from Transactions
     WHERE Price > 0
     group by ProdNo
 ) tm on t.ProdNo = tm.ProdNo and LastPurchaseDate = tm.LastPurchaseDate

但是在我的数据集中,这会返回(减少),显示每个产品有多行

ProdNo    | LastPurchaseDate | Price
3STRFLX   | 20120924         | 0.000000
3STRFLX   | 20120924         | 22.000000
3STRFLX   | 20150623         | 0.000000
3STRFLX   | 20150623         | 1.220000
3STRFLX   | 20150623         | 1.222197

所以要确认一下:无论价格如何,我希望每个产品购买一行,不管价格如何,但我需要退回数据中的价格。

由于

6 个答案:

答案 0 :(得分:6)

您可以使用CTE和排名函数PARTITION BY

WITH CTE AS
(
    select t.ProdNo, t.TransactionDate as 'LastPurchaseDate', t.Price,
           rn = row_number() over (partition by ProdNo order by TransactionDate desc)
    from Transactions t
)
SELECT ProdNo, LastPurchaseDate, Price  FROM CTE WHERE RN = 1

答案 1 :(得分:1)

你走在正确的轨道上。如果您使用该怎么办:

select t.ProdNo, t.TransactionDate as 'LastPurchaseDate', t.Price
from Transactions t
inner join (
     select ProdNo, max(TransactionDate) as 'LastPurchaseDate'
     from Transactions
     WHERE Price > 0
     group by ProdNo
 ) tm on t.ProdNo = tm.ProdNo and t.TransactionDate= tm.LastPurchaseDate

请注意加入条件的变化。

您的查询中发生了什么:LastPurchaseDate = tm.LastPurchaseDate。只有一列名为LastPurchaseDate,因此它将其与自身等同,这始终是正确的。因此,您t.ProdNo = tm.ProdNo离开,因为t.ProdNo不是唯一的,您会为每个t.ProdNo返回多条记录。

答案 2 :(得分:1)

一种方法使用ROW_NUMBER windowed function

我的查询使用common table expression (CTE)来提供示例数据。使用此技术时,您始终需要CTE或subquery。这是因为SELECT子句中生成的值不可用于WHERE子句。这是Logical Processing Order之类的结果。换一种说法; SQL Server在过滤数据后生成行号。 CTE /子查询为您提供了第二个WHERE子句,该子句在生成行号后执行**。

-- Returning the most recent record from a transaction table.
WITH SampleDate AS
    (
        SELECT
            ROW_NUMBER() OVER (PARTITION BY ProdNo ORDER BY TransactionDate DESC) AS Rn,
            *
        FROM
            (
                VALUES                      
                    ('3STRFLEX', 13.02, '20162911', 'AWC '),
                    ('3STRFLEX', 15.02, '20162011', 'DWC '),
                    ('3STRFLEX', 15.02, '20160101', 'AWC '),
                    ('AFTV2'   , 35.49, '20162708', 'AWC '),
                    ('AFTV2'   , 29.99, '20160106', 'DWC '),
                    ('AFTV2'   , 29.99, '20160205', 'AWC ')
            ) AS x(ProdNo, Price, TransactionDate, PurchasedBy)
    )
SELECT
    *
FROM
    SampleDate
WHERE
    Rn = 1
;

**实际上这并非完全正确。出于某种原因,它被称为逻辑顺序。 SQL Sever可以/将以任何它认为合适的方式执行您的查询。但是,无论您的查询是物理执行的,它都会遵循逻辑顺序。

答案 3 :(得分:0)

试试这个。通过使用row_number()。

             select * from 
             (
             select 
             T.ProdNo, 
             T.TransactionDate as 'LastPurchaseDate', 
             T.Price,           
             row_number() over (partition by ProdNo order by TransactionDate desc) as rnk
             from Transactions T
             )a
             where rnk='1'

答案 4 :(得分:0)

请试试这个 - 如果一个ProdNo有两个相同的最大TransactionDate,则返回两行

select ProdNo,Price,TransactionDate from Transactions t 
where not exists (select 1 from Transactions where ProdNo=t.ProdNo and TransactionDate>t.TransactionDate)

答案 5 :(得分:-1)

SELECT A.ProdNo ,Price ,A.TransactionDate,PurchasedBy 
FROM #Transactions 
JOIN 
(
SELECT ProdNo,MAX(TransactionDate) TransactionDate
FROM #Transactions 
GROUP BY ProdNo
)A ON A.TransactionDate = #Trans.TransactionDate