2009年5月31日

利用GOOGLE系列工具建立安全无障碍的(群)博客

首先介绍一下https安全网络。通常网络上的内容,即可http://打头的网页,是内容是明码传输的,路由器等网络设备可以拦截分析,GFW的一大重要工作即在于此。

而https是加密传输的,路由器不知道传输的具体内容,象银行支付等就是基于此协议的。

更多介绍见:http://zh.wikipedia.org/w/index.php?title=Https&variant=zh-cn



主要思路:

1、用gmail或google docs加密撰写稿件,投递到blogspot站点。

2、用google reader加密订阅blogspot博客。



好处:

1、无需自己架设主机。

2、全程安全、无任何障碍。



缺点:

网友在传播时,复制粘贴到别的网站时可能会受到限制。



详细步骤:

1、申请gmail:

https://www.gmail.com

2、申请blogger帐号(也是google产品):

用代理如https://www.sneakme.net(这个代理非常快,可流畅播放youtube)上www.blogger.com,用gmail帐号登录。

3、设置 blogger:

在“出版业”中可设置博客的独立域名,如我的www.tallrain.cn=tallrain.blogspot.com

对于独立域名,需将此域名解析转向到ghs.google.com或其它最终定义到有限IP的地址,如我的www.tallrain.cn解析转向到ghs.keso.cn。

在“供稿”页中可设置输出的feed地址,如http://feedproxy.google.com/tallrain,可在google的feed中加入广告。

在“电子邮件和移动博客”页中,可设置电子邮件发布地址,从你的GMAIL中将内容直接发送到此地址即可实现发布博客。其它人向此地址发送邮件也可以实现联合供稿,但建议用https://gmail.com,因为它是加密的。



4、用gmail写稿

这是最方便的,但是有个前提,不支持图片。

进入https://gmail.com,写邮件主题和正文,然后直接发送到第3步所定义的邮件地址即可。

带图片的情况后面单独讲。



5、用google docs写稿

如果是个人博客,其实写稿也非常容易。

https://docs.google.com中新建文档,和WORD一样编辑、保存,然后点击右上角的 共享》以网页形式发布...》张贴到博客,定义好博客设置,如:



定义好之后就可以直接就文档发布到博客上了。和gmail一样,这过程全部是在google的服务器之间加密进行的,安全可靠,GFW无计可施。

google docs有一个好处就是支持图片,而且图片地址也是加密的,每次查看图片时都会向google的服务器发送一次查询的请求,图片的显示地址与文件名无关。

因此可以很放心方便地利用google docs实现多图的博客供稿,就象用word编辑文件一样方便。

google docs投递的稿件还可以通过原地址更新,只要重要发布一次就可以了。



6、利用gmail和google docs实现带图片的联合供稿

方法是首先在google docs里编辑稿件,然后点击右上角的 共享》以网页形式发布,发布在线文档,这样就生成了一篇在线文档,将文档地址的头从http://改为https://,这样图片的地址是经过google docs加密的网络地址。

然后就此发布后的文档全选》复制,在gmail中新建邮件,粘贴,就实现了在gmail中贴网络图片的目的。



7、博客订阅

https://www.google.com/reader,同样是加密的。



经由以上环节,所有数据传输都是在google的服务器间加密传输的。



8、其实建立博客群还有一个很简单的办法,就是首先在google reader中建立一个文件夹,用此文件夹订阅若干个博客RSS,然后将此文件夹共享,即可得到一个新的公用地址,然后得到一个对应的订阅RSS,如这个地址就是一组订阅http://www.google.com/reader/shared/user/17431774544185162274/label/%E6%9C%80%E8%BF%91%E6%B4%BB%E5%8A%A8,其RSS就是http://www.google.com/reader/public/atom/user%2F17431774544185162274%2Flabel%2F%E6%9C%80%E8%BF%91%E6%B4%BB%E5%8A%A8




本地加密图片

本地图片:

google docs图片测试

本地图片:

163


163



网易企业邮,商务邮箱专家

test

just a test...

test again

040516.jpg

2009年5月24日

Oracle迭代和存储过程练习2

一、创建多维表snlink_dim
create table SNLINK_DIM
(
  ROOTID  NUMBER(10),
  SN      VARCHAR2(10),
  CID     NUMBER(10),
  LEVELID NUMBER(2),
  DIM     VARCHAR2(255)
)
;


