sql复杂排序(200分)

  • 主题发起人 主题发起人 dyc
  • 开始时间 开始时间
D

dyc

Unregistered / Unconfirmed
GUEST, unregistred user!
有一表单是本公司的进货统计,在delphi中其排序令我头痛
望众兄弟助我,表单如下:
code(国标号) name(规格)
GB5781-86 螺栓M10X20(直径x长度)
GB5781-86 螺栓M10X30(直径x长度)
GB5781-86 螺栓M5X20(直径x长度)
GB5782-86 螺栓M10X20(直径x长度)
GB75-86 螺栓M30X20(直径x长度)
GB938-86 螺栓M8X20(直径x长度)
GB5784-86 螺栓M25X20(直径x长度)
GB5781-86 螺栓M36X20(直径x长度)
................. .........................................(共有纪录数千条)

排序要求:
1.首先根据code排序,要求国标号小的在前.
问题出现: sql排序结果是:5781,5782, ...... ,75,938,...
而要求是:75,938,5781,5782,.............
2.其次根据name排序,要求相同国标号的螺栓直径小的在前,
螺栓直径相同的长度小的在前,(即M8应排在M10前....)。
3.结果输出报表.

这个问题困惑了我很久,以前在foxpro中到有办法,但在delphi中
却没有找到好的解决方法,但肯定有好的办法,“难道戴妃还不如
狐狸吗?”

 
不知道你用的是什么数据库,这个数据库SQL中是否支持子串及类型转换。
不过可以有一个变通的办法。即增加3个字段用于排序。
 
localsql支持的标准sql用法太少了,如果你用的是paradox,好象只能用计算字段的
方法解决。将纯数字的部分提出,转为整型,可以排序,
 
使用 tQUERY 做查询, 主要是使用 SQL 里的符号 DESC(升序排列)
SQL 写法如下
按国标代码升序排序
select code,name from table1
order by code desc
按名称升序排序
select code ,name from table1
order by name desc

还可以这样写
select code,name from table1
order by name desc,name desc
 
王大虾:他的问题好象不在升降序上。
 
肯定要进行字符串的抽取,这不是简单的排序问题。
王大侠总是想大事化小,小事化了,没事最好。^-^
 
动态增加两个字段作为排序的主键。
两个字段的内容从前面两个字段中取得,
程序退出时再将这两个临时字段删除即可。
具体的编程应该没什么问题吧?
当然如果能够直接创建新字段而且不是临时的那是最好。
 
我觉得数据库中表结构不合理。至少规格不应当就这样用一个字段来表示。
如果程序还要增加功能的话,趁早还是把表的定义改了的好。
 
???
在我按下POST 按钮的时候,又看了一眼题目,就知道我答错了,而且
提问者的问题简单用SQL无法处理
所以没有再说
但绝不是想 "想大事化小,小事化了,没事最好。"
俺不答没有把握的问题
 
还是看你用的是什么数据库,若用的是SQL SEVER,可如下所示:
select *,convert(smallint,substring(code,3,patindex('%-%',code)-3))
as tt from yourtable order by tt
从而得到按国标号排序的结果集,其它类似。
若你用的是其它数据库SEVER,则你应查看与本例相关的函数以了解其用法。
若你用的是LOCAL SQL,对不起,请使用计算字段,顺便说一名,光计算字段一项,
就已经远非FOXPRO所能及的了。
最后,你应很仔细地检查你的数据库的各表的组成,优良的数据库结构设计可给你
的编程带来良好的编程体验。

TO 王寒松:
大侠,说笑一句而已,你昨天刚帮我解决一个问题,我今天准备给你100分呢。
我知道你水平高,故十分强烈地希望你能帮我解决下面的问题:
<a href="http://www.gislab.ecnu.edu.cn/delphibbs/DispQ.asp?LID=114265">我如何让我的DLL中的FORM最小化时,整个应用程序最小化<a>
<a href="http://www.gislab.ecnu.edu.cn/delphibbs/DispQ.asp?LID=113738">关于OLE与WORD的嵌入问题<a>
 
