Sql server 2000 采用Not In分頁,但主鍵是多個字段

bb_chen 2009-07-08 03:30:15
因現在根據其它系統中做一查詢系統。所以不能在數據庫上做任何修改(如存儲過程),所有SQL 語句全部放在C#中傳遞。

了解到分頁有種方法是用Not in ,對於主鍵為一個的可以這樣
SELECT TOP 10 * FROM COPMG as A WHERE MG001 NOT IN (SELECT TOP 20 MG001 FROM COPMG ORDER BY MG001) ORDER BY MG001
但是如果主鍵是多個字段呢?我像下面這樣寫,提示錯誤:
SELECT TOP 10 * FROM COPMG as A WHERE MG001,MG002,MG003 NOT IN (SELECT TOP 20 MG001,MG002,MG003 FROM COPMG ORDER BY MG001,MG002,MG003) ORDER BY MG001,MG002,MG003
...全文
729 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
半妖尐槑 2011-12-20
  • 打赏
  • 举报
回复
是啊,效率慢慢地哦...[Quote=引用 16 楼 wquanchao 的回复:]
引用 3 楼 htl258 的回复:
SQL code

SELECT TOP 10 * FROM COPMG as A WHERE ltrim(MG001)+ltrim(MG002)+ltrim(MG003) NOT IN (SELECT TOP 20 ltrim(MG001)+ltrim(MG002)+ltrim(MG003) FROM COPMG ORDER BY ltrim(MG00……
[/Quote]
wquanchao 2011-11-05
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 htl258 的回复:]
SQL code

SELECT TOP 10 * FROM COPMG as A WHERE ltrim(MG001)+ltrim(MG002)+ltrim(MG003) NOT IN (SELECT TOP 20 ltrim(MG001)+ltrim(MG002)+ltrim(MG003) FROM COPMG ORDER BY ltrim(MG001)+ltrim(MG002)+lt……
[/Quote]
不能用,效率上也太慢
feixianxxx 2009-07-08
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 zjybushiren88888 的回复:]
友情帮顶 学习了
[/Quote]
你是新来的。
haitao 2009-07-08
  • 打赏
  • 举报
回复
我的理解是:可以用 a left join b on a.f1=b.f1 and a.f2=b.f2 ... where b.f1 is not null
代替 in
而且可以解决in不支持多字段的弊端(既语法不支持:(f1,f2,...) in (select f1,f2,... from ...))
zjybushiren88888 2009-07-08
  • 打赏
  • 举报
回复
友情帮顶 学习了
ai_li7758521 2009-07-08
  • 打赏
  • 举报
回复
--==================================================================================
--取top M到N行
--==================================================================================


1.
select top m * from tablename where id not in (select top n id from tablename order by id asc/*|desc*/)

2.
select top m * into 临时表(或表变量) from tablename order by columnname -- 将top m笔插入到临时表
set rowcount n --只取n条结果
select * from 表变量 order by columnname desc

3.
select top n * from
(select top m * from tablename order by columnname) a
order by columnname desc


4.如果tablename里没有其他identity列,那么:
先生成一个序列,存储在一临时表中.
select identity(int) id0,* into #temp from tablename

取n到m条的语句为:
select * from #temp where id0 > =n and id0 <= m

如果你在执行select identity(int) id0,* into #temp from tablename这条语句的时候报错,那是因为你的DB中间的select into/bulkcopy属性没有打开要先执行:
exec sp_dboption 你的DB名字,'select into/bulkcopy',true


5.如果表里有identity属性,那么简单:
select * from tablename where identity_col between n and m

6.SQL2005开始.可以使用row_number() over()生成行号
;with cte as
(
select id0=row_number() over(order by id),* from tablename
)
select * from cte where id0 between n to m
ai_li7758521 2009-07-08
  • 打赏
  • 举报
回复
--=======================================================
--邹建
--=======================================================


-----------------------------------------------------------------------------------------------------
--TOP n 实现的通用分页存储过程(转自邹建)
CREATE PROC sp_PageView
@tbname sysname, --要分页显示的表名
@FieldKey nvarchar(1000), --用于定位记录的主键(惟一键)字段,可以是逗号分隔的多个字段
@PageCurrent int=1, --要显示的页码
@PageSize int=10, --每页的大小(记录数)
@FieldShow nvarchar(1000)='', --以逗号分隔的要显示的字段列表,如果不指定,则显示所有字段
@FieldOrder nvarchar(1000)='', --以逗号分隔的排序字段列表,可以指定在字段后面指定DESC/ASC
用于指定排序顺序
@Where nvarchar(1000)='', --查询条件
@PageCount int OUTPUT --总页数
AS
SET NOCOUNT ON
--检查对象是否有效
IF OBJECT_ID(@tbname) IS NULL
BEGIN
RAISERROR(N'对象"%s"不存在',1,16,@tbname)
RETURN
END
IF OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsTable')=0
AND OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsView')=0
AND OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsTableFunction')=0
BEGIN
RAISERROR(N'"%s"不是表、视图或者表值函数',1,16,@tbname)
RETURN
END

--分页字段检查
IF ISNULL(@FieldKey,N'')=''
BEGIN
RAISERROR(N'分页处理需要主键(或者惟一键)',1,16)
RETURN
END

--其他参数检查及规范
IF ISNULL(@PageCurrent,0)<1 SET @PageCurrent=1
IF ISNULL(@PageSize,0)<1 SET @PageSize=10
IF ISNULL(@FieldShow,N'')=N'' SET @FieldShow=N'*'
IF ISNULL(@FieldOrder,N'')=N''
SET @FieldOrder=N''
ELSE
SET @FieldOrder=N'ORDER BY '+LTRIM(@FieldOrder)
IF ISNULL(@Where,N'')=N''
SET @Where=N''
ELSE
SET @Where=N'WHERE ('+@Where+N')'

--如果@PageCount为NULL值,则计算总页数(这样设计可以只在第一次计算总页数,以后调用时,把总页数传回给存储过程,避免再次计算总页数,对于不想计算总页数的处理而言,可以给@PageCount赋值)
IF @PageCount IS NULL
BEGIN
DECLARE @sql nvarchar(4000)
SET @sql=N'SELECT @PageCount=COUNT(*)'
+N' FROM '+@tbname
+N' '+@Where
EXEC sp_executesql @sql,N'@PageCount int OUTPUT',@PageCount OUTPUT
SET @PageCount=(@PageCount+@PageSize-1)/@PageSize
END

--计算分页显示的TOPN值
DECLARE @TopN varchar(20),@TopN1 varchar(20)
SELECT @TopN=@PageSize,
@TopN1=(@PageCurrent-1)*@PageSize

--第一页直接显示
IF @PageCurrent=1
EXEC(N'SELECT TOP '+@TopN
+N' '+@FieldShow
+N' FROM '+@tbname
+N' '+@Where
+N' '+@FieldOrder)
ELSE
BEGIN
--处理别名
IF @FieldShow=N'*'
SET @FieldShow=N'a.*'

--生成主键(惟一键)处理条件
DECLARE @Where1 nvarchar(4000),@Where2 nvarchar(4000),
@s nvarchar(1000),@Field sysname
SELECT @Where1=N'',@Where2=N'',@s=@FieldKey
WHILE CHARINDEX(N',',@s)>0
SELECT @Field=LEFT(@s,CHARINDEX(N',',@s)-1),
@s=STUFF(@s,1,CHARINDEX(N',',@s),N''),
@Where1=@Where1+N' AND a.'+@Field+N'=b.'+@Field,
@Where2=@Where2+N' AND b.'+@Field+N' IS NULL',
@Where=REPLACE(@Where,@Field,N'a.'+@Field),
@FieldOrder=REPLACE(@FieldOrder,@Field,N'a.'+@Field),
@FieldShow=REPLACE(@FieldShow,@Field,N'a.'+@Field)
SELECT @Where=REPLACE(@Where,@s,N'a.'+@s),
@FieldOrder=REPLACE(@FieldOrder,@s,N'a.'+@s),
@FieldShow=REPLACE(@FieldShow,@s,N'a.'+@s),
@Where1=STUFF(@Where1+N' AND a.'+@s+N'=b.'+@s,1,5,N''),
@Where2=CASE
WHEN @Where='' THEN N'WHERE ('
ELSE @Where+N' AND ('
END+N'b.'+@s+N' IS NULL'+@Where2+N')'

--执行查询
EXEC(N'SELECT TOP '+@TopN
+N' '+@FieldShow
+N' FROM '+@tbname
+N' a LEFT JOIN(SELECT TOP '+@TopN1
+N' '+@FieldKey
+N' FROM '+@tbname
+N' a '+@Where
+N' '+@FieldOrder
+N')b ON '+@Where1
+N' '+@Where2
+N' '+@FieldOrder)
END
ai_li7758521 2009-07-08
  • 打赏
  • 举报
回复
--===========================================================
--高效分页存储过程,仅适用于Sql2005
--===========================================================
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
-- =============================================
-- Description: <高效分页存储过程,仅适用于Sql2005>
-- Notes: <排序字段强烈建议建索引>
-- Page2005 'dyj_vclient','client_id,last_dt','client_id','last_dt','desc','',20,1,0
-- =============================================
ALTER Procedure [dbo].[Page2005]
@TableName varchar(50), --表名
@Fields varchar(5000) = '*', --字段名(全部字段为*)
@PrimaryKey varchar(20), --主键
@OrderField varchar(5000), --排序字段(必须!支持多字段)
@Orderby varchar(8)='desc', --排序方式(desc:倒序,asc:顺序)
@sqlWhere varchar(5000) = Null, --条件语句(不用加where)
@pageSize int, --每页多少条记录
@pageIndex int = 1 , --指定当前为第几页
@TotalPage int output --返回总页数
as
begin
Begin Tran --开始事务
Declare @sql nvarchar(4000);
Declare @totalRecord int;
if isnull(@PrimaryKey,'')=''
set @PrimaryKey='*'
--计算总记录数

if (@SqlWhere='' or @sqlWhere=NULL)
set @sql = 'select @totalRecord = count('+ @PrimaryKey +') from ' + @TableName
else
set @sql = 'select @totalRecord = count('+ @PrimaryKey +') from ' + @TableName + ' where ' + @sqlWhere
EXEC sp_executesql @sql,N'@totalRecord int OUTPUT',@totalRecord OUTPUT--计算总记录数

--计算总页数
select @TotalPage=CEILING((@totalRecord+0.0)/@PageSize)
if (@SqlWhere='' or @sqlWhere=NULL)
set @sql = 'Select * FROM (select ROW_NUMBER() Over(order by ' + @OrderField + ' '+ @Orderby +') as rowId,' + @Fields + ' from ' + @TableName
else
set @sql = 'Select * FROM (select ROW_NUMBER() Over(order by ' + @OrderField + ' '+ @Orderby +') as rowId,' + @Fields + ' from ' + @TableName + ' where ' + @SqlWhere


--处理页数超出范围情况
if @PageIndex <=0
Set @pageIndex = 1

if @pageIndex>@TotalPage
Set @pageIndex = @TotalPage
--处理开始点和结束点
Declare @StartRecord int
Declare @EndRecord int

set @StartRecord = (@pageIndex-1)*@PageSize + 1
set @EndRecord = @StartRecord + @pageSize - 1
--继续合成sql语句
set @Sql = @Sql + ') as ' + @TableName + ' where rowId between ' + Convert(varchar(50),@StartRecord) + ' and ' + Convert(varchar(50),@EndRecord)

Exec(@Sql)
---------------------------------------------------
If @@Error <> 0
Begin
RollBack Tran
Return -1
End
Else
Begin
Commit Tran
Return @totalRecord ---返回记录总数
End
end
Andy__Huang 2009-07-08
  • 打赏
  • 举报
回复
这是一个完整的分页存储过程:


CREATE PROC proc_pageview
@tbname sysname, --要分页显示的表名
@FieldKey nvarchar(1000), --用于定位记录的主键(惟一键)字段,可以是逗号分隔的多个字段
@PageCurrent int=1, --要显示的页码
@PageSize int=10, --每页的大小(记录数)
@FieldShow nvarchar(1000)='', --以逗号分隔的要显示的字段列表,如果不指定,则显示所有字段
@FieldOrder nvarchar(1000)='', --以逗号分隔的排序字段列表,可以指定在字段后面指定DESC/ASC
@Where varchar(1000)='', --查询条件
@RecordCount int OUTPUT --总页数
AS
SET NOCOUNT ON
--检查对象是否有效
IF OBJECT_ID(@tbname) IS NULL
BEGIN
RAISERROR(N'对象"%s"不存在',1,16,@tbname)
RETURN
END
IF OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsTable')=0
AND OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsView')=0
AND OBJECTPROPERTY(OBJECT_ID(@tbname),N'IsTableFunction')=0
BEGIN
RAISERROR(N'"%s"不是表、视图或者表值函数',1,16,@tbname)
RETURN
END

--分页字段检查
IF ISNULL(@FieldKey,N'')=''
BEGIN
RAISERROR(N'分页处理需要主键(或者惟一键)',1,16)
RETURN
END

--其他参数检查及规范
IF ISNULL(@PageCurrent,0)<1 SET @PageCurrent=1
IF ISNULL(@PageSize,0)<1 SET @PageSize=10
IF ISNULL(@FieldShow,N'')=N'' SET @FieldShow=N'*'
IF ISNULL(@FieldOrder,N'')=N''
SET @FieldOrder=N''
ELSE
SET @FieldOrder=N'ORDER BY '+LTRIM(@FieldOrder)
IF ISNULL(@Where,N'')=N''
SET @Where=N''
ELSE
SET @Where=N'WHERE ('+@Where+N')'

--如果@PageCount为NULL值,则计算总页数(这样设计可以只在第一次计算总页数,以后调用时,把总页数传回给存储过程,避免再次计算总页数,对于不想计算总页数的处理而言,可以给@PageCount赋值)
IF @RecordCount IS NULL
BEGIN
DECLARE @sql nvarchar(4000)
SET @sql=N'SELECT @RecordCount=COUNT(*)'
+N' FROM '+@tbname
+N' '+@Where
EXEC sp_executesql @sql,N'@RecordCount int OUTPUT',@RecordCount OUTPUT
END

--计算分页显示的TOPN值
DECLARE @TopN varchar(20),@TopN1 varchar(20)
SELECT @TopN=@PageSize,
@TopN1=(@PageCurrent-1)*@PageSize

--第一页直接显示
IF @PageCurrent=1
EXEC(N'SELECT TOP '+@TopN
+N' '+@FieldShow
+N' FROM '+@tbname
+N' '+@Where
+N' '+@FieldOrder)
ELSE
BEGIN
--处理别名
IF @FieldShow=N'*'
SET @FieldShow=N'a.*'

--生成主键(惟一键)处理条件
DECLARE @Where1 nvarchar(4000),@Where2 nvarchar(4000),
@s nvarchar(1000),@Field sysname
SELECT @Where1=N'',@Where2=N'',@s=@FieldKey
WHILE CHARINDEX(N',',@s)>0
SELECT @Field=LEFT(@s,CHARINDEX(N',',@s)-1),
@s=STUFF(@s,1,CHARINDEX(N',',@s),N''),
@Where1=@Where1+N' AND a.'+@Field+N'=b.'+@Field,
@Where2=@Where2+N' AND b.'+@Field+N' IS NULL',
@Where=REPLACE(@Where,@Field,N'a.'+@Field),
@FieldOrder=REPLACE(@FieldOrder,@Field,N'a.'+@Field),
@FieldShow=REPLACE(@FieldShow,@Field,N'a.'+@Field)
SELECT @Where=REPLACE(@Where,@s,N'a.'+@s),
@FieldOrder=REPLACE(@FieldOrder,@s,N'a.'+@s),
@FieldShow=REPLACE(@FieldShow,@s,N'a.'+@s),
@Where1=STUFF(@Where1+N' AND a.'+@s+N'=b.'+@s,1,5,N''),
@Where2=CASE
WHEN @Where='' THEN N'WHERE ('
ELSE @Where+N' AND ('
END+N'b.'+@s+N' IS NULL'+@Where2+N')'
--执行查询
EXEC(N'SELECT TOP '+@TopN
+N' '+@FieldShow
+N' FROM '+@tbname
+N' a LEFT JOIN(SELECT TOP '+@TopN1
+N' '+@FieldKey
+N' FROM '+@tbname
+N' a '+@Where
+N' '+@FieldOrder
+N')b ON '+@Where1
+N' '+@Where2
+N' '+@FieldOrder)
END

GO
bb_chen 2009-07-08
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 fredrickhu 的回复:]
SQL codeselecttop10 b.*from (selecttop20 主键字段,排序字段from 表名orderby 排序字段desc) a,表名 bwhere b.主键字段= a.主键字段orderby a.排序字段
[/Quote]
b表是指那個表?
--小F-- 2009-07-08
  • 打赏
  • 举报
