不帅 发表于 2015-1-16 22:36:41

MYSQL编程:小议奴才表INT自增主键拔出纪录的办法

也许最好的策略是以不变应万变:给客户他们所需要的,不多也不少。如果MySQL学习教程适合他们,他们就不应该买别的工具。事实上,云计算产业一直推崇自助服务,但提供这些服务的公司已经开始认识到解决方案提供商推销他们商品的价值。拔出奴才表最多见的也许就是用在进销存、MRP、ERP内里,好比一张发卖定单,定单Order(ID,OrderDate),定单明细OrderDetail(OrderID,ProductID,Num,Price)这个也许就是最复杂的奴才表了,两个表经由过程ID与OrderID创建联系关系,这里主键ID是自增的INT范例,OrderID是表OrderDetail的外键。固然,键的选择办法良多,如今我们选择的是在sql内里最复杂的办法。关于如许的表布局,我们最多见的成绩就是保留的时分如何处置键值的成绩,由于两个表联系关系十分的严密,我们举行保留的时分必要把它们放在一个事件内里,这时候成绩就会呈现,Order表中的ID是主动增加型的字段。如今必要我们录进一张定单,包含在Order表中拔出一笔记录和在OrderDetail表中拔出多少笔记录。由于Order表中的ID是主动增加型的字段,那末我们在纪录正式拔出到数据库之前没法事前得知它的取值,只要在更新后才干晓得数据库为它分派的是甚么值,然后再用这个ID作为OrderDetail表的OrderID的值,最初更新OderDetail表。可是,为了确保数据的分歧性,Order与OrderDetail在更新时必需在事件回护下同时举行,即确保两表同时更行乐成,这个就会有点困扰。

办理这类成绩罕见的次要有两类办法:

一种是微软在网上书店里利用的办法,利用了四个存储历程。改装一下,使之切合如今的例子

--存储历程一