是dbf文件,用local sql;
表单结构已经存在,我无法修改:-(

to yanghaijun: 如何计算字段,如何抽取字符串,
请知无不言,言无不尽;
to 3h: 本人愚钝,详细一点好吗?
 
假设新的计算字段为a(integer),则table1中的CalcFields应加入如下语句

procedure TForm1.Table1CalcFields(DataSet: TDataSet);
begin
Table1a.Value:=StrToInt(copy(Table1CODE.AsString,3,pos('-',Table1CODE.AsString)-3));
end;
可得到值为5781,75...的一整型字段,根据你的问题,共应有三个计算字段。
 
to menxin:
本人对delphi中的数据库设计不熟悉,
能否请你较详细的讲一下如何激活
TForm1.Table1CalcFields(DataSet: TDataSet)
以及后续步骤的处理,
最好有code,
拜托!
 

你的表格的这两个字段定义的时候就应该有所注意:
1.code这个字段既然都是国标号,没有必要在国标号前面加上"GB"
至于给用户看的界面怎么显示,你可以用程序来处理,也很简单,比如用display
format 属性
2.第二个字段应该分开
名字 规格
如果只有螺栓一种,名字可以省略了

如果工作量不大,建议你更改结构,一劳永逸,并且符合规范

btw:
When the AutoCalcFields property is True, OnCalcFields is triggered when:

1.A dataset is opened.
2.A dataset is put into dsEdit state.
3.Focus moves from one visual control to another, or from one column to
another is a data-aware grid control and modifications were made to
the record.
4.A record is retrieved from a database.

 
procedure TForm1.FormShow(Sender: TObject);
var CurrDir,str1,str2:String;
SQL:Tquery;
begin
sql:=TQuery.Create(Application);
GetDir(0,CurrDir);
Query1.DatabaseName:=CurrDir;
//建立或清空临时表
if FileExists(CurrDir+'/temp.dbf') then sql.sql.text:='delete from "temp.dbf"' else sql.sql.Text:='create table "temp.dbf" (code char(10),name char(20),ss char(10))';
sql.ExecSQL;
//查询数据并生成查询字段插入到临时表中
query1.sql.text:='select * from "yourdbf.dbf"';
Query1.open;
Query1.DisableControls;
while not Query1.Eof do begin
str1:=Query1.fieldbyname('code').AsString;
str2:=Query1.fieldbyname('name').AsString;
sql.sql.Text:='insert into "temp.dbf" values("'+str1+'","'+str2+'","'+formatfloat('0000',strtoint(copy(str1,3,pos('-',str1)-3)))+formatfloat('00',strtoint(copy(str2,6,pos('X',str2)-6)))+formatfloat('00',strtoint(copy(str2,pos('X',str2)+1,length(str2)-pos('X',str2)+1)))+'")';
sql.ExecSQL;
Query1.Next;
end;
Query1.close;
//排序查询
query1.sql.Text:='select code,name,ss from "temp.dbf" order by ss';
Query1.Open;
sql.free;
//打印query1的数据内容
end;
//你如不能改库的结构,只能加临时表,计算字段方法不好使,我给你寄去一个例子

 
>to menxin: 本人对delphi中的数据库设计不熟悉,能否请你较详细的讲一下如何激
>活TForm1.Table1CalcFields(DataSet: TDataSet)
生成计算字段后,将table.AutoCalcFields 设为true,自然会触发该事件的!
 
他的问题是排序,计算字段生成后,不能用于排序,这两个事件相干扰
 
喂dyc,我帮你解决了,为什么没有应,邮件收到了吗
 
to lss:
老兄不要着急,我正在硝化你的代码,再次请教下面代码的意义:
在我的机子上无法通过:
sql.sql.Text:='insert into "temp.dbf" values("'+str1+'","'+str2+'","'+formatfloat('0000',strtoint(copy(str1,3,pos('-',str1)-3)))+formatfloat('00',strtoint(copy(str2,6,pos('X',str2)-6)))+formatfloat('00',strtoint(copy(str2,pos('X',str2)+1,length(str2)-pos('X',str2)+1)))+'")';
不要嫌麻烦,成功了200大洋给你
 
你没有收到我给你的例子吗,它是可以以执行的一个完整的例子文件,包括
一个工程文件和一个form,另有一个包含你的数据的一个dbf库,程序配合该
库使用,程序本身没有问题,可能是你使用的数据库和我的不太一样,具体是
什么地方通不过,能说说吗

我这一行的含义是,向临时库中插入记录,其中有两个字段是原数据库字段,
其值分别在str1和str2中,第三个字段为排序字段,是根据你排序的要求按顺
序将前两个字段值提取出来,不足位数补0,最后用order by 排序,这种方法
比较笨,但你不能改原数据库结构,也就只能这样了


 

Similar threads

回复
0
查看
1K
不得闲
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
D
回复
0
查看
877
DelphiTeacher的专栏
D
D
回复
0
查看
845
DelphiTeacher的专栏
D
后退
顶部