在上一篇
中,我虽然抛弃了大家不喜欢的游标,但是临时表还是存在的,但是ascrat老兄的意思被我误解了一半,所以,哈哈。。。。。。。下面是老兄在上一篇的回复,我又重新修改了T-SQL,这回要比上回的更好。
感谢老兄的指点,希望大家贡献更好的,感谢大家的参与!!!
呃...可能楼主误解了我的意思..我说的是这样..
1, 主表的查询还是你写的方式
2, 明细的像这样:
select .... from
(
select 主表的10个定单, 需要的主表字段 from 主表..分页..
) a
inner join 明细表 b on a.主表ID = b.主表ID
你可以想象一下..如果这里的集合 a 不只是一个主表筛选出来, 而是从很多个表连接并计算得出的集合, 如果每个集合都 into 到临时表里去, 效率暂且不说..代码也会多很多的.
代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
--
ascrat老兄的提示,好办法啊
--
省去了游标,省去了临时表
--
(学习的)路漫漫其修远啊
SELECT
a.
*
,od.
*
FROM
(
SELECT
*
FROM
(
SELECT
ROW_NUMBER()
OVER
(
ORDER
BY
oi.CreateDate
DESC
)
AS
rownumber,oi.OrderSeqNO
FROM
OrderInfo oi
WHERE
oi.OrderSeqNO
LIKE
'
%2%
'
)
AS
o
WHERE
o.rownumber
BETWEEN
10
AND
20
) a
INNER
JOIN
OrderDetail od
ON
a.OrderSeqNO
=
od.OrderSeqNO
这个系列的完整代码如下
代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
--
SELECT TOP 10 oi.OrderSeqNO, oi.GoodsName ,ci.CompanyName,od.*
--
FROM OrderInfo oi INNER JOIN CompanyInfo ci ON oi.CompanyID=ci.CompanyID
--
LEFT JOIN OrderDetail od ON oi.OrderSeqNO=od.OrderSeqNO
--
使用row_unmber()实现分页
--
本来我们想要的结果是10条订单,结果却不是10条订单,而是10条明细
--
其实是针对的子表进行分页了,订单并不是要显示的个数,出来的个数是明细的个数
--
就是因为主表和子表联合查询的结果,主表记录和子表记录是1:N的关系,一个主表记录有多个明细
--
建立聚集索引
--
CLUSTERED INDEX INDEX_OrderInfo ON OrderInfo (OrderSeqNo)
--
显示查询执行计划
SET
STATISTICS
IO
ON
select
*
from
(
SELECT
ROW_NUMBER ()
OVER
(
ORDER
BY
oi.createdate
DESC
)
AS
rownumber,oi.orderseqno ,od.OrderDetailID
FROM
OrderInfo oi
LEFT
JOIN
OrderDetail od
ON
oi.OrderSeqNO
=
od.OrderSeqNO
WHERE
oi.OrderSeqNO
LIKE
'
%2%
'
)
AS
o
WHERE
rownumber
BETWEEN
10
AND
20
--
不用游标的分页
--
先将分页的主表放在临时表中,然后用临时表和子表联合查询,来获取子表信息
--
既保证了分页的正确性,也包括了子表信息
CREATE
TABLE
#
order
(
number
BIGINT
,
orderseqno
VARCHAR
(
36
),
)
insert
into
#
order
SELECT
*
FROM
(
SELECT
ROW_NUMBER()
OVER
(
ORDER
BY
oi.CreateDate
DESC
)
AS
rownumber,oi.OrderSeqNO
FROM
OrderInfo oi
WHERE
oi.OrderSeqNO
LIKE
'
%2%
'
)
AS
o
WHERE
o.rownumber
BETWEEN
10
AND
20
SELECT
*
FROM
#
order
INNER
JOIN
OrderDetail od
ON
od.OrderSeqNO
=
#
order
.orderseqno
DROP
TABLE
#
order
--
ascrat老兄的提示,好办法啊
--
省去了游标,省去了临时表
--
(学习的)路漫漫其修远啊
SELECT
a.
*
,od.
*
FROM
(
SELECT
*
FROM
(
SELECT
ROW_NUMBER()
OVER
(
ORDER
BY
oi.CreateDate
DESC
)
AS
rownumber,oi.OrderSeqNO
FROM
OrderInfo oi
WHERE
oi.OrderSeqNO
LIKE
'
%2%
'
)
AS
o
WHERE
o.rownumber
BETWEEN
10
AND
20
) a
INNER
JOIN
OrderDetail od
ON
a.OrderSeqNO
=
od.OrderSeqNO
--
解决上面的问题,有以下几种办法
--
1、先根据条件查询主表记录,然后在C#代码中循环,再次到数据库查询每条主表记录的明细信息,然后赋值给属性
--
2、在数据库的存储过程中使用游标,也是先查询主表记录,然后使用游标循环的过程中,查询子表信息,然后在C#中
--
集中处理
--
很显然,后一种减少了数据库的往来开销,一次获取了想要的数据,个人认为要比第一种好,欢迎大家一起讨论更好的办法
--
需要注意的就是ROW_NUMBER()返回的类型是bigint,而不是int
--
下面是游标的存储过程
--
建立主表临时表
CREATE
TABLE
#
temp
(
rownumber
bigint
,
orderseqno
VARCHAR
(
36
),
goodsname
VARCHAR
(
50
),
companyname
VARCHAR
(
100
)
)
--
建立子表临时表
CREATE
TABLE
#detail
(
orderseqno
VARCHAR
(
36
),
detailid
UNIQUEIDENTIFIER
,
unitprice
DECIMAL
(
12
,
2
),
Qty
int
)
--
插入主表数据到主表临时表
insert
into
#
temp
SELECT
*
--
oo.rownumber, oo.OrderSeqNO, oo.GoodsName, oo.CompanyName
FROM
(
SELECT
ROW_NUMBER ()
OVER
(
ORDER
BY
oi.createdate
DESC
)
AS
rownumber,
oi.OrderSeqNO, oi.GoodsName ,ci.CompanyName
FROM
OrderInfo oi
INNER
JOIN
CompanyInfo ci
ON
oi.CompanyID
=
ci.CompanyID
WHERE
oi.CreateDate
<
GETDATE
()
)
AS
oo
WHERE
rownumber
BETWEEN
10
AND
20
--
定义游标
DECLARE
@temp_cursor
CURSOR
--
给游标赋值
SET
@temp_cursor
=
CURSOR
FOR
SELECT
#
temp
.orderseqno,#
temp
.goodsname
FROM
#
temp
--
定义游标循环过程中所需保存的临时数据
DECLARE
@orderseqno
VARCHAR
(
36
),
@goodsname
varchar
(
50
)
--
打开游标
OPEN
@temp_cursor
FETCH
NEXT
FROM
@temp_cursor
INTO
@orderseqno
,
@goodsname
--
循环游标,查询子表数据,然后插入子表临时表
WHILE
@@FETCH_STATUS
=
0
BEGIN
INSERT
INTO
#detail
SELECT
od.OrderSeqNO,od.OrderDetailID, od.UnitPrice,od.Qty
FROM
OrderDetail od
WHERE
od.OrderSeqNO
=
@orderseqno
FETCH
NEXT
FROM
@temp_cursor
INTO
@orderseqno
,
@goodsname
END
--
关闭游标
CLOSE
@temp_cursor
DEALLOCATE
@temp_cursor
SELECT
*
FROM
#
temp
SELECT
*
FROM
#detail
--
删除临时表
DROP
TABLE
#
temp
DROP
TABLE
#detail
在回复中有人指点我应该添加一些执行计划,然后分析一下,很好的建议,本身先声明对于执行计划和分析目前不是很擅长,所以简单分析一下吧。分析一下
使用临时表保存主表查询结果,和不适用临时表的优劣吧。
使用临时表
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
--
不用游标的分页
--
先将分页的主表放在临时表中,然后用临时表和子表联合查询,来获取子表信息
--
既保证了分页的正确性,也包括了子表信息
CREATE
TABLE
#
order
(
number
BIGINT
,
orderseqno
VARCHAR
(
36
),
)
insert
into
#
order
SELECT
*
FROM
(
SELECT
ROW_NUMBER()
OVER
(
ORDER
BY
oi.CreateDate
DESC
)
AS
rownumber,oi.OrderSeqNO
FROM
OrderInfo oi
WHERE
oi.OrderSeqNO
LIKE
'
%2%
'
)
AS
o
WHERE
o.rownumber
BETWEEN
10
AND
20
SELECT
*
FROM
#
order
INNER
JOIN
OrderDetail od
ON
od.OrderSeqNO
=
#
order
.orderseqno
DROP
TABLE
#
order
不适用临时表
代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
--
ascrat老兄的提示,好办法啊
--
省去了游标,省去了临时表
--
(学习的)路漫漫其修远啊
SELECT
a.
*
,od.
*
FROM
(
SELECT
*
FROM
(
SELECT
ROW_NUMBER()
OVER
(
ORDER
BY
oi.CreateDate
DESC
)
AS
rownumber,oi.OrderSeqNO
FROM
OrderInfo oi
WHERE
oi.OrderSeqNO
LIKE
'
%2%
'
)
AS
o
WHERE
o.rownumber
BETWEEN
10
AND
20
) a
INNER
JOIN
OrderDetail od
ON
a.OrderSeqNO
=
od.OrderSeqNO
下面是这两种的执行计划,很容易看出来,他们之间的读取数据库方面是一样的,不一样的就是使用了临时表,后面要临时表和明细表进行连接,所以对临时表产生了逻辑读取的操作,肯定要比不适用临时表性能有优势。
代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
表
'
#order’。扫描计数 0,逻辑读取 11 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表
'
OrderInfo
'
。扫描计数 1,逻辑读取 8 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
(11 行受影响)
(1 行受影响)
(19 行受影响)
表
'
OrderDetail
'
。扫描计数 11,逻辑读取 41 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表
'
#
order
‘。扫描计数
1
,逻辑读取
1
次,物理读取
0
次,预读
0
次,lob 逻辑读取
0
次,lob 物理读取
0
次,lob 预读
0
次。
(
1
行受影响)
(
19
行受影响)
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->
表
'
OrderDetail
'
。扫描计数
11
,逻辑读取
41
次,物理读取
0
次,预读
0
次,lob 逻辑读取
0
次,lob 物理读取
0
次,lob 预读
0
次。
表
'
OrderInfo
'
。扫描计数
1
,逻辑读取
8
次,物理读取
0
次,预读
0
次,lob 逻辑读取
0
次,lob 物理读取
0
次,lob 预读
0
次。
(
1
行受影响)