CREATEPROCEDUREInsertOrder
@IdINT=NULLOUTPUT,
@OrderDateDATETIME=NULL,
@ProductIDListNVARCHAR(4000)=NULL,
@NumListNVARCHAR(4000)=NULL,
@PriceListNVARCHAR(4000)=NULL
AS
SETNOCOUNTON
SETXACT_ABORTON
BEGINTRANSACTION
--拔出主表
INSERTOrders(OrderDate)select@OrderDate
SELECT@Id=@@IDENTITY
--拔出子表
IF@ProductIDListISNOTNULL
EXECUTEInsertOrderDetailsByList@Id,@ProductIdList,@numList,@PriceList
COMMITTRANSACTION
RETURN0
--存储历程二
CREATEPROCEDUREInsertOrderDetailsByList
@IdINT,
@ProductIDListNVARCHAR(4000)=NULL,
@NumListNVARCHAR(4000)=NULL,
@PriceListNVARCHAR(4000)=NULL
AS
SETNOCOUNTON
DECLARE@LengthINT
DECLARE@FirstProductIdWordNVARCHAR(4000)
DECLARE@FirstNumWordNVARCHAR(4000)
DECLARE@FirstPriceWordNVARCHAR(4000)
DECLARE@ProductIdINT
DECLARE@NumINT
DECLARE@PriceMONEY
SELECT@Length=DATALENGTH(@ProductIDList)
WHILE@Length>0
BEGIN
EXECUTE@Length=PopFirstWord@@ProductIDListOUTPUT,@FirstProductIdWordOUTPUT
EXECUTEPopFirstWord@NumListOUTPUT,@FirstNumWordOUTPUT
EXECUTEPopFirstWord@PriceListOUTPUT,@FirstPriceWordOUTPUT
IF@Length>0
BEGIN
SELECT@ProductId=CONVERT(INT,@FirstProductIdWord)
SELECT@Num=CONVERT(INT,@FirstNumWord)
SELECT@Price=CONVERT(MONEY,@FirstPriceWord)
EXECUTEInsertOrderDetail@Id,@ProductId,@Price,@Num
END
END
--存储历程三
CREATEPROCEDUREPopFirstWord
@SourceStringNVARCHAR(4000)=NULLOUTPUT,
@FirstWordNVARCHAR(4000)=NULLOUTPUT
AS
SETNOCOUNTON
DECLARE@OldwordNVARCHAR(4000)
DECLARE@LengthINT
DECLARE@CommaLocationINT
SELECT@Oldword=@SourceString
IFNOT@OldwordISNULL
BEGIN
SELECT@CommaLocation=CHARINDEX(,,@Oldword)
SELECT@Length=DATALENGTH(@Oldword)
IF@CommaLocation=0
BEGIN
SELECT@FirstWord=@Oldword
SELECT@SourceString=NULL
RETURN@Length
END
SELECT@FirstWord=SUBSTRING(@Oldword,1,@CommaLocation-1)
SELECT@SourceString=SUBSTRING(@Oldword,@CommaLocation+1,@Length-@CommaLocation)
RETURN@Length-@CommaLocation
END
RETURN0
------------------------------------------------
--存储历程四
CREATEPROCEDUREInsertOrderDetail
@OrderIdINT=NULL,
@ProductIdINT=NULL,
@PriceMONEY=NULL,
@NumINT=NULL
AS
SETNOCOUNTON
INSERTOrderDetail(OrderId,ProductId,Price,Num)
SELECT@OrderId,@ProductId,@Price,@Num
RETURN0
拔出时,传进的子表数据都是长度为4000的NVARCHAR范例,各个字段利用“,”支解,然后挪用PopFirstWord分拆后分离挪用InsertOrderDetail举行保留,由于在InsertOrder中举行了事件处置,数据的平安性也对照有保证,几个存储历程计划的精致新颖,很成心思,可是子表的几个数据巨细不克不及凌驾4000字符,生怕不年夜保险。
第二种办法是我对照经常使用的,为了便利,就不必存储历程了,这个例子用的是VB.NET。
‘处置数据的类
PublicclassDbTools
privateConst_IDENTITY_SQLAsString="SELECT@@IDENTITYASID"
privateConst_ID_FOR_REPLACEAsString="_ID_FOR_REPLACE"
‘对奴才表拔出纪录
PublicFunctionInsFatherSonRec(ByValmain_sqlAsString,ByValParamArrayarParam()AsString)AsInteger
DimconnAsNewSqlConnection(StrConn)
DimIDASINTEGER
conn.Open()
DimtransAsSqlTransaction=conn.BeginTransaction
Try
主纪录
myDBTools.SqlData.ExecuteNonQuery(trans,CommandType.Text,main_sql)
前往新增ID号
ID=myDBTools.SqlData.ExecuteScalar(trans,CommandType.Text,_IDENTITY_SQL)
从纪录
IfNotarParamIsNothingThen
ForEachsqlInarParam
将刚取得的ID号代进
sql=sql.Replace(_ID_FOR_REPLACE,ID)
myDBTools.SqlData.ExecuteNonQuery(trans,CommandType.Text,sql)
Next
EndIf
trans.Commit()
CatcheAsException
trans.Rollback()
Finally
conn.Close()
EndTry
ReturnID
EndFunction
Endclass
下面这段代码里有myDBTools,是对罕见的数据库操纵封装后的类,这个类对数据库举行间接的操纵,有履历的.NET数据库程序员基础上城市有,一些出名的例子程序一样平常也都供应。
下面的是通用部分,上面是对详细票据的操纵
PublidclassOrder
Public_OrderDateasdate‘主表纪录
PublicChildDtasdatatable‘子表纪录,布局与OrderDetail分歧
PublicfunctionSave()asinteger
Dimstrasstring
Dimiasinteger
DimarParam()AsString
Dimstrasstring=”insertintoOrder(OrderDate)values(‘”&_OrderDate&“’)”
IfnotChilddtisnothingthen
arParam=NewString(ChildDT.Rows.Count-1){}
fori=0toChilddt.rows.count-1
arparam(i)=”insertintoOrderDetail(OrderID,ProductID,Num,Price)Values(_ID_FOR_REPLACE,”&drow(“ProductID)&“,”&drow(“Num”)&“,”drow(“price”)&“)”
nexti
Endif
Return(newdbtools).InsFatherSonRec(str,arparam)
Endclass
<P>
下面的两个例子为了便利注释,往失落了一些查验考证历程,有乐趣的伴侣能够参照网上书店的例子研讨第一种办法,大概依据本人索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存。如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录。

不帅 发表于 2015-1-19 18:31:21

where子句的作用是在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,条件中不能包含聚组函数,使用where条件显示特定的行。

活着的死人 发表于 2015-1-26 22:23:11

从底层原理到表层引用,书籍多的很。个人认为没有什么那本书好?这样的说法。主要看和个人的学习方法是否适合。

老尸 发表于 2015-2-4 21:04:23

但换公司用MSSQL2K感觉自己好像根本就不了解MSSQL。什么DTS触发器以前根本没用过。

小女巫 发表于 2015-2-10 10:51:11

发几份SQL课件,以飨阅者

谁可相欹 发表于 2015-3-10 13:44:51

学习SQL语言的话如果要学会去做网站就不是很难!但是要做数据库管理的话就有难度了!

简单生活 发表于 2015-3-17 08:10:02

作了些试验,发现使用CLR的存储过程或函数在达到一定的阀值的时候,系统性能会呈指数级下滑!这是非常危险的!只使用几个可能没有问题,当一旦大规模使用会造成严重的系统性能问题!

山那边是海 发表于 2015-3-24 03:44:00

如果是将来做数据库的开发设计,就应该详细学习T-SQL的各种细节,包括T-SQL的程序设计、存储过程、触发器以及具体使用某个开发语言来访问数据库。
页: [1]
查看完整版本: MYSQL编程:小议奴才表INT自增主键拔出纪录的办法