回复
select top 10 b.* from (select top 20 主键字段,排序字段 
from 表名 order by 排序字段 desc) a,表名 b
where b.主键字段 = a.主键字段 order by a.排序字段
--小F-- 2009-07-08
  • 打赏
  • 举报
回复
--这样不行吗?
select top 10 b.* from (select top 20 主键字段,排序字段 from 表名 order by 排序字段 desc) a,表名 b where b.主键字段 = a.主键字段 order by a.排序字段
hery2002 2009-07-08
  • 打赏
  • 举报
回复
是否可以用NOT EXISTS替代?
htl258_Tony 2009-07-08
  • 打赏
  • 举报
回复
关于分页处理,可参考邹老大的BLOG:
http://blog.csdn.net/zjcxc/category/125592.aspx
htl258_Tony 2009-07-08
  • 打赏
  • 举报
回复
SELECT TOP 10 * FROM COPMG as A WHERE ltrim(MG001)+ltrim(MG002)+ltrim(MG003) NOT IN (SELECT  TOP 20  ltrim(MG001)+ltrim(MG002)+ltrim(MG003) FROM COPMG ORDER BY ltrim(MG001)+ltrim(MG002)+ltrim(MG003)) ORDER BY ltrim(MG001)+ltrim(MG002)+ltrim(MG003)
未测..
bb_chen 2009-07-08
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 pt1314917 的回复:]
这样语法是错误的。
最好另外加一个主键字段。。。
[/Quote]

不能改數據庫
pt1314917 2009-07-08
  • 打赏
  • 举报
回复
这样语法是错误的。
最好另外加一个主键字段。。。

34,594

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