查看: 7475|回复: 15

oracle数据库特种恢复技术(五)--redo篇

[复制链接]
论坛徽章:
5
2010新春纪念徽章
日期:2010-03-01 11:07:242012新春纪念徽章
日期:2012-01-04 11:54:26铁扇公主
日期:2012-02-21 15:03:13奥运会纪念徽章:皮划艇静水
日期:2012-09-17 16:05:02优秀写手
日期:2013-12-18 09:29:09
跳转到指定楼层
1#
发表于 2011-12-5 11:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 ubotutwin 于 2012-2-1 10:06 编辑

oracle数据库特种恢复技术(五)--redo
作者:谢浩

oracle数据库特种恢复技术(二)—块内篇链接:http://www.itpub.net/thread-1507766-1-1.html
oracle数据库特种恢复技术(三)—转换篇链接:http://www.itpub.net/thread-1507774-1-1.html
Oracle数据库特种恢复技术(四)—实验篇链接:http://www.itpub.net/thread-1510202-1-1.html
oracle数据库特种恢复技术(五)--redo篇链接:http://www.itpub.net/thread-1517926-1-1.html
Oracle数据库特种恢复技术(六)—undo篇链接:http://www.itpub.net/thread-1558146-1-1.html
Oracle 数据库特种恢复技术(七)-总结篇链接:http://www.itpub.net/thread-1558154-1-1.html




      继续上一篇的内容。

      本篇围绕redo日志挖掘展开,可以说是本系列中对数据库恢复最无足轻重的一篇。之所以这样说是因为,只有在数据库及其备份出现严重故障的特殊情况下才会用到本系列所描述的技术,而这种情况下,少量的数据完整性缺失已经是无足轻重的问题了。但本篇所分析的内容对数据变更轨迹的挖掘、数据库同步技术等都有很大意义。

1、对测试表分别进行insert和update操作,并分别记录scn:
SELECTDbms_Flashback.get_system_change_number() from dual;
insert into xh_tempvalues('s11','s21','s31',1,2,'s4',sysdate,sysdate,sysdate,'s5','s','d','f');
commit;
SELECTDbms_Flashback.get_system_change_number() from dual;

SELECT Dbms_Flashback.get_system_change_number()from dual;
update xh_temp a set a.object_name='test1'where a.object_name = 's2';
commit;
SELECTDbms_Flashback.get_system_change_number() from dual;

2、以scn base方式分别dump两个操作的在线redolog:
Alter system dump logfile '/u01/app/oracle/oradata/PHONEDB/onlinelog/o1_mf_3_6lf2hxow_.log'scn min 21184829 scn max 21184832;

alter system dump logfile'/u01/app/oracle/oradata/PHONEDB/onlinelog/o1_mf_3_6lf2hxow_.log' scn min21184178 scn max 21184181;

3、从dump的trace文件中分别获得两个操作的redo记录的rba,使用dd工具复制redolog文件相应位置的二进制代码:
ddif=/u01/app/oracle/oradata/PHONEDB/onlinelog/o1_mf_3_6lf2hxow_.logof=./update.dd count=10 skip=9269 bs=512

ddif=/u01/app/oracle/oradata/PHONEDB/onlinelog/o1_mf_3_6lf2hxow_.logof=./updateC2.dd count=10 skip=9971 bs=512

这里的bs选择512是根据oracle软件redo的block尺寸,redo文件的block size不同于数据文件,而是与os单次io的块大小像匹配的,在linux、aix、windows中默认一次io是512字节,hp ux中默认是1024字节。Linux系统可以通过fdisk命令查看os blocksize。这个block size会在redolog的第一个块的偏移20位置用4字节存储(来自Dissecting the Redo Logs)Oracle这样设计的目的是为了尽量保证redo写入的安全性,保证io异常时不会有“切块”的情况发生,因为真正保证数据库数据的并不是数据文件,而是重做日志。(但是如果物理存储设备带有缓存,还是不能避免会有部分数据丢失)