二、创建ADDSNLINK触发器
CREATE OR REPLACE TRIGGER tg_addsnlink
AFTER INSERT ON snlink
FOR EACH ROW
DECLARE
  pragma AUTONOMOUS_TRANSACTION;
  rootid  NUMBER;
  cid     NUMBER;
  fsn     VARCHAR2(100);
  flevid  NUMBER;
  fdim    VARCHAR2(100);
  clevid  NUMBER;
  cdim    VARCHAR2(100);
  cursql  VARCHAR2(1000);
  mdim    VARCHAR2(100);
  mdim2   VARCHAR2(100);
  i       NUMBER;
  TYPE myrecord IS RECORD(levelid NUMBER, dim VARCHAR2(100));
  myrec myrecord;
  CURSOR myfid(thesn VARCHAR2) IS SELECT levelid, dim FROM snlink_dim WHERE sn=thesn;
  CURSOR myfid2(rid NUMBER, lev NUMBER, fdim VARCHAR2, flen NUMBER)
   IS SELECT MAX(DIM) FROM snlink_dim
   WHERE rootid = rid
   AND levelid = lev
   AND SUBSTR(dim, 1, flen+1) = fdim || ',';
BEGIN
  cid := :new.id;
  rootid := getrootid(:new.fid);
  IF :new.fid<0 THEN -- add new root
    rootid := :new.id;
    clevid := 1;
    cdim :='1';
    cursql := 'INSERT INTO snlink_dim VALUES(' || rootid || ',''' || :new.sn || ''',' || rootid;
    cursql := cursql || ',' || 1 || ',''1'')';
    EXECUTE immediate cursql;
    COMMIT;       
  ELSE  -- to get levelid and dim
    cid := :new.id;
    fsn := getsnbyid(:new.fid);
    OPEN myfid(fsn);
    FETCH myfid INTO myrec;
    flevid := myrec.levelid;
    fdim := myrec.dim;
    clevid := flevid + 1; -- get levelid
    OPEN myfid2(rootid, clevid, fdim, length(fdim));
    FETCH myfid2 INTO mdim;
    IF (mdim is null) or (mdim = '') THEN -- first child
      cdim := fdim || ',1';   
    ELSE --
      i := 1;
      WHILE i>0 LOOP
        i := INSTR(mdim,',');
        if i>0 THEN
         mdim := SUBSTR(mdim,i+1,length(mdim)-i);        
        END IF;
      END LOOP;
      mdim2 := TO_CHAR(TO_NUMBER(mdim)+1);
      cdim := fdim || ',' || mdim2;      
    END IF;   
    cursql := 'INSERT INTO snlink_dim VALUES(' || rootid || ',''' || :new.sn || ''',' || cid;
    cursql := cursql || ',' || clevid || ',''' || cdim || ''')';    
    EXECUTE immediate cursql;
    COMMIT;          
  END IF;  
END;


三、建SNINFO表
CREATE TABLE sninfos
(
 sn    varchar2(10),
 pn    varchar2(10)
);


四、定义产品结构
+pn1
 -pn2
 +pn3
  +pn4
   -pn5


五、创建批量导入的存储过程
CREATE OR REPLACE PROCEDURE batch_add_snlink(beginid NUMBER, qty NUMBER)
AS
  i NUMBER;
  cursql VARCHAR2(1000);
  sn1 VARCHAR2(10);
  sn2 VARCHAR2(10);
  sn3 VARCHAR2(10);
  sn4 VARCHAR2(10);
  sn5 VARCHAR2(10);
BEGIN
  i := beginid;
  WHILE i< (beginid + qty) LOOP
    sn1 := 'sn1-' || i;
    sn2 := 'sn2-' || i;
    sn3 := 'sn3-' || i;
    sn4 := 'sn4-' || i;
    sn5 := 'sn5-' || i;
    cursql := 'INSERT INTO sninfos values('''||sn1||''', ''pn1'')';
    EXECUTE immediate cursql;
    COMMIT;
    cursql := 'INSERT INTO sninfos values('''||sn2||''', ''pn2'')';
    EXECUTE immediate cursql;
    COMMIT;
    cursql := 'INSERT INTO sninfos values('''||sn3||''', ''pn3'')';
    EXECUTE immediate cursql;
    COMMIT;  
    cursql := 'INSERT INTO sninfos values('''||sn4||''', ''pn4'')';
    EXECUTE immediate cursql;
    COMMIT;  
    cursql := 'INSERT INTO sninfos values('''||sn5||''', ''pn5'')';           
    EXECUTE immediate cursql;
    COMMIT;
    addsnlink(sn1, sn2);
    addsnlink(sn1, sn3);
    addsnlink(sn3, sn4);
    addsnlink(sn4, sn5);
    i := i + 1;
  END LOOP;
END;


六、调用batch_add_snlink(1001,1000)插入100条记录,并查看sninfos, snlink, snlink_dim的数据情况。


七、从snlink表查询数据生成交叉表
SELECT
 i1.sn as pn1,
 i2.sn as pn2,
 i3.sn as pn3,
 i4.sn as pn4,
 i5.sn as pn5
FROM
 sninfos i1,
 sninfos i2,
 sninfos i3,
 sninfos i4,
 sninfos i5,
 snlink s1,
 snlink s2,
 snlink s3,
 snlink s4,
 snlink s5
WHERE i1.sn = s1.sn
AND i2.sn = s2.sn
AND i3.sn = s3.sn
AND i4.sn = s4.sn
AND i5.sn = s5.sn
AND s1.id = s2.fid
AND i2.pn = 'pn2'
AND s1.id = s3.fid
AND i3.pn = 'pn3'
AND s3.id = s4.fid
AND s4.id = s5.fid
ORDER BY i1.sn

1120 rows selected in 0.889 seconds.
10000 rows selected in 6.707 seconds.
24092 rows selected in 25.335 seconds.

八、从snlink_dim表查询数据生成交叉表
SELECT
 s1.sn as pn1,
 s2.sn as pn2,
 s3.sn as pn3,
 s4.sn as pn4,
 s5.sn as pn5
FROM
 snlink_dim s1,
 snlink_dim s2,
 snlink_dim s3,
 snlink_dim s4,
 snlink_dim s5
WHERE s1.dim = '1'
AND s2.dim = '1,1'
AND s3.dim = '1,2'
AND s4.dim = '1,2,1'
AND s5.dim = '1,2,1,1'
AND s1.rootid = s2.rootid
AND s1.rootid = s3.rootid
AND s1.rootid = s4.rootid
AND s1.rootid = s5.rootid
ORDER BY s1.sn

1130 rows selected in 0.546 seconds.
10000 rows selected in 4.93 seconds.
24092 rows selected in 11.654 seconds.


九、创建BOM表1
CREATE TABLE bom1
(
 pn    VARCHAR2(10),
 cpn   VARCHAR2(10),
 qty   NUMBER(3)
);

输入以下数据:
+pn1
 +pn2,1
  -pn3,2
  -pn6,2
 +pn4,2
  -pn5,1
 -pn3,1


十、创建pn表
CREATE TABLE pn
(
 pn    VARCHAR2(10),
 des  VARCHAR2(1024)
);


十一、关联迭代查询
SELECT LEVEL, bom1.pn, bom1.cpn, pn.des, bom1.qty
FROM bom1, pn
WHERE bom1.cpn=pn.pn
START WITH bom1.pn='pn1'
CONNECT BY PRIOR cpn=bom1.pn

2009年5月12日

数据库多维迭代算法


关键词:数据库 迭代 递归 多维

一、两种传统的数据库迭代结构算法

对于数据库的迭代结构,有两种传统的算法:递归算法和边界算法。

比如对于下面图1的结构:

1

递归算法的数据结构如表1所示:

节点id

节点值

父节点id

1

1111

-2

3

1112

1

4

1113

1

5

1114

4

6

1115

4

7

1116

1

8

1117

7

9

1118

8

1

父节点id如为负值,表示这是一个根节点。

从表1可以看出,我们用若干组父-子递归的结构来表达完整的迭代结构。

这种算法很容易理解,但是缺点也很明显:

  1. 要从任意一个节点展现整个结构时,要从此节点向根节点做一个逆向递归,然后由根节点向所有层的子节点做N次正向递归,数据库的运算开销很大。特别是正向递归到达所有外围节点时要做一个空查询,形成浪费。

  2. 尽管oracle对递归查询有优化算法,如

select distinct *
from table1
start with
节点值='1111'
connect by prior
节点id=父节点id

这样可以形成以'1111'为根的整个节点树结构。

但是这种优化在统计时是无能为力的,而且此查询返回的结果丢失了很多结构的细节。


下面我们再来分析第二种迭代算法:边界算法。

这种算法有点类似邮递员送信路径的传统数学难题,方法是将节点的边界串起来,同时记录其结构。

对于图1的结构,数据库中记录如表2所示:

节点值

结构id

节点顺序

节点层次

1111

1001

1

1

1112

1001

2

2

1113

1001

3

2

1114

1001

4

3

1115

1001

5

3

1116

1001

6

2

1117

1001

7

3

1118

1001

8

4

2

这里1001是此结构的id。因此我们可以用结构id,仅通过一次查询,就可以将整个结构展现出来。

此算法的缺点是:

  1. 取子结构麻烦,比如我们要查询1113-1114-1115的子结构,我们要从1113开始将整个结构截取出来,然后分析哪些是它的子结构。

  2. 数据更新麻烦,在插入或删除某个子结构时,要将节点顺序重新排序。


二、多维迭代算法的原理

所谓多维迭代算法,是指任意一个节点,在继承父节点的特性同时,创建自己的特性维度。

对于图1的结构,其数据库中的记录如表3所示:

节点值

结构id

节点维度

1111

1001

1

1112

1001

1,1

1113

1001

1,2

1114

1001

1,2,1

1115

1001

1,2,2

1116

1001

1,3

1117

1001

1,3,1

1118

1001

1,3,1,1

3

我们可以看出,任意一个节点都有其结构中的唯一维度,而且往左减一个维度就是其父节点的维度。因此我们要取子结构也非常方便,只要对节点维度从左开始截取若干位进行匹配就可以了。这种结构无需递归,因此统计时效率得到级数级的提升。

下面介绍多维迭代的一些扩展算法:

  1. 查询子结构

如查询1113的子结构,算法是取结构id=1001,且节点2维维度='1,2',返回1113111411153条数据,且111411151113的子节点。

  1. 插入子结构

如我们要将图2的子结构插入1116这个节点上,即22211116的子节点:

2

则运算方法为:首先获得2221的新维度(1,3,2),然后将整个子结构的第1维度更新为(1,3,2),最后最新子结构的结构id(1001)

  1. 取消子结构

假如我们要取消1116-1117-1118这个子结构,那么首先获得新的结构id,然后用1替换子结构的前2(1,3)

  1. 替换子结构

假如我们用图2的子结构替换图11116-1117-1118的子结构,或者说用2221替换1116,则首先临时记录1116的结构id(1001)和维度(1,3),然后取消1116子结构,然后更新2221子结构的id和维度。


三、多维迭代算法的典型应用

  1. ERP缺料统计

我们知道ERPBOM是一个典型的递归结构,在进行缺料统计时,要把最顶层的料号展开成所有底层料号的集合,因此有很多的递归。

如果我们在表3的多维结构上增加数量属性,就可以得到一个类似BOM的结构体。即使我们不改动BOM,也可以通过第三方开发,把BOM结构映射为一个多维结构范式,从而减少递归运算。

  1. 包装装配数据统计

生产上的包装和装配数据通常采用递归结构,如果要对多组数据进行统计的话,要进行成千上万次的递归,效率极低。

如果包装和装配数据都采用多维结构存储的话,只要一次查询就可以导出统计报表了,而且报表数据还保留了完整的结构。

  1. 数据仓库应用

如果要对递归数据进行数据仓库处理的话,只要将递归结构映射为一个多维结构,就可以方便地储存和统计递归数据,同时保留其结构。

  1. 家谱

我们只要在多维结构上分别定义父亲维度和母亲维度,就可以方便地进行多数家谱运算。


Oracle迭代和存储过程练习

用临时表生成包含层次信息的结构树。

一、创建测试帐号
DROP USER TEST CASCADE;
CREATE USER TEST IDENTIFIED BY tt;
GRANT CONNECT, RESOURCE TO TEST;


二、创建数据表SNLINK
CREATE TABLE SNLINK
(
 ID NUMBER(10)    NOT NULL,
 SN VARCHAR(10)    NOT NULL,
 FID NUMBER(10)
)
;


三、创建序列SEQ_SNLINK_ID
CREATE SEQUENCE SEQ_SNLINK_ID
MINVALUE 1
MAXVALUE 100000
START WITH 1
INCREMENT BY 1
;


四、递增函数getnewid
CREATE OR REPLACE FUNCTION getnewid RETURN NUMBER
AS
id NUMBER;
CURSOR myid IS SELECT seq_snlink_id.NEXTVAL FROM dual;
BEGIN
  OPEN myid;
  FETCH myid INTO id;
  CLOSE myid;
--  DBMS_OUTPUT.PUT_LINE('newid='||id);
  RETURN(id);
END getnewid;


五、查询SN对应的ID
CREATE OR REPLACE FUNCTION getidbysn(thesn IN VARCHAR2) RETURN NUMBER
AS
id NUMBER;
CURSOR myid(thesn VARCHAR2) IS SELECT id FROM snlink WHERE sn=thesn;
BEGIN
  OPEN myid(thesn);
  FETCH myid INTO id;
  IF myid%NOTFOUND THEN id:=0-getnewid;
  END IF;
  CLOSE myid;
  RETURN(id);
END getidbysn;


六、创建ADDSNLINK过程
CREATE OR REPLACE PROCEDURE addsnlink(fsn IN varchar2,csn IN varchar2) AS
  cid number;
  fid number;
  gid number;  -- grandfather id 
  cursql varchar2(1000);
BEGIN
-- get fid begin
  fid:=getidbysn(fsn);
  IF fid<0 THEN  -- get gid and insert fsn
    gid:=getnewid;
    cursql:='INSERT INTO snlink VALUES('||(0-fid)||', '||fsn||', '||(0-gid)||')';
--    DBMS_OUTPUT.put_line('sql1='||cursql); 
    EXECUTE immediate cursql;  
    fid:=0-fid;    
  END IF;
-- get cid begin
  cid:=getidbysn(csn);
  IF cid>0 THEN -- record found, raise error
--    DBMS_OUTPUT.PUT_LINE('RECORD FOUND, NOT ALLOWED!');
    ROLLBACK;
  ELSE
    cursql:='INSERT INTO snlink VALUES('||(0-cid)||', '||csn||', '||fid||')';
--    DBMS_OUTPUT.put_line('sql1='||cursql); 
    EXECUTE immediate cursql;       
    COMMIT;
  END IF;
END addsnlink;


七、一次性导入全部数据
CREATE OR REPLACE PROCEDURE inputalldata AS
  cursql varchar2(1000);
BEGIN
  cursql:='delete from snlink';
  EXECUTE immediate cursql;
  COMMIT;
  addsnlink('1111','1112');
  addsnlink('1111','1113');
  addsnlink('1113','1114');
  addsnlink('1113','1115');
  addsnlink('1111','1116');
  addsnlink('1116','1117');
  addsnlink('1117','1118');
  COMMIT;
END inputalldata;


八、以某SN为根进行层次查询
SELECT DISTINCT LEVEL, id, sn, fid
FROM SNLINK
START WITH SN='1111'
CONNECT BY PRIOR id=fid


九、查父节点
CREATE OR REPLACE FUNCTION getfatherid(cid IN NUMBER) RETURN NUMBER
AS
fid NUMBER;
CURSOR myid(cid NUMBER) IS SELECT fid FROM snlink WHERE id=cid;
BEGIN
  OPEN myid(cid);
  FETCH myid INTO fid;
  IF myid%NOTFOUND THEN fid:=0-getnewid;
  END IF;
  CLOSE myid;
  RETURN(fid);
END getfatherid;


十、查根节点
CREATE OR REPLACE FUNCTION getrootid(cid IN NUMBER) RETURN NUMBER
AS
cid2 NUMBER;
fid NUMBER;
rid NUMBER;
BEGIN
  cid2:=cid;
  fid:=0;
  rid:=0;
  WHILE fid>=0 LOOP
    fid:=getfatherid(cid2);
    cid2:=fid;
    IF fid>0 THEN rid:=fid;
    END IF;
  END LOOP;
  RETURN(rid);
END getrootid;


十一、创建查询结构临时表
CREATE GLOBAL TEMPORARY TABLE tmp_snlink_dim
(
 seqid        VARCHAR2(100),
 sn        VARCHAR2(10),
 cid        NUMBER(10),
 levelid    NUMBER(2),
 dim        VARCHAR2(255)
)
ON COMMIT PRESERVE ROWS;


十三、查家族
CREATE OR REPLACE PROCEDURE queryfamily(seqid2 VARCHAR2, pid2 IN NUMBER, levelid2 IN NUMBER, dim2 IN varchar2)
AS
 i NUMBER;
 pid3 NUMBER;
 levid NUMBER;
 levid2 NUMBER;
 dimid VARCHAR2(100);
 dimid2 VARCHAR2(100);
 cid2 NUMBER;
 cid3 NUMBER;
 csn2 VARCHAR2(10);
 cursql varchar2(1000);
 myrec snlink%ROWTYPE;
 CURSOR mycid IS SELECT * FROM snlink WHERE fid=pid2;
 CURSOR mycid2 IS SELECT * FROM snlink WHERE fid=pid3;
BEGIN
  i := 0;
  levid := levelid2 + 1;
--  DBMS_OUTPUT.put_line('i1:='||i);       
  OPEN mycid;
  FETCH mycid INTO myrec;
  WHILE mycid%FOUND LOOP
    i := i + 1;
--    DBMS_OUTPUT.put_line('i2:='||i);     
    cid2 := myrec.id;
    csn2 := myrec.sn;
    dimid := dim2 || ',' || i;
    cursql := 'INSERT INTO tmp_snlink_dim VALUES(''' || seqid2 || ''',''' || csn2 || ''',' || cid2;
    cursql := cursql || ',' || levid || ',''' || dimid || ''')';
--    DBMS_OUTPUT.put_line('sql='||cursql); 
    EXECUTE immediate cursql;
    cid3:=cid2;
    levid2:=levid;
    dimid2:=dimid;
    queryfamily(seqid2,cid3,levid2,dimid2);
--    cid2:=cid3;
--    levid:=levid2;
--    dimid:=dimid2;
    FETCH mycid INTO myrec; 
  END LOOP;
  CLOSE mycid;
  COMMIT;
END queryfamily;



十四、查询ID对应的SN
CREATE OR REPLACE FUNCTION getsnbyid(theid IN NUMBER) RETURN VARCHAR2
AS
sn NUMBER;
CURSOR myid(theid NUMBER) IS SELECT sn FROM snlink WHERE id=theid;
BEGIN
  OPEN myid(theid);
  FETCH myid INTO sn;
  IF myid%NOTFOUND THEN sn:='';
  END IF;
  CLOSE myid;
  RETURN(sn);
END getsnbyid;


十五、根据SN和线程字符串生成临时结果集
CREATE OR REPLACE PROCEDURE queryfamily2(csn IN VARCHAR2, seqid IN VARCHAR2)
AS
  cid NUMBER;
  rootid NUMBER;
  rootsn varchar2(10);
  cursql varchar2(1000); 
BEGIN
  cid:=getidbysn(csn); 
  if cid>0 then
   rootid:=getrootid(cid);
   rootsn:=getsnbyid(rootid);
   cursql := 'INSERT INTO tmp_snlink_dim VALUES(''' || seqid || ''',' || rootsn || ',' || rootid;
   cursql := cursql || ',' || 1 || ',''1'')';
--   DBMS_OUTPUT.put_line('sql='||cursql); 
   EXECUTE immediate cursql;     
   queryfamily(seqid,rootid,1,'1');
  END IF;
END queryfamily2;


十六、生成结果:
EXECUTE QUERYFAMILY2('1113','XYZ');
SQL> SELECT * FROM TMP_SNLINK_DIM ORDER BY DIM;

SEQID        SN                 CID LEVELID  DIM
------------ ---------- ----------- -------  -----------
XYZ          1111               189       1  1
XYZ          1116               195       2  1,1
XYZ          1117               196       3  1,1,1
XYZ          1118               197       4  1,1,1,1
XYZ          AC                 193       2  1,2
XYZ          1112               191       2  1,3
XYZ          1113               192       2  1,4
XYZ          1114               193       3  1,4,1
XYZ          1115               194       3  1,4,2