首先,尽管我还涉猎……但我绝不是SQL专家。
我的问题如下:我有一个大型数据库,其中包含用于
的表iteminfo(基本商品说明)(。[itemno])
solditems(关于商品销售的信息)(。[itemno]。[ratecode]。[qty]。[price])
费率(基本上是商品的销售价格)(。[ratecode])
我需要生成一个报告(水晶报告),以显示每个商品在每种价格下已售出多少次以及该商品的总价值。我遇到的问题是[rates]表对于不同的数据库可能大小不同,并且可以添加更多的速率,或者可以删除未使用的速率。
我建立了以下SQL查询来获取此信息,但是如果数据库中有10种不同的比率,我需要将代码复制粘贴到10次以下,从而使查询非常混乱,当然,它不会t会考虑第11个比率,并且如果除去比率(或更糟的是,如果比率nr 5被除去并且6变成5、7变成6,等等),则开始返回奇数。
注意:s.itemno是主要查询,是要查询的特定项目的项目编号。
(select count(solditems.ratecode)
from solditems
where solditems.itemno = s.itemno
and solditems.ratecode = (
select [ratecode]
from (
select row_number() over (order by [ratecode]) as rownumber, *
from dbo.rates
) as mytable
where rownumber = '**1**'
)
) as ratqty**1**,
(select sum(solditems.qty * solditems.price) from solditems
where solditems.itemno = s.itemno and solditems.ratecode = (select
[ratecode] from (select row_number() over (order by [ratecode]) as
rownumber, * from dbo.rates) as mytable where rownumber = '**1**'))
as rateval**1**,
...
如果我使用像C这样的编程语言,我将只写一个for循环,例如(伪代码):int maxi = count(rates.ratecode)for i = 0和i!= maxi {为rownumber i做一些事情} i ++
Q1:有没有一种方法可以像SQL中那样构建for循环(必须与Crystal报表兼容,因此越简单越好)。
第2季度:如果取消汇率,随后的表格上升到某个位置(6变为5,7变为6,依此类推),我将如何避免出现问题。
奖金问:上面的代码不是很优雅,有没有更简单的方法?
请求的示例输出:
itemno 1在价码1下已售出5次,每次售价€1000 itemno 2在价码1下已售出6次,每次售价€500。 等
答案 0 :(得分:0)
为避免循环和粘贴粘贴,您需要一个dynamic pivot
用于两个聚合值,例如:
DECLARE
@cmd NVARCHAR(MAX) = N'',
@qty_cols NVARCHAR(MAX) = N'',
@val_cols NVARCHAR(MAX) = N'',
@n int = 0
-- this can be done in any other manner like via spt_values or FOR XML and so on
SELECT TOP 100 PERCENT
@n += 1,
@qty_cols += ', [rateqty-' + CAST(@n AS VARCHAR(10)) + ']',
@val_cols += ', [rateval-' + CAST(@n AS VARCHAR(10)) + ']',
@cmd += ', MAX([rateqty-' + CAST(@n AS VARCHAR(10)) + ']) as [rateqty-' + CAST(@n AS VARCHAR(10)) + ']'
+ ', MAX([rateval-' + CAST(@n AS VARCHAR(10)) + ']) as [rateval-' + CAST(@n AS VARCHAR(10)) + ']'
FROM #rates r
ORDER BY r.ratecode
set @cmd = 'SELECT ' + STUFF(@cmd, 1, 2, '') + '
from
(
select
''rateqty-'' + CAST(rn AS VARCHAR(10)) ratecode_qty,
''rateval-'' + CAST(rn AS VARCHAR(10)) ratecode_val,
rateqty, rateval
from (
select ratecode, rateqty, rateval, ROW_NUMBER() OVER(ORDER BY r.ratecode) rn
from #rates r
) r
) r
pivot (max(r.rateqty) for ratecode_qty in (' + STUFF(@qty_cols, 1, 2, '') + ' )) p1
pivot (max(p1.rateval) for ratecode_val in (' + STUFF(@val_cols, 1, 2, '') + ' )) p2
order by 1'
exec(@cmd)
;
对于这些示例数据:
insert into rates(ratecode)
values (1), (2), (3)
insert into solditems(ratecode, qty, price)
values
(1, 5, 22),
(1, 2, 22),
(3, 1, 33)
输出将是:
| rateqty-1 | rateval-1 | rateqty-2 | rateval-2 | rateqty-3 | rateval-3 |
|-----------|-----------|-----------|-----------|-----------|-----------|
| 2 | 154 | 0 | 0 | 1 | 33 |
此处的完整来源: http://sqlfiddle.com/#!18/6f390/42
关于简化报表中的子查询的问题,其中有更多的源表参与其中,然后我的猜测(因为您仅显示了部分代码)必须ratecodes
进行{外部查询(听起来有点吓人),或直接加入CROSS JOIN
并进行汇总(先是然后是),如下所示:
solditems
upd:发布此子查询后,我意识到SELECT
...
FROM ... <outer query>
CROSS APPLY
(
select
r.ratecode,
count(1) rateqty, -- i don't quite understand what is this supposed to be; number of transactions?
sum(si.qty * si.price) rateval
from solditems si
INNER JOIN dbo.rates r
ON si.ratecode = r.ratecode
where si.itemno = s.itemno
group by r.ratecode
) s
除dbo.rates
之外均未使用。因此,如果您要进行数据透视,则无需在此处加入ROWNUMBER
的链接:
rates