dd输出:
00000000h: 01 22 00 00 F8 44 01 00 FB 02 0000 10 80 38 9F ; .
00000010h: 90 03 00 00 0D 05 00 00 35 60 4201 02 00 06 C5 ; ?......5`B....?
00000020h: 00 00 00 00 61 02 C1 02 00 00 0100 02 00 00 00 ; ....a.?........
00000030h: 02 00 00 00 00 63 61 74 34 60 4201 00 00 75 63 ; .....cat4`B...uc
00000040h: 72 70 01 80 02 C1 20 02 C1 1A 2C00 08 03 C2 4C ; r
00000050h: 46 9D D2 2D 0B 02 01 00 03 00 0000 E6 66 C0 00 ; F澮-........鎓?
00000060h: 0F 60 42 01 00 00 01 00 02 02 73C4 16 00 18 00 ; .`B.......s?...
00000070h: 31 00 13 00 07 00 02 00 00 00 0000 01 00 0D 00 ; 1...............
00000080h: 01 00 AB 0C 01 01 00 00 00 00 0000 05 00 28 00 ; ..?..........(.
00000090h: 29 33 00 00 93 0D 80 00 77 13 3100 E6 66 C0 00 ; )3.
000000a0h: E3 66 C0 00 FA 12 02 01 01 00 0000 2C 01 08 00 ; 鉬??......,...
000000b0h: 00 00 13 01 07 00 00 00 00 00 0000 00 00 00 00 ; ................
000000c0h: 00 00 00 00 36 00 64 00 00 18 0000 00 6C 6F 63 ; ....6.d......loc
000000d0h: 41 47 45 4E 54 5F 53 54 41 54 5553 5F 4D 41 52 ; AGENT_STATUS_MAR
000000e0h: 4B 45 52 28 78 6F 0C 01 16 14 0306 C1 04 1E 37 ; KER(xo......?.7
000000f0h: 59 61 02 C1 41 47 45 4E 54 53 5F4D 41 52 4B 45 ; Ya.罙GENTS_MARKE
00000100h: 44 6F 63 61 30 69 6F 6E 05 02 1900 02 00 FF FF ; Doca0ion......
00000110h: 49 00 80 00 ED 5F 42 01 00 00 0000 02 00 FF FF ; I
00000120h: 04 00 20 00 28 00 15 00 29 33 0000 93 0D 80 00 ; .. .(..
。。。。。。。。。。。。。。。。。。。。。省略。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
其中重要信息如下:
前4个字节为redo标识。

从offset 4起占4字节的是该redoblock的rba:F8 44 01 00。

从offset 12起占1字节是该redoblock中第一个redo record的偏移地址:10(一个字节最多表示到255,因此如果一个redo block中被上一个redo block中的redo record占用超过255字节,则该redo block的剩余空间将不再被使用)。


4、根据上一步骤得到的offset,找到第一个redorecord:90 03 00 00 0D 05 00 00 …………..,其中前4字节90 03 00 00表示该redorecord的长度390,之后的0D是一个叫做VLD的变量,该变量直接决定着redo record header的长度,我一直没有找到该变量和redo record header长度之间的对应关系,但是通过分析得出,最重要的增删改操作(即op为11.*的操作)vld为0D,对应的redo record header长度为68字节,事务相关操作(即op为5.*的操作)vld为05,对应的redo record header长度为68字节。

5、由于该redo record中vld为0D,所以第一个改变向量的物理位置为redo record开始offset 68的位置:
00000054h: 0B 02 01 00 03 00 00 00 E6 66 C000 0F 60 42 01 ; ........鎓?.`B.
00000064h: 00 00 01 00 02 02 73 C4 16 00 1800 31 00 13 00 ; ......s?...1...
00000074h: 07 00 02 00 00 00 00 00 01 000D                ; ...........

