我正在寻求改进我使用SQL-Server 2005为ASP.NET 4.0中的小型Web应用程序编写的查询。此应用程序将允许用户按产品ID进行搜索并让它返回以下信息:
以下是Products表的结构(我只包括相关列,这是一个已经在生产中的数据库,这些是非pk列)
在我放下查询之前,我到目前为止我只想说我可以通过多个查询轻松获取此信息,因此如果这是最佳实践,则忽略改进查询,但我的目标是最小化数量获取所有必需信息所需的查询。
到目前为止我所拥有的:(注意:有些行的价格= 0所以我忽略了底部的那些选择寻找MIN价格)
SELECT price, MAX(pDate)
FROM Products
WHERE product_id = @product_id AND
(price = (SELECT MAX(price)
FROM Products
WHERE product_id =@product_id) OR
price = (SELECT MIN(price)
FROM Products
WHERE product_id = @product_id AND price > 0))
GROUP BY price
现在返回2行:
我最理想的是让查询返回1行,如果可能的话,上面包含上述所有必需信息,因为它可以简化在ASP中显示ASP中的信息。就像我之前说的那样,如果有多个查询是方法,则无需在此处重新编写复杂查询。
修改的
以下是一些示例数据
所需的查询结果:(忽略我在excel中输入的格式)
以下是我将使用的查询,感谢Ken Benson:
SELECT TOP 1 prod.product_id,
minp.price AS minprice, minp.pDate as minlastdate,
maxp.price AS maxprice, maxp.pDate as maxlastdate,
ag.price AS averageprice
FROM products AS prod
LEFT JOIN (SELECT lmd.product_id,max(lmd.pDate) as pDate,mn.price FROM products as lmd INNER JOIN
(SELECT product_id, min(price) AS price from products WHERE price > 0 group by product_id) as mn ON lmd.product_id=mn.product_id AND lmd.price=mn.price
group by lmd.product_id,mn.price ) AS minp ON minp.product_id=prod.product_id
LEFT JOIN (SELECT lxd.product_id,max(lxd.pDate) as pDate,mx.price FROM products as lxd INNER JOIN
(SELECT product_id, max(price) AS price from products group by product_id) as mx ON lxd.product_id=mx.product_id AND lxd.price=mx.price
group by lxd.product_id,mx.price ) AS maxp ON maxp.product_id=prod.product_id
LEFT JOIN (SELECT product_id,avg(price) as price FROM products WHERE price > 0 GROUP BY product_id) AS ag ON ag.product_id=prod.product_id
WHERE prod.product_id=@product_id
答案 0 :(得分:1)
我认为你可以做几个连接回到桌面......
Select product_id, min.price, min.pDate, max.price, max.pDate
FROM products as p
LEFT JOIN (Select Min(price), pDate, product_id FROM products GROUP BY product_id)
as min on min.product_id=p.product_id
LEFT JOIN (Select max(price), pDate, product_id FROM products GROUP BY product_id)
as max on max.product_id=p.product_id
Where p.product_id = @product_id
这第二段代码应该产生预期的结果....
SELECT prod.product_id,
minp.price AS minprice, minp.pDate as minlastdate,
maxp.price AS maxprice, maxp.pDate as maxlastdate,
ag.price AS averageprice
FROM products AS prod
LEFT JOIN (SELECT lmd.product_id,max(lmd.pDate) as pDate,mn.price FROM products as lmd INNER JOIN
(SELECT product_id, min(price) AS price from products group by product_id) as mn ON lmd.product_id=mn.product_id
group by lmd.product_id,mn.price ) AS minp ON minp.product_id=prod.product_id
LEFT JOIN (SELECT lxd.product_id,max(lxd.pDate) as pDate,mx.price FROM products as lxd INNER JOIN
(SELECT product_id, max(price) AS price from products group by product_id) as mx ON lxd.product_id=mx.product_id
group by lxd.product_id,mx.price ) AS maxp ON maxp.product_id=prod.product_id
LEFT JOIN (SELECT product_id,avg(price) as price FROM products GROUP BY product_id) AS ag ON ag.product_id=prod.product_id
WHERE prod.product_id=1
LIMIT 1
<是>是的 - 遗漏了'和'条件:
SELECT TOP 1
prod.product_id,
minp.price AS minprice, minp.pDate as minlastdate,
maxp.price AS maxprice, maxp.pDate as maxlastdate,
ag.price AS averageprice
FROM products AS prod
LEFT JOIN (SELECT lmd.product_id,max(lmd.pDate) as pDate,mn.price FROM products as lmd INNER JOIN
(SELECT product_id, min(price) AS price from products group by product_id) as mn ON lmd.product_id=mn.product_id **AND lmd.price=mn.price**
group by lmd.product_id,mn.price ) AS minp ON minp.product_id=prod.product_id
LEFT JOIN (SELECT lxd.product_id,max(lxd.pDate) as pDate,mx.price FROM products as lxd INNER JOIN
(SELECT product_id, max(price) AS price from products group by product_id) as mx ON lxd.product_id=mx.product_id AND **lxd.price=mx.price**
group by lxd.product_id,mx.price ) AS maxp ON maxp.product_id=prod.product_id
LEFT JOIN (SELECT product_id,avg(price) as price FROM products GROUP BY product_id) AS ag ON ag.product_id=prod.product_id
WHERE prod.product_id=@product_id
答案 1 :(得分:0)
我会通过排名函数和条件聚合的组合来实现这一点:
select product_id,
max(case when seqnum_hi = 1 then price end) as highPrice,
max(case when seqnum_hi = 1 then pdate end) as highPrice_date
max(case when seqnum_low = 1 then price end) as lowPrice,
max(case when seqnum_low = 1 then pdate end) as lowPrice_date,
max(case when seqnum_rec = 1 then price end) as recentPrice,
max(case when seqnum_rec = 1 then pdate end) as recentPrice_date,
avg(price) as avg_price
from (select p.*,
row_number() over (partition by product_id order by price asc) as seqnum_low,
row_number() over (partition by product_id order by price desc) as seqnum_hi,
row_number() over (partition by product_id order by pdate desc) as seqnum_rec
from price
where product_id = @product_id
group by product_id
序号表示具有您关注的特定属性的行(高价,低价,最近)。条件max然后只选择那些行中的信息。
答案 2 :(得分:0)
以下应该得到你想要的。它很长,但是可读,所以任何需要的人都应该很容易修改:
;WITH CTE_MaxPrice AS
(
SELECT product_id, MAX(P.price) AS MaxPrice
FROM Products P
GROUP BY product_id
HAVING product_id = @product_id
),
CTE_MinPrice AS
(
SELECT product_id, MIN(P.price) AS MinPrice
FROM Products P
GROUP BY product_id
HAVING product_id = @product_id
),
CTE_MaxPriceDate AS
(
SELECT P.product_id, MAX(P.pDate) AS MaxDate
FROM Products P
INNER JOIN CTE_MaxPrice MaxP ON P.product_id = MaxP.product_id
AND P.price = MaxP.MaxPrice
GROUP BY P.product_id
),
CTE_MinPriceDate AS
(
SELECT P.product_id, MAX(P.pDate) AS MinDate
FROM Products P
INNER JOIN CTE_MinPrice MinP ON P.product_id = MinP.product_id
AND P.price = MinP.MinPrice
GROUP BY P.product_id
)
SELECT MaxP.MaxPrice, MaxPD.MaxDate,
MinP.MinPrice, MinPD.MinDate,
RP.price AS RecentPrice, MAX(RP.pDate) AS RecentDate,
AVG(AP.price) AS AveragePrice
FROM Products P
INNER JOIN CTE_MaxPrice MaxP ON P.product_id = MaxP.product_id
INNER JOIN CTE_MinPrice MinP ON P.product_id = MinP.product_id
AND MinP.MinPrice > 0
INNER JOIN CTE_MaxPriceDate MaxPD ON P.product_id = MaxPD.product_id
INNER JOIN CTE_MinPriceDate MinPD ON P.product_id = MinPD.product_id
INNER JOIN Products RP ON P.product_id = RP.product_id
INNER JOIN Products AP ON P.product_id = AP.product_id
GROUP BY MaxP.MaxPrice, MaxPD.MaxDate,
MinP.MinPrice, MinPD.MinDate, RP.price
HAVING P.product_id = @product_id
答案 3 :(得分:0)
好了,因为已经有三次尝试回答,而且没有一种方法可以按照你想要的方式工作,我会告诉你我将如何做 - 这假设你可以使用存储过程并假设产品table不是很大,以至于多个单独的查询会成为一个问题:
CREATE PROCEDURE myproc AS
DECLARE @Price1 money
DECLARE @Date1 smalldatetime
DECLARE @Price2 money
DECLARE @Date2 smalldatetime
DECLARE @Price3 money
DECLARE @Date3 smalldatetime
DECLARE @Price4 money
SELECT @Price1 = MAX(Price) FROM Products
SELECT @Date1 = MAX(pDate) FROM Products WHERE Price=@Price1
SELECT @Price2 = Min(Price) FROM Products WHERE Price >0
SELECT @Date2 = MAX(pDate) FROM Products WHERE Price=@Price2
SELECT @Date3 = Max(pDate) FROM Products
SELECT @Price3 = MAX(Price) FROM Products WHERE pDate=@Date3 --max in case there are more than one purchases with the same date.
SELECT @Price4 = AVG(Price) FROM Products WHERE Price>0
SELECT @Price1 As MaxPrice,
@Date1 As MaxPriceDate,
@Price2 As LowPrice,
@Date2 As LowPriceDate,
@Price4 As AveragePrice,
@Price3 As RecentPrice,
@Price3 As RecentPriceDate
GO
原谅任何印刷错误,我没有对此进行测试,但如果您可以使用存储过程,这将有效。
所以这与从客户端执行多个查询没什么不同,但应该更好地将它们全部放入单个SP中。你也可以通过使用其他答案中的一些代码来减少一些查询,但为了清楚起见,我已经这样做了。