改变向量中第1、2个字节是该操作的opcode,0B 02转换为10进制为11 2,表示单行插入操作。(op code代码详细信息后附)。

改变向量开始offset 24位置,记录了该改变向量中的记录长度列表:
0000006ch: 16 00 18 00 31 00 13 00 07 00 0200 00 00 00 00 ; ....1...........
0000007ch: 01 00 0D 00 01 00 AB 0C                         ; ......?
    该列表中,每个记录的长度占两个字节存储,第一个长度是指列表本身的长度,列表中的存放的长度数值,指的是对应记录的有效长度,在文件中存储的记录的实际长度要在有效长度的基础上向上增加到4的倍数,比如第1、2字节:16 00转换为10进制为22,所以该列表的长度就是24字节,最后两个字节为填充字节,没有实际意义。
    将其中列表转换为10进制,并按4字节补齐后为:
18 00 31 00 13 00 07 00 02 00 00 00 00 0001 00 0D 00 01 00
对应
24   52  20   8    4     0   0   4    16    4
长度列表之后就是记录的实际值:
00000084h: 01 01 00 00 00 00 00 00 05 00 2800 29 33 00 00 ; ..........(.)3..
00000094h: 93 0D 80 00 77 13 31 00 E6 66 C000 E3 66 C0 00 ; ?
000000a4h: FA 12 02 01 01 00 00 00 2C 01 0800 00 00 13 01 ; ?......,.......
000000b4h: 07 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 ; ................
000000c4h: 36 00 64 00 00 18 00 00 00 6C 6F63 41 47 45 4E ; 6.d......locAGEN
000000d4h: 54 5F 53 54 41 54 55 53 5F 4D 4152 4B 45 52 28 ; T_STATUS_MARKER(
000000e4h: 78 6F 0C 01 16 14 03 06 C1 04 1E37 59 61 02 C1 ; xo......?.7Ya.?
000000f4h: 41 47 45 4E 54 53 5F 4D 41 52 4B45 44 6F 63 61 ; AGENTS_MARKEDoca
00000104h: 30 69 6F 6E                                     ; 0ion

这部分中,前24字节对应dump文件中的ktb结构体,offset 24开始的52字节对应dump文件中的kdo结构体,kdo结构体中一个重要的变量就是offset20位置的solt变量,该变量记录了update操作对应的行号,该行号对应的是数据行在data block中的行号,也就是rowid中的行号,至此,已经在redolog中获得了update操作所对应的对象id、dba、行号三个信息,根据此三个信息已经可以计算出redo record操作的行的rowid了。

继续观察,kdo结构体后紧随的是操作的字段编号,占4个字节:01 00 40 04,这里由于前面信息长度列表里这段信息的长度是1,所以有效数据是01,其后的00 40 04为填充位,无意义。再往后保存的是具体操作的字段的值74 65 73 74 31 00 01 00。
SQL> select dump('test1',1016) fromdual;

DUMP('TEST1',1016)
--------------------------------------------------
Typ=96 Len=5 CharacterSet=ZHS16GBK:74,65,73,74,31
可以看到,和dump函数的输出相吻合,最后3个字节的00 01 00,还是填充位,无意义。
      这就是一个update操作最关键的修改数据块的改变向量的全部内容,此后在同一redo record中还有其他操作的改变向量,如op为5.1、5.2是对回滚段的相应修改,都属于事务操作的范畴。
      Insert操作与update操作的区别是没有“字段编号”这一部分信息(因为用不到),只有ktb、kdo、字段值这三个部分。
      Delete操作则只有ktb、kdo两个部分,直接按照kdo中的slot行号信息,加之前的object号,dba就能定位到要删除的行。

      至此,redolog中已经能够解出对数据的操作,只要根据不同的op code就能还原redo sql,在这之后又遇到了一个问题,就是如何界定redo log中哪些记录属于一个事务。对此我做了如下实验,在session a中做一个update操作不提交,然后在session b中再做一个update操作并提交,然后再返回session a中提交事务,这样session a中的事务对应的redo 记录就必然被session b中的事务所分割,这个目的是达到了,但是我始终没有找到session a的redo记录之间的联系,session a的事务的改变向量被分割到多个redo record中,没有任何线索能将其串联。为此,一度陷入僵局。

之后我转换了一种思路:这一部分分析的目的,是在恢复数据之后保证数据的准确性,也就是说,要在人工模拟oracle打开过程之后再模拟oracle的recovery database过程。那么,套用oracle本身的行为模式是良好的选择,即,先将redolog里所有对应start scn之后的redo record全部应用前滚,然后再根据data block上的状态flag进行回滚。也就是说oracle本身在redolog这个环节并不需要界定事务,事务的最终标识是在数据块上的相关锁的产生和清除来界定的。

至此redo部分已经可以进行简单的应用,下一步是要根据数据块上的事务标识,通过undo构造一致性块,进一步增加恢复的精确性。

附op code列表(来自网络):
格式:layer: opcode
       LAYER的含义:
               4 — Block Cleanout
               5 — Transaction Management
             10 — 索引操作
             11 — 行操作
              13 — 段[url=]管理[/url]
              14 — Extent 管理
              17 — 表空间管理
              18 — Block Image (Hot Backups)
              19 — Direct Loader
              20 — Compatibility segment
              22 — 本地管理表空间
              23 — Block Writes
              24 — DDL语句
Layer 1 : Transaction Control - KCOCOTCT     
   Opcode 1 : KTZFMT
   Opcode 2 : KTZRDH
   Opcode 3 : KTZARC
   Opcode 4 : KTZREP
Layer 2 : Transaction Read -  KCOCOTRD     
Layer 3 : Transaction Update -  KCOCOTUP     
Layer 4 : Transaction Block -  KCOCOTBK     [ktbcts.h]
         Opcode 1 : Block Cleanout
         Opcode 2 : Physical Cleanout
         Opcode 3 : Single Array Change
         Opcode 4 : Multiple Changes to an Array
         Opcode 5 : Format Block
Layer 5 : Transaction Undo -  KCOCOTUN     [ktucts.h]
         Opcode 1 : Undo block or undo segment header - KTURDB
         Opcode 2 : Update rollback segment header - KTURDH
         Opcode 3 : Rollout a transaction begin
         Opcode 4 : Commit transaction (transaction table update)
- no undo record
         Opcode 5 : Create rollback segment (format) - no undo record
         Opcode 6 : Rollback record index in an undo block - KTUIRB
         Opcode 7 : Begin transaction (transaction table update)
         Opcode 8 : Mark transaction as dead
         Opcode 9 : Undo routine to rollback the extend of a rollback segment
         Opcode 10 :Redo to perform the rollback of extend of rollback segment
                    to the segment header.
         Opcode 11 :Rollback DBA in transaction table entry - KTUBRB
         Opcode 12 :Change transaction state (in transaction table entry)
         Opcode 13 :Convert rollback segment format (V6 -> V7)
         Opcode 14 :Change extent allocation parameters in a rollback segment
         Opcode 15 :
         Opcode 16 :
         Opcode 17 :
         Opcode 18 :
         Opcode 19 : Transaction start audit log record
         Opcode 20 : Transaction continue audit log record     
         Opcode 24 : Kernel Transaction Undo Relog CHanGe - KTURLGU
Layer 6 : Control File -  KCOCODCF     [tbs.h]
Layer 10 : INDEX -  KCOCODIX     [kdi.h]
         Opcode 1 : load index block (Loader with direct mode)
         Opcode 2 : Insert leaf row
         Opcode 3 : Purge leaf row
         Opcode 4 : Mark leaf row deleted
         Opcode 5 : Restore leaf row (clear leaf delete flags)
         Opcode 6 : Lock index block
         Opcode 7 : Unlock index block
         Opcode 8 : Initialize new leaf block
         Opcode 9 : Apply Itl Redo
         Opcode 10 :Set leaf block next link
         Opcode 11 :Set leaf block previous link
         Opcode 12 :Init root block after split
         Opcode 13 :Make leaf block empty
         Opcode 14 :Restore block before image
         Opcode 15 :Branch block row insert
         Opcode 16 :Branch block row purge
         Opcode 17 :Initialize new branch block
         Opcode 18 :Update keydata in row
         Opcode 19 :Clear row’s split flag
         Opcode 20 :Set row’s split flag
         Opcode 21 :General undo above the cache (undo)
         Opcode 22 :Undo operation on leaf key above the cache (undo)
         Opcode 23 :Restore block to b-tree
         Opcode 24 :Shrink ITL (transaction entries)
         Opcode 25 :Format root block redo
         Opcode 26 :Undo of format root block (undo)
         Opcode 27 :Redo for undo of format root block
         Opcode 28 :Undo for migrating block
         Opcode 29 :Redo for migrating block
         Opcode 30 :IOT leaf block nonkey update
         Opcode 31 :Cirect load root redo
         Opcode 32 :Combine operation for insert and restore rows
Layer 11 : Row Access -  KCOCODRW     [kdocts.h]
         Opcode 1 : Interpret Undo Record (Undo)
         Opcode 2 : Insert Row Piece
         Opcode 3 : Drop Row Piece
         Opcode 4 : Lock Row Piece
         Opcode 5 : Update Row Piece
         Opcode 6 : Overwrite Row Piece
         Opcode 7 : Manipulate First Column (add or delete the 1rst column)
         Opcode 8 : Change Forwarding address
         Opcode 9 : Change the Cluster Key Index
         Opcode 10 :Set Key Links (change the forward & backward key links
                    on a cluster key)
         Opcode 11 :Quick Multi-Insert (ex: insert as select …)
         Opcode 12 :Quick Multi-Delete
         Opcode 13 :Toggle Block Header flags
Layer 12 : Cluster -  KCOCODCL     [?]
Layer 13 : Transaction Segment -  KCOCOTSG     [ktscts.h]
         Opcode 1 : Data segment format
         Opcode 2 : Merge
         Opcode 3 : Set link in block
         Opcode 4 : Not used
         Opcode 5 : New block (affects segment header)
         Opcode 6 : Format block (affects data block)
         Opcode 7 : Record link
         Opcode 8 : Undo free list (undo)
         Opcode 9 : Redo free list head (called as part of undo)
         Opcode 9 : Format free list block (freelist group)
         Opcode 11 :Format new blocks in free list
         Opcode 12 :free list clear
         Opcode 13 :free list restore (back) (undo of opcode 12)
Layer 14 : Transaction Extent -  KCOCOTEX     [kte.h]
         Opcode 1 : Add extent to segment
         Opcode 2 : Unlock Segment Header
         Opcode 3 : Extent DEaLlocation (DEL)
         Opcode 4 : Undo to Add extent operation (see opcode 1)
         Opcode 5 : Extent Incarnation number increment
         Opcode 6 : Lock segment Header
         Opcode 7 : Undo to rollback extent deallocation (see opcode 3)
         Opcode 8 : Apply Position Update (truncate)
         Opcode 9 : Link blocks to Freelist
         Opcode 10 :Unlink blocks from Freelist
         Opcode 11 :Undo to Apply Position Update (see opcode 8)
         Opcode 12 :Convert segment header to 6.2.x type
Layer 15 : Table Space -  KCOCOTTS     [ktt.h]
        Opcode 1 : Format deferred rollback segment header
        Opcode 2 : Add deferred rollback record
        Opcode 3 : Move to next block
        Opcode 4 : Point to next deferred rollback record
Layer 16 : Row Cache -  KCOCOQRC     
Layer 17 : Recovery (REDO) -  KCOCORCV     [kcv.h]
         Opcode 1 : End Hot Backup : This operation clears the hot backup
                    in-progress flags in the indicated list of files
         Opcode 2 : Enable Thread : This operation creates a redo record
                    signalling that a thread has been enabled
         Opcode 3 : Crash Recovery Marker
         Opcode 4 : Resizeable datafiles
         Opcode 5 : Tablespace ONline
         Opcode 6 : Tablespace OFFline
         Opcode 7 : Tablespace ReaD Write
         Opcode 8 : Tablespace ReaD Only
         Opcode 9 : ADDing datafiles to database
         Opcode 10 : Tablespace DRoP
         Opcode 11 : Tablespace PitR     
Layer 18 : Hot Backup Log Blocks -  KCOCOHLB     [kcb.h]
         Opcode 1 : Log block image
         Opcode 2 : Recovery testing
Layer 19 : Direct Loader Log Blocks - KCOCODLB     [kcbl.h]
         Opcode 1 : Direct block logging
         Opcode 2 : Invalidate range
         Opcode 3 : Direct block relogging
         Opcode 4 : Invalidate range relogging     
Layer 20 : Compatibility Segment operations - KCOCOKCK  [kck.h]
         Opcode 1 : Format compatibility segment -  KCKFCS
         Opcode 2 : Update compatibility segment - KCKUCS
Layer 21 : LOB segment operations - KCOCOLFS     [kdl2.h]
         Opcode 1 : Write data into ILOB data block - KDLOPWRI
Layer 22 : Tablespace bitmapped file operations -  KCOCOTBF [ktfb.h]
Opcode 1 : format space header - KTFBHFO
Opcode 2 : space header generic redo - KTFBHREDO
Opcode 3 : space header undo - KTFBHUNDO
Opcode 4 : space bitmap block format - KTFBBFO
Opcode 5 : bitmap block generic redo - KTFBBREDO
Layer 23 : write behind logging of blocks - KCOCOLWR [kcbb.h]
Opcode 1 : Dummy block written callback - KCBBLWR
Layer 24 : Logminer related (DDL or OBJV# redo) - KCOCOKRV [krv.h]
Opcode : common portion of the ddl - KRVDDL
Opcode : direct load redo - KRVDLR
Opcode : lob related info - KRVLOB
Opcode : misc info - KRVMISC
Opcode : user info - KRVUSER
         
      备注:该操作不包含undo vector, segment header的修改即使交易回滚,它也不会发生回滚。

论坛徽章:
3
技术图书徽章
日期:2014-06-20 16:30:312015年新春福章
日期:2015-03-04 14:53:162015年新春福章
日期:2015-03-06 11:58:39
2#
发表于 2011-12-5 11:33 | 只看该作者
支持一下!学习了!

使用道具 举报

回复
招聘 : 数据库管理员
论坛徽章:
83
IT宝贝
日期:2013-11-15 18:40:242015年新春福章
日期:2015-03-06 11:57:31美羊羊
日期:2015-03-04 14:48:58马上加薪
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11
3#
发表于 2011-12-5 18:34 | 只看该作者
真不错,排期将于本周四放置到itpub门户页面的红字头条中,期待lz的继续连载

使用道具 举报

回复
论坛徽章:
9
蛋疼蛋
日期:2011-10-18 11:00:17ITPUB十周年纪念徽章
日期:2011-11-01 16:25:51蜘蛛蛋
日期:2011-11-09 13:48:06迷宫蛋
日期:2011-11-24 10:38:342012新春纪念徽章
日期:2012-01-04 11:56:44蜘蛛蛋
日期:2013-07-12 21:52:36凯迪拉克
日期:2013-12-12 09:53:072014年新春福章
日期:2014-02-18 16:44:08马上有对象
日期:2014-02-18 16:44:08
4#
发表于 2011-12-5 18:38 | 只看该作者
哥 你太强了

使用道具 举报

回复
论坛徽章:
5
ITPUB9周年纪念徽章
日期:2010-10-08 09:28:51数据库板块每日发贴之星
日期:2011-07-22 01:01:02蜘蛛蛋
日期:2011-08-24 14:10:13ITPUB十周年纪念徽章
日期:2011-11-01 16:24:042012新春纪念徽章
日期:2012-01-04 11:54:26
5#
发表于 2011-12-5 19:02 | 只看该作者

使用道具 举报

回复
论坛徽章:
17
生肖徽章2007版:蛇
日期:2009-03-10 21:14:362014年世界杯参赛球队: 伊朗
日期:2014-06-13 11:29:242014年新春福章
日期:2014-02-22 15:22:32马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:242012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26ITPUB十周年纪念徽章
日期:2011-09-27 16:32:49双黄蛋
日期:2011-08-27 13:04:11
6#
发表于 2011-12-6 08:27 | 只看该作者
加油加油

使用道具 举报

回复
论坛徽章:
171
ITPUB社区OCM联盟徽章
日期:2013-07-30 11:25:46最佳人气徽章
日期:2013-03-19 17:13:45ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30ITPUB季度 技术新星
日期:2012-05-22 15:10:11BLOG每日发帖之星
日期:2012-02-15 16:43:07生肖徽章2007版:马
日期:2012-03-07 10:13:26蓝锆石
日期:2012-02-24 10:13:15萤石
日期:2012-02-24 10:13:15海蓝宝石
日期:2012-02-24 10:13:15紫水晶
日期:2012-03-01 21:28:36
7#
发表于 2011-12-6 09:18 | 只看该作者
有深度啊

使用道具 举报

回复
论坛徽章:
0
8#
发表于 2011-12-6 10:33
select bd_corp.unitcode from bd_corp where bd_corp.pk_corp = bd_calbody.pk_corp
and bd_corp.unitcode='0106251001'  这个语句查询出来有那些值啊?根据你第一次的查询结果应该是有空记录的吧。你update  一个列,这个列是否允许为空啊。如果不允许,你肯定更新要报错。还有你 update bd_calbody set bodycode=bd_corp.unitcode from bd_calbody  left join bd_corp on bd_corp.pk_corp = bd_calbody.pk_corp where  bd_corp.unitcode='0102110901' 这个你直接用的话,你确定语法正确?

论坛徽章:
0
9#
发表于 2011-12-6 10:33 | 只看该作者
select bd_corp.unitcode from bd_corp where bd_corp.pk_corp = bd_calbody.pk_corp
and bd_corp.unitcode='0106251001'  这个语句查询出来有那些值啊?根据你第一次的查询结果应该是有空记录的吧。你update  一个列,这个列是否允许为空啊。如果不允许,你肯定更新要报错。还有你 update bd_calbody set bodycode=bd_corp.unitcode from bd_calbody  left join bd_corp on bd_corp.pk_corp = bd_calbody.pk_corp where  bd_corp.unitcode='0102110901' 这个你直接用的话,你确定语法正确?

使用道具 举报

回复
论坛徽章:
0
10#
发表于 2011-12-6 10:33 | 只看该作者
select bd_corp.unitcode from bd_corp where bd_corp.pk_corp = bd_calbody.pk_corp
and bd_corp.unitcode='0106251001'  这个语句查询出来有那些值啊?根据你第一次的查询结果应该是有空记录的吧。你update  一个列,这个列是否允许为空啊。如果不允许,你肯定更新要报错。还有你 update bd_calbody set bodycode=bd_corp.unitcode from bd_calbody  left join bd_corp on bd_corp.pk_corp = bd_calbody.pk_corp where  bd_corp.unitcode='0102110901' 这个你直接用的话,你确定语法正确?

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表