Archive for the ‘开发与经营’ Category

SQL语法大全

一、基础
1、说明:创建数据库
CREATE DATABASE database-name
2、说明:删除数据库
drop database dbname
3、说明:备份sql server
— 创建 备份数据的 device
USE master
EXEC sp_addumpdevice ‘disk’, ‘testBack’, ‘c:\mssql7backup\MyNwind_1.dat’
— 开始 备份
BACKUP DATABASE pubs TO testBack
4、说明:创建新表
create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)
根据已有的表创建新表:
A:create table tab_new like tab_old (使用旧表创建新表)
B:create table tab_new as select col1,col2… from tab_old definition only
5、说明:删除新表
drop table tabname
6、说明:增加一个列
Alter table tabname add column col type
注:列增加后将不能删除。DB2中列加上后数据类型也不能改变,唯一能改变的是增加varchar类型的长度。
7、说明:添加主键: Alter table tabname add primary key(col)
说明:删除主键: Alter table tabname drop primary key(col)
8、说明:创建索引:create [unique] index idxname on tabname(col….)
删除索引:drop index idxname
注:索引是不可更改的,想更改必须删除重新建。
9、说明:创建视图:create view viewname as select statement
删除视图:drop view viewname
10、说明:几个简单的基本的sql语句
选择:select * from table1 where 范围
插入:insert into table1(field1,field2) values(value1,value2)
删除:delete from table1 where 范围
更新:update table1 set field1=value1 where 范围
查找:select * from table1 where field1 like ’%value1%’ —like的语法很精妙,查资料!
排序:select * from table1 order by field1,field2 [desc]
总数:select count as totalcount from table1
求和:select sum(field1) as sumvalue from table1
平均:select avg(field1) as avgvalue from table1
最大:select max(field1) as maxvalue from table1
最小:select min(field1) as minvalue from table1
11、说明:几个高级查询运算词
A: UNION 运算符
UNION 运算符通过组合其他两个结果表(例如 TABLE1 和 TABLE2)并消去表中任何重复行而派生出一个结果表。当 ALL 随 UNION 一起使用时(即 UNION ALL),不消除重复行。两种情况下,派生表的每一行不是来自 TABLE1 就是来自 TABLE2。
B: EXCEPT 运算符
EXCEPT 运算符通过包括所有在 TABLE1 中但不在 TABLE2 中的行并消除所有重复行而派生出一个结果表。当 ALL 随 EXCEPT 一起使用时 (EXCEPT ALL),不消除重复行。
C: INTERSECT 运算符
INTERSECT 运算符通过只包括 TABLE1 和 TABLE2 中都有的行并消除所有重复行而派生出一个结果表。当 ALL 随 INTERSECT 一起使用时 (INTERSECT ALL),不消除重复行。
注:使用运算词的几个查询结果行必须是一致的。
12、说明:使用外连接
A、left (outer) join:
左外连接(左连接):结果集几包括连接表的匹配行,也包括左连接表的所有行。
SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
B:right (outer) join:
右外连接(右连接):结果集既包括连接表的匹配连接行,也包括右连接表的所有行。
C:full/cross (outer) join:
全外连接:不仅包括符号连接表的匹配行,还包括两个连接表中的所有记录。
12、分组:Group by:
一张表,一旦分组 完成后,查询后只能得到组相关的信息。
组相关的信息:(统计信息) count,sum,max,min,avg 分组的标准)
在SQLServer中分组时:不能以text,ntext,image类型的字段作为分组依据
在selecte统计函数中的字段,不能和普通的字段放在一起;
13、对数据库进行操作:
分离数据库: sp_detach_db; 附加数据库:sp_attach_db 后接表明,附加需要完整的路径名
14.如何修改数据库的名称:
sp_renamedb ‘old_name’, ‘new_name’
二、提升
1、说明:复制表(只复制结构,源表名:a 新表名:b) (Access可用)
法一:select * into b from a where 11(仅用于SQlServer)
法二:select top 0 * into b from a
2、说明:拷贝表(拷贝数据,源表名:a 目标表名:b) (Access可用)
insert into b(a, b, c) select d,e,f from b;
3、说明:跨数据库之间表的拷贝(具体数据使用绝对路径) (Access可用)
insert into b(a, b, c) select d,e,f from b in ‘具体数据库’ where 条件
例子:..from b in ‘”&Server.MapPath(“.”)&”\data.mdb” &”‘ where..
4、说明:子查询(表名1:a 表名2:b)
select a,b,c from a where a IN (select d from b ) 或者: select a,b,c from a where a IN (1,2,3)
5、说明:显示文章、提交人和最后回复时间
select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b
6、说明:外连接查询(表名1:a 表名2:b)
select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
7、说明:在线视图查询(表名1:a )
select * from (SELECT a,b,c FROM a) T where t.a > 1;
8、说明:between的用法,between限制查询数据范围时包括了边界值,not between不包括
select * from table1 where time between time1 and time2
select a,b,c, from table1 where a not between 数值1 and 数值2
9、说明:in 的使用方法
select * from table1 where a [not] in (‘值1’,’值2’,’值4’,’值6’)
10、说明:两张关联表,删除主表中已经在副表中没有的信息
delete from table1 where not exists ( select * from table2 where table1.field1=table2.field1 )
11、说明:四表联查问题:
select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where …..
12、说明:日程安排提前五分钟提醒
SQL: select * from 日程安排 where datediff(‘minute’,f开始时间,getdate())>5
13、说明:一条sql 语句搞定数据库分页
select top 10 b.* from (select top 20 主键字段,排序字段 from 表名 order by 排序字段 desc) a,表名 b where b.主键字段 = a.主键字段 order by a.排序字段
具体实现:
关于数据库分页:
declare @start int,@end int
@sql nvarchar(600)
set @sql=’select top’+str(@end-@start+1)+’+from T where rid not in(select top’+str(@str-1)+’Rid from T where Rid>-1)’
exec sp_executesql @sql
–注意:在top后不能直接跟一个变量,所以在实际应用中只有这样的进行特殊的处理。Rid为一个标识列,如果top后还有具—体的字段,这样做是非常有好处的。因为这样可以避免 top的字段如果是逻辑索引的,查询的结果后实际表中的不一致(逻–辑索引中的数据有可能和数据表中的不一致,而查询时如果处在索引则首先查询索引)
14、说明:前10条记录
select top 10 * form table1 where 范围

–5、说明:选择在每一组b值相同的数据中对应的a最大的记录的所有信息(类似这样的用法可以用于论坛每月排行榜,每月热销产品分析,按科目成绩排名,等等.)
select a,b,c from tablename ta where a=(select max(a) from tablename tb where tb.b=ta.b)

16、说明:包括所有在 TableA 中但不在 TableB和TableC 中的行并消除所有重复行而派生出一个结果表
(select a from tableA ) except (select a from tableB) except (select a from tableC)

17、说明:随机取出10条数据
select top 10 * from tablename order by newid()

18、说明:随机选择记录
select newid()

19、说明:删除重复记录

1),delete from tablename where id not in (select max(id) from tablename group by col1,col2,…)

2),select distinct * into temp from tablename
delete from tablename
insert into tablename select * from temp
评价: 这种操作牵连大量的数据的移动,这种做法不适合大容量但数据操作

3),例如:在一个外部表中导入数据,由于某些原因第一次只导入了一部分,但很难判断具体位置,这样只有在下一次全部导入,这样也就产生好多重复的字段,怎样删除重复字段
alter table tablename

–添加一个自增列
add column_b int identity(1,1)
delete from tablename where column_b not in(
select max(column_b) from tablename group by column1,column2,…)
alter table tablename drop column column_b

20、说明:列出数据库里所有的表名
select name from sysobjects where type=’U’ // U代表用户

21、说明:列出表里的所有的列名
select name from syscolumns where id=object_id(‘TableName’)

22、说明:列示type、vender、pcs字段,以type字段排列,case可以方便地实现多重选择,类似select 中的case。
select type,sum(case vender when ‘A’ then pcs else 0 end),sum(case vender when ‘C’ then pcs else 0 end),sum(case vender when ‘B’ then pcs else 0 end) FROM tablename group by type
显示结果:
type vender pcs
电脑 A 1
电脑 A 1
光盘 B 2
光盘 A 2
手机 B 3
手机 C 3

23、说明:初始化表table1
TRUNCATE TABLE table1

24、说明:选择从10到15的记录
select top 5 * from (select top 15 * from table order by id asc) table_别名 order by id desc

三、技巧
1、1=1,1=2的使用,在SQL语句组合时用的较多
“where 1=1” 是表示选择全部 “where 1=2”全部不选,
如:
if @strWhere !=”
begin
set @strSQL = ‘select count(*) as Total from [‘ + @tblName + ‘] where ‘ + @strWhere
end
else
begin
set @strSQL = ‘select count(*) as Total from [‘ + @tblName + ‘]’
end
我们可以直接写成
错误!未找到目录项。
set @strSQL = ‘select count(*) as Total from [‘ + @tblName + ‘] where 1=1 安定 ‘+ @strWhere 2、收缩数据库
–重建索引
DBCC REINDEX
DBCC INDEXDEFRAG
–收缩数据和日志
DBCC SHRINKDB
DBCC SHRINKFILE

3、压缩数据库
dbcc shrinkdatabase(dbname)

4、转移数据库给新用户以已存在用户权限
exec sp_change_users_login ‘update_one’,’newname’,’oldname’
go

5、检查备份集
RESTORE VERIFYONLY from disk=’E:\dvbbs.bak’

6、修复数据库
ALTER DATABASE [dvbbs] SET SINGLE_USER
GO
DBCC CHECKDB(‘dvbbs’,repair_allow_data_loss) WITH TABLOCK
GO
ALTER DATABASE [dvbbs] SET MULTI_USER
GO

7、日志清除
SET NOCOUNT ON
DECLARE @LogicalFileName sysname,
@MaxMinutes INT,
@NewSize INT

USE tablename — 要操作的数据库名
SELECT @LogicalFileName = ‘tablename_log’, — 日志文件名
@MaxMinutes = 10, — Limit on time allowed to wrap log.
@NewSize = 1 — 你想设定的日志文件的大小(M)

Setup / initialize
DECLARE @OriginalSize int
SELECT @OriginalSize = size
FROM sysfiles
WHERE name = @LogicalFileName
SELECT ‘Original Size of ‘ + db_name() + ‘ LOG is ‘ +
CONVERT(VARCHAR(30),@OriginalSize) + ‘ 8K pages or ‘ +
CONVERT(VARCHAR(30),(@OriginalSize*8/1024)) + ‘MB’
FROM sysfiles
WHERE name = @LogicalFileName
CREATE TABLE DummyTrans
(DummyColumn char (8000) not null)

DECLARE @Counter INT,
@StartTime DATETIME,
@TruncLog VARCHAR(255)
SELECT @StartTime = GETDATE(),
@TruncLog = ‘BACKUP LOG ‘ + db_name() + ‘ WITH TRUNCATE_ONLY’

DBCC SHRINKFILE (@LogicalFileName, @NewSize)
EXEC (@TruncLog)
— Wrap the log if necessary.
WHILE @MaxMinutes > DATEDIFF (mi, @StartTime, GETDATE()) — time has not expired
AND @OriginalSize = (SELECT size FROM sysfiles WHERE name = @LogicalFileName)
AND (@OriginalSize * 8 /1024) > @NewSize
BEGIN — Outer loop.
SELECT @Counter = 0
WHILE ((@Counter < @OriginalSize / 16) AND (@Counter < 50000))
BEGIN — update
INSERT DummyTrans VALUES ('Fill Log') DELETE DummyTrans
SELECT @Counter = @Counter + 1
END
EXEC (@TruncLog)
END
SELECT 'Final Size of ' + db_name() + ' LOG is ' +
CONVERT(VARCHAR(30),size) + ' 8K pages or ' +
CONVERT(VARCHAR(30),(size*8/1024)) + 'MB'
FROM sysfiles
WHERE name = @LogicalFileName
DROP TABLE DummyTrans
SET NOCOUNT OFF

8、说明:更改某个表
exec sp_changeobjectowner 'tablename','dbo'

9、存储更改全部表
CREATE PROCEDURE dbo.User_ChangeObjectOwnerBatch
@OldOwner as NVARCHAR(128),
@NewOwner as NVARCHAR(128)
AS

DECLARE @Name as NVARCHAR(128)
DECLARE @Owner as NVARCHAR(128)
DECLARE @OwnerName as NVARCHAR(128)

DECLARE curObject CURSOR FOR
select 'Name' = name,
'Owner' = user_name(uid)
from sysobjects
where user_name(uid)=@OldOwner
order by name

OPEN curObject
FETCH NEXT FROM curObject INTO @Name, @Owner
WHILE(@@FETCH_STATUS=0)
BEGIN
if @Owner=@OldOwner
begin
set @OwnerName = @OldOwner + '.' + rtrim(@Name)
exec sp_changeobjectowner @OwnerName, @NewOwner
end
— select @name,@NewOwner,@OldOwner

FETCH NEXT FROM curObject INTO @Name, @Owner
END

close curObject
deallocate curObject
GO

10、SQL SERVER中直接循环写入数据
declare @i int
set @i=1
while @i<30
begin
insert into test (userid) values(@i)
set @i=@i+1
end
案例:
有如下表,要求就裱中所有沒有及格的成績,在每次增長0.1的基礎上,使他們剛好及格:
Name score
Zhangshan 80
Lishi 59
Wangwu 50
Songquan 69
while((select min(score) from tb_table)<60)
begin
update tb_table set score =score*1.01
where score60
break
else
continue
end

数据开发-经典

1.按姓氏笔画排序:
Select * From TableName Order By CustomerName Collate Chinese_PRC_Stroke_ci_as //从少到多

2.数据库加密:
select encrypt(‘原始密码’)
select pwdencrypt(‘原始密码’)
select pwdcompare(‘原始密码’,’加密后密码’) = 1–相同;否则不相同 encrypt(‘原始密码’)
select pwdencrypt(‘原始密码’)
select pwdcompare(‘原始密码’,’加密后密码’) = 1–相同;否则不相同

3.取回表中字段:
declare @list varchar(1000),
@sql nvarchar(1000)
select @list=@list+’,’+b.name from sysobjects a,syscolumns b where a.id=b.id and a.name=’表A’
set @sql=’select ‘+right(@list,len(@list)-1)+’ from 表A’
exec (@sql)

4.查看硬盘分区:
EXEC master..xp_fixeddrives

5.比较A,B表是否相等:
if (select checksum_agg(binary_checksum(*)) from A)
=
(select checksum_agg(binary_checksum(*)) from B)
print ‘相等’
else
print ‘不相等’

6.杀掉所有的事件探察器进程:
DECLARE hcforeach CURSOR GLOBAL FOR SELECT ‘kill ‘+RTRIM(spid) FROM master.dbo.sysprocesses
WHERE program_name IN(‘SQL profiler’,N’SQL 事件探查器’)
EXEC sp_msforeach_worker ‘?’

7.记录搜索:
开头到N条记录
Select Top N * From 表
——————————-
N到M条记录(要有主索引ID)
Select Top M-N * From 表 Where ID in (Select Top M ID From 表) Order by ID Desc
———————————-
N到结尾记录
Select Top N * From 表 Order by ID Desc
案例
例如1:一张表有一万多条记录,表的第一个字段 RecID 是自增长字段, 写一个SQL语句, 找出表的第31到第40个记录。
select top 10 recid from A where recid not in(select top 30 recid from A)
分析:如果这样写会产生某些问题,如果recid在表中存在逻辑索引。
select top 10 recid from A where……是从索引中查找,而后面的select top 30 recid from A则在数据表中查找,这样由于索引中的顺序有可能和数据表中的不一致,这样就导致查询到的不是本来的欲得到的数据。
解决方案

1, 用order by select top 30 recid from A order by ricid 如果该字段不是自增长,就会出现问题

2, 在那个子查询中也加条件:select top 30 recid from A where recid>-1
例2:查询表中的最后以条记录,并不知道这个表共有多少数据,以及表结构。
set @s = ‘select top 1 * from T where pid not in (select top ‘ + str(@count-1) + ‘ pid from T)’
print @s exec sp_executesql @s

9:获取当前数据库中的所有用户表
select Name from sysobjects where xtype=’u’ and status>=0

10:获取某一个表的所有字段
select name from syscolumns where id=object_id(‘表名’)
select name from syscolumns where id in (select id from sysobjects where type = ‘u’ and name = ‘表名’)
两种方式的效果相同

11:查看与某一个表相关的视图、存储过程、函数
select a.* from sysobjects a, syscomments b where a.id = b.id and b.text like ‘%表名%’

12:查看当前数据库中所有存储过程
select name as 存储过程名称 from sysobjects where xtype=’P’

13:查询用户创建的所有数据库
select * from master..sysdatabases D where sid not in(select sid from master..syslogins where name=’sa’)
或者
select dbid, name AS DB_NAME from master..sysdatabases where sid 0x01

14:查询某一个表的字段和数据类型
select column_name,data_type from information_schema.columns
where table_name = ‘表名’

15:不同服务器数据库之间的数据操作
–创建链接服务器
exec sp_addlinkedserver ‘ITSV ‘, ‘ ‘, ‘SQLOLEDB ‘, ‘远程服务器名或ip地址 ‘
exec sp_addlinkedsrvlogin ‘ITSV ‘, ‘false ‘,null, ‘用户名 ‘, ‘密码 ‘
–查询示例
select * from ITSV.数据库名.dbo.表名
–导入示例
select * into 表 from ITSV.数据库名.dbo.表名
–以后不再使用时删除链接服务器
exec sp_dropserver ‘ITSV ‘, ‘droplogins ‘

–连接远程/局域网数据(openrowset/openquery/opendatasource)

–1、openrowset
–查询示例
select * from openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)
–生成本地表
select * into 表 from openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)

–把本地表导入远程表
insert openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)
select *from 本地表
–更新本地表
update b
set b.列A=a.列A
from openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)as a inner join 本地表 b
on a.column1=b.column1
–openquery用法需要创建一个连接
–首先创建一个连接创建链接服务器
exec sp_addlinkedserver ‘ITSV ‘, ‘ ‘, ‘SQLOLEDB ‘, ‘远程服务器名或ip地址 ‘
–查询
select *
FROM openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘)
–把本地表导入远程表
insert openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘)
select * from 本地表
–更新本地表
update b
set b.列B=a.列B
FROM openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘) as a
inner join 本地表 b on a.列A=b.列A

–3、opendatasource/openrowset
SELECT *
FROM opendatasource( ‘SQLOLEDB ‘, ‘Data Source=ip/ServerName;User ID=登陆名;Password=密码 ‘ ).test.dbo.roy_ta
–把本地表导入远程表
insert opendatasource( ‘SQLOLEDB ‘, ‘Data Source=ip/ServerName;User ID=登陆名;Password=密码 ‘).数据库.dbo.表名
select * from 本地表
SQL Server基本函数
SQL Server基本函数

1.字符串函数 长度与分析用

1,datalength(Char_expr) 返回字符串包含字符数,但不包含后面的空格

2,substring(expression,start,length) 取子串,字符串的下标是从“1”,start为起始位置,length为字符串长度,实际应用中以len(expression)取得其长度

3,right(char_expr,int_expr) 返回字符串右边第int_expr个字符,还用left于之相反

4,isnull( check_expression , replacement_value )如果check_expression為空,則返回replacement_value的值,不為空,就返回check_expression字符操作类

5,Sp_addtype 自定義數據類型
例如:EXEC sp_addtype birthday, datetime, ‘NULL’

6,set nocount {on|off}使返回的结果中不包含有关受 Transact-SQL 语句影响的行数的信息。如果存储过程中包含的一些语句并不返回许多实际的数据,则该设置由于大量减少了网络流量,因此可显著提高性能。SET NOCOUNT 设置是在执行或运行时设置,而不是在分析时设置。SET NOCOUNT 为 ON 时,不返回计数(表示受 Transact-SQL 语句影响的行数)。

SET NOCOUNT 为 OFF 时,返回计数常识 在SQL查询中:from后最多可以跟多少张表或视图:256在SQL语句中出现 Order by,查询时,先排序,后取在SQL中,一个字段的最大容量是8000,而对于nvarchar(4000),由于nvarchar是Unicode码。
SQLServer2000同步复制技术实现步骤一、 预备工作
1.发布服务器,订阅服务器都创建一个同名的windows用户,并设置相同的密码,做为发布快照文件夹的有效访问用户–管理工具–计算机管理–用户和组–右键用户–新建用户–建立一个隶属于administrator组的登陆windows的用户(SynUser)
2.在发布服务器上,新建一个共享目录,做为发布的快照文件的存放目录,操作:我的电脑–D:\ 新建一个目录,名为: PUB–右键这个新建的目录–属性–共享–选择”共享该文件夹”–通过”权限”按纽来设置具体的用户权限,保证第一步中创建的用户(SynUser) 具有对该文件夹的所有权限 –确定
3.设置SQL代理(SQLSERVERAGENT)服务的启动用户(发布/订阅服务器均做此设置)开始–程序–管理工具–服务–右键SQLSERVERAGENT–属性–登陆–选择”此账户”–输入或者选择第一步中创建的windows登录用户名(SynUser)–“密码”中输入该用户的密码
4.设置SQL Server身份验证模式,解决连接时的权限问题(发布/订阅服务器均做此设置)企业管理器–右键SQL实例–属性–安全性–身份验证–选择”SQL Server 和 Windows”–确定
5.在发布服务器和订阅服务器上互相注册企业管理器–右键SQL Server组–新建SQL Server注册…–下一步–可用的服务器中,输入你要注册的远程服务器名 –添加–下一步–连接使用,选择第二个”SQL Server身份验证”–下一步–输入用户名和密码(SynUser)–下一步–选择SQL Server组,也可以创建一个新组–下一步–完成
6.对于只能用IP,不能用计算机名的,为其注册服务器别名(此步在实施中没用到) (在连接端配置,比如,在订阅服务器上配置的话,服务器名称中输入的是发布服务器的IP)开始–程序–Microsoft SQL Server–客户端网络实用工具–别名–添加–网络库选择”tcp/ip”–服务器别名输入SQL服务器名–连接参数–服务器名称中输入SQL服务器ip地址–如果你修改了SQL的端口,取消选择”动态决定端口”,并输入对应的端口号二、 正式配置1、配置发布服务器打开企业管理器,在发布服务器(B、C、D)上执行以下步骤:(1) 从[工具]下拉菜单的[复制]子菜单中选择[配置发布、订阅服务器和分发]出现配置发布和分发向导 (2) [下一步] 选择分发服务器 可以选择把发布服务器自己作为分发服务器或者其他sql的服务器(选择自己)(3) [下一步] 设置快照文件夹采用默认\\servername\Pub(4) [下一步] 自定义配置 可以选择:是,让我设置分发数据库属性启用发布服务器或设置发布设置否,使用下列默认设置(推荐)(5) [下一步] 设置分发数据库名称和位置 采用默认值(6) [下一步] 启用发布服务器 选择作为发布的服务器(7) [下一步] 选择需要发布的数据库和发布类型(8) [下一步] 选择注册订阅服务器(9) [下一步] 完成配置2、创建出版物发布服务器B、C、D上(1)从[工具]菜单的[复制]子菜单中选择[创建和管理发布]命令(2)选择要创建出版物的数据库,然后单击[创建发布](3)在[创建发布向导]的提示对话框中单击[下一步]系统就会弹出一个对话框。对话框上的内容是复制的三个类型。我们现在选第一个也就是默认的快照发布(其他两个大家可以去看看帮助)(4)单击[下一步]系统要求指定可以订阅该发布的数据库服务器类型,SQLSERVER允许在不同的数据库如 orACLE或ACCESS之间进行数据复制。但是在这里我们选择运行”SQL SERVER 2000″的数据库服务器(5)单击[下一步]系统就弹出一个定义文章的对话框也就是选择要出版的表注意: 如果前面选择了事务发布 则再这一步中只能选择带有主键的表(6)选择发布名称和描述(7)自定义发布属性 向导提供的选择:是 我将自定义数据筛选,启用匿名订阅和或其他自定义属性否 根据指定方式创建发布 (建议采用自定义的方式)(8)[下一步] 选择筛选发布的方式 (9)[下一步] 可以选择是否允许匿名订阅1)如果选择署名订阅,则需要在发布服务器上添加订阅服务器方法: [工具]->[复制]->[配置发布、订阅服务器和分发的属性]->[订阅服务器] 中添加否则在订阅服务器上请求订阅时会出现的提示:改发布不允许匿名订阅如果仍然需要匿名订阅则用以下解决办法 [企业管理器]->[复制]->[发布内容]->[属性]->[订阅选项] 选择允许匿名请求订阅2)如果选择匿名订阅,则配置订阅服务器时不会出现以上提示(10)[下一步] 设置快照 代理程序调度(11)[下一步] 完成配置当完成出版物的创建后创建出版物的数据库也就变成了一个共享数据库有数据 srv1.库名..author有字段:id,name,phone, srv2.库名..author有字段:id,name,telphone,adress 要求: srv1.库名..author增加记录则srv1.库名..author记录增加 srv1.库名..author的phone字段更新,则srv1.库名..author对应字段telphone更新 –*/ –大致的处理步骤 –1.在 srv1 上创建连接服务器,以便在 srv1 中操作 srv2,实现同步 exec sp_addlinkedserver ‘srv2′,”,’SQLOLEDB’,’srv2的sql实例名或ip’ exec sp_addlinkedsrvlogin ‘srv2′,’false’,null,’用户名’,’密码’ go–2.在 srv1 和 srv2 这两台电脑中,启动 msdtc(分布式事务处理服务),并且设置为自动启动。我的电脑–控制面板–管理工具–服务–右键 Distributed Transaction Coordinator–属性–启动–并将启动类型设置为自动启动 go –然后创建一个作业定时调用上面的同步处理存储过程就行了 企业管理器 –管理 –SQL Server代理 –右键作业 –新建作业 –“常规”项中输入作业名称 –“步骤”项 –新建 –“步骤名”中输入步骤名 –“类型”中选择”Transact-SQL 脚本(TSQL)” –“数据库”选择执行命令的数据库 –“命令”中输入要执行的语句: exec p_process –确定 –“调度”项 –新建调度 –“名称”中输入调度名称 –“调度类型”中选择你的作业执行安排 –如果选择”反复出现” –点”更改”来设置你的时间安排 然后将SQL Agent服务启动,并设置为自动启动,否则你的作业不会被执行 设置方法: 我的电脑–控制面板–管理工具–服务–右键 SQLSERVERAGENT–属性–启动类型–选择”自动启动”–确定. –3.实现同步处理的方法2,定时同步 –在srv1中创建如下的同步处理存储过程 create proc p_process as –更新修改过的数据 update b set name=i.name,telphone=i.telphone from srv2.库名.dbo.author b,author i where b.id=i.id and(b.name i.name or b.telphone i.telphone) –插入新增的数据 insert srv2.库名.dbo.author(id,name,telphone) select id,name,telphone from author i where not exists( select * from srv2.库名.dbo.author where id=i.id) –删除已经删除的数据(如果需要的话) delete b from srv2.库名.dbo.author b where not exists( select * from author where id=b.id)go

哪些进程是苹果系统的。What Are All Those Processes?

最近服务器出现问题,为了查找特殊软件,只有在进程里面找端倪了,为了弄清楚什么是苹果的,什么是后来加上去的,只有查找了,把下面的表放在这,一个是可以学习,另外可以排除苹果的进程。

ystem Processes (mostly owned by root):

Process Its function
AppleFileServer The personal file sharing (AFP over IP) server. It should only be present if file sharing is enabled (in the System Preferences’ Sharing pane).
autodiskmount Responsible for mounting removable disks and media.
automount Automatically mounts and unmounts network (NFS and AFP) file systems as they are accessed / left idle.
configd Maintains dynamic configuration information about the computer and its environment (mainly the network).
CrashReporter Logs information about program crashes. It can be configured (via editing /etc/hostconfig in OS X 10.0, and the Console utility’s preferences on OS X 10.1) to log crashes in ~/Library/Logs.
cron Runs various scheduled programs and scripts, mostly to perform perodic maintenance on the computer. Note: in Mac OS X, this is set to run system maintenance late at night; if the computer is turned off every night, the maintenance may never get done. Either leave the computer on overnight occasionally, or use something like Brian R. Hill’s program MacJanitor to perform maintenance manually. In Mac OS X 10.4 it was mostly replaced by launchd, but is kept around for compatibility.
DirectoryService This process acts as a central clearinghouse for “Directory” information — mainly users/groups/authentication, and service location (e.g. file servers, printers, etc). It gathers information from a variety of plugins (NetInfo, LDAP, Active Directory, NIS, Bonjour/Rendesvous/, AppleTalk, SMB) and hands it out to whatever program requested it.
DesktopDB Keeps track of information on currently known applications and their document types. Used by the Finder to associate documents with the appropriate application.
distnoted Provides distributed notifications services.
dynamic_pager Assists the kernel with managing swap files for virtual memory.
ftpd Handles incoming FTP (File Transfer Protocol) connections. This process is created dynamically by xinetd (or inetd in earlier versions of OS X), so it should only appear when someone is actually connected to your computer.
httpd This is Apache, the web server that ships with OS X. It should only be present if web sharing is enabled (in the System Preferences’ Sharing pane). It is normal for there to be several of these running, one owned by root, the rest by www.
init (10.0-10.3 only)
The master of the computer from the BSD/unix point of view. This is responsible for creating (via the /etc/rc* scripts and StartupItems) and looking after many of the other background processes. In Mac OS X 10.4 it was replaced by launchd.
inetd (10.0-10.3 only)
Responsible for starting and looking after some internet services (mainly FTP and telnet) provided by this computer. As of version 10.2 this was functionally replaced by xinetd (which was then replaced by launchd), but was kept around through Mac OS X 10.3 for compatibility.
ipconfigd (10.0-10.1.1 only)
Automatically configures the network. Now merged into configd (since OS X 10.1.2, if I’m reading right).
KernelEventAgent Handles notifications about file system status (e.g. “A server you are using is no longer available. Do you want to continue trying to contact it?” and “Your startup disk is almost full. You need to make more space available on your startup disk by deleting files.”)
kextd Responsible for loading and unloading kernel extensions (e.g. device drivers) as they are needed.
launchd (v10.4 and later)
This process replaces init and mach_init, and takes over most of the functions of cron and xinetd.
lookupd Handles looking up information from network information services such as NetInfo and DNS, and acts as a bridge to allow unix/BSD/posix programs to get information from DirectoryService.
mach_init (10.0-10.3 only)
The Mach kernel’s bootstrap port server. This is the first process created during bootup, and creates the BSD init process (which then creates everything else). In Mac OS X 10.3, it’s also used to create several daemons that used to be created via StartupItems. In Mac OS X 10.4, it’s replaced by launchd.
mDNSResponder The multicast DNS (a component of Bonjour/Rendezvous) responder; this advertises network services (such as AFP file sharing) provided by this computer, as well as the computer’s self-chosen “.local” name.
Note: this runs under the pseudo-user “nobody” (presumably for security reasons).
netinfod Serves out NetInfo data. There will be one of these processes for each NetInfo domain served from the computer (normally just one, for the local domain). ProcessViewer/Activity Monitor won’t tell you which daemon process serves which NetInfo domain, but the ps command will.
nfsiod Services asynchronous requests to an NFS server. It is normal for there to be several of these.
nibindd Finds, creates, and destroys NetInfo servers (i.e. netinfod). This process will only exist if you have something beyond the standard local NetInfo domain set up.
notifyd Passes event notifications between processes.
ntpd Synchronizes the Mac’s clock with network time servers.
pitond The Retrospect backup client (only present if you’ve installed Retrospect Client).
pmTool This is actually a user process that happens to run as root. Activity Monitor uses it to collect information on running processes.
portmap Dynamically assigns RPC (network Remote Procedure Call) services (such as NetInfo and NFS) to TCP/UDP ports.
slpd The Service Location Protocol (SLP) responder; this advertises network services (such as AFP file sharing) provided by this computer. SLP has been functionally replaced by Bonjour/Rendezvous, but is kept active for compatibility with older computers on the network.
slpdLoad This process frequently shows up as a Zombie in ProcessViewer’s listing (with semirandom owner, parent, and statistics) under early versions of OS X. Don’t worry, it’s harmless, just a little confused.
(More technically: a zombie process is one that has finished (i.e. died), but whose parent process has not received notification of its death. In order to keep process information around until the parent process is notified, the zombie’s entry is left in the process table even though the process itself is gone. A bit morbid, perhaps, but since it doesn’t consume resources, it’s not really a problem.)
sshd The secure shell server — listens for and handles incoming SSH (encrypted remote login) connections. It was added in version 10.0.1 and should only be present if “Allow remote login” is enabled (in the System Preferences’ Sharing pane).
Note: In 10.3, sshd no longer runs continuously to listen for incoming ssh connections. Instead, xinetd (v10.3) or launchd (v10.4) does the listening, and only starts sshd when it’s actually needed.
syslogd Logs and/or dispatches system status and error messages.
telnetd Handles incoming telnet (remote login) connections. It’s enabled by the “Allow remote login” option in the System Preferences’ Sharing pane of Mac OS X 10.0; in later versions it’s disbled, and SSH is used instead (although telnetd can be reenabled manually by editing the /etc/inetd.conf file). This process is created dynamically by inetd, so it should only appear when someone is actually telnetted into your computer.
update Responsible for keeping disks synchronized with the file system cache, to keep data loss to a minimum in case of a crash.
xinetd Responsible for starting and looking after some internet services (mainly ssh, FTP and telnet) provided by this computer. This is essentially an extended version of inetd. In Mac OS X 10.4 it was mostly replaced bylaunchd, but is kept around for compatibility.

User processes (generally owned by the current user):

Process Its function
ATSServer The Apple Type Solution Server; responsible for managing the available fonts and making them available to applications.
Dock Maintains and displays the Dock.
DocklingServer Keeps docklings’ status and displays up to date.
Finder The Finder.
hdid Handles mounted disk image (.img and .dmg) files.
LaunchCFMApp Applications in the old-style Macintosh format (Code Fragment Manager format, aka CFM, aka PEF) will show up in Process Viewer under this name. LaunchCFMApp is actually a wrapper program provided for compatibility with this old application format; Process Viewer just can’t see through the wrapper to the actual application inside.
(Note: the distinction between the old (CFM) and new (mach-o) formats is not the same as the distinction betweem the old (Carbon) and new (Cocoa) application environments. Many of the Carbon apps you’re likely to run into on OS X are in mach-o format.)
loginwindow This is only partly a user process — it starts before anyone logs into the computer, and is responsible for displaying the login screen (or not, if autologin is set), validating login attempts, and setting up the user environment (launching the Finder, Dock, any login apps, etc) at login. It also acts as a process monitor for user processes, restarts the Finder or Dock if they crash, and implements the Force Quit Applications window. Finally, it handles the logout, restart, and shutdown procedures.
pbs The pasteboard server; analogous to the clipboard under Mac OS 9.
pmTool a background process that Activity Monitor uses to collect information on running processes.
Note that this process runs as root (despite being part of a user-level program).
SystemUIServer (OS X 10.1 and later)
Maintains the Menu Items in the right end of the menu bar.
TruBlueEnvironment
or “(null)”
The Classic (OS 9 compatibility) environment. This single process includes OS 9 and all running classic applications. The name derives from an early Apple code-name for the Classic environment: “the Blue Box”.
For some reason, Activity Monitor (under Mac OS X v10.3) has trouble reading this process’s name, and tends to display it as “(null)”.
WindowServer (aka Window Manager) Responsible for managing the computer’s display and mediating between the various Applications and other processes that want to display information on it. It also does the grunt work of launching new user applications, so most user processes are actually its children in the process hierarchy.

IT创业失败案例解析 – 第二篇

前段时间我们关闭了Overto公司,这是一家我参与的创业公司。从公司停业便不难看出这是一次失败的创业经历。 因为我们从失败中学到了很多,我认为对创业失败做一个可靠性分析对您应该有用。希望大家不要重蹈我们的覆辙。

 

没人全职工作

从公司成立初期,我们发现没有一位创始人愿意辞职,来全身心地投入到新公司的运作中。当时,我们以为自己能够在工作之余运营网络服务。在某种程度上, 的确如此。 只要服务器和程序没有什么大问题就万事大吉。一有足够的空闲时间,我们就会忙着开发新功能。可是自从那次我们的基础设施出了故障,问题便接踵而至。我们无 法抽出时间来解决问题,服务器也因此有多次宕机。这毫无疑问影响了用户体验。由于我们不得不把注意力集中放在解决当前问题,而不是增加新功能上,所以服务 /功能开发也受到阻碍。缺少从事维护和错误修正工作的全职人员是这次失败的主要原因。

把握市场脉搏

这是前面提到的原因所引发的部分后果。由于我们把有限时间中的大部分时间放在了服务运营维护上,因而我们也没能抓住瞬息万变的市场脉搏。我们原本需要 扩展新领域,以把应用程序提升到另一个层次,可结果我们甚至连当前的开发任务都没完成。整个项目就这样在测试版本中夭折了,而对用户来说项目没有丝毫变 化。

缺乏营销技能

处于互联网服务生和死之间的细线是用户。在一开始的时候,用户数量系统地增长。后来我们毫不费力就达到顶峰。这时候是该做些营销推广了。不幸的是,我们之中没有一个人在营销领域内有经验,更糟糕的是,我们都没有足够时间去弥补这一缺失。

商业模式

公司成立之初,我们就没有好好检视我们的商业模式。 并且有几个功能没能达到我们最初设想的效果。 颇有讽刺意味的是,那还不是最麻烦的问题,因为我们已经有了一堆新形势下调整战略的想法。 总之,你应该计划好适时改变最初的商业模式。

错失出售公司的机会

在确定无法长期维持运营之后,我们曾一度有机会将公司转让。 长话短说,一开始我们要价过高,导致谈判失败。 我们过多地考虑自己在它身上的投入,而忽略了它在潜在买主眼中的价值。 不论你为了某件东西付出多少心血,它的最终价值取决于买家的出价。

最终决定 拖延太久

我认为在这点上我们有点感情用事。 毕竟它就像我们的孩子一样,要在马上关闭公司和减少损失之间做出一个决定,的确让我们很纠结。我们一直自欺欺人地想一切都会好转,然而我们已经无力让它再正常运作了。

成立公司的幕后故事

在波兰,成立一家公司需要相当大的努力,不过当初看来,这确实是一个好想法。 所有创始人都是熟人,所以做决策时,不用担心缺乏信任。我们只是想给自己一点动力,使它成为一个真正的公司。而我们始料未及的是,通过展示公司的细节,我 们获得大量信誉。而不是让人们觉得,这公司就是由几位学生在假期做的,将来得不到任何支持。虽然让人们看清某一服务后面的公司并不能保证你能生存下去,但 至少还是会有人关心你的。

起步之前长时间讨论

在启动项目之前,关于计划做什么和如何做,我们进行了相当长时间的讨论。当然我们没有面面俱到,但是当我拿Overto跟其他创业公司对比之后,我发现,我们在成立初期的考虑很周全。

经验丰富

我们的确有一批精英来运营网络服务。开发、管理和用户支持——我们过去在这些领域上都很有经验。几乎没有什么能难倒我们。在我们应用程序所涉及的任何技术方面,我们不需要去寻求其他专家的帮助。

要在相同地点工作

有一段时间,我们在同一个办公楼工作,这极大有助于决策制定。 如果需要讨论某些重要的事情,我们可以随时见面。 但不久之后,我们分别在不同的地点工作,也正是那时,我们知道了在同一间办公室工作有多重要。

尽管当初为了这个项目我们投资了一些钱,但我认为这不是一种损失。 和我所学到的经验相比,这不算什么。如果我打算再次接触同类项目时,成功的机会会更大。

 

IT创业失败案例解析 – 第一篇

创业启示录:创业失败报告这个系列包括30多家创业公司的失败案例分析。本文就有由其中一家IT创业公司的CTO所撰写。还是那句老话,成功的故事固然非常鼓舞人心,但我们也可以从失败故事中学到很多。以下是译文。

在互联网泡沫破灭时期,我和朋友一起成立了一家软件公司,我自己担任CTO一职。我们开发了一款知识管理软件,包含了博客、Wiki、文档管理系统、链接管理和技能管理等。

我们在1999年开始创业,当时基本没有其他人做Wiki和博客,我们算很早的。(Moveable Type是成立于2001年)。链接管理系统本质上和后来的Delicious一样。除了那些新特性(至少是在1999年)之外,还有如下三大特性:

  • 1. 所有东西都可以添加标签。技能、人、链接、文档、博文、wiki和今天的分众分类法。标签之间可以连接以来构成实体。标签也可以链到其他文档、博文和人;
  • 2. 所有东西都可以评分(1-5 五个等级);
  • 3. 基于标签和评分,我们做了一个灵巧的模糊搜索。比如,如果你的团队需要Oracle大师,在搜索“Oracle大师”时,也会返回精通SQL Server的专家。

我们从VC那得到一笔种子投资资金,我们非常高兴并成功开发我们的程序。在向很多用户展示(程序)后,我们收到了来自大公司的有利反馈。但我们的创业 为什么失败了呢?我并没有成为百万富翁?其中有太多的原因,但正如我在《成功商业规则》一文中所说,成功的商业规则很简单:

  • 1. 客户是你公司的头等大事;
  • 2. 最佳商业计划是:卖客户所需的产品;
  • 3. 如果你的收入高于支出,那你的公司就成功了。

对企业来说,重中之重的事情就是卖出产品。但事实上,很多创业公司都忘记了,包括我们。左思右想后,我们得出为什么失败的6个原因(由于VC市场崩溃,在我们需要资金的时候,无人能资助一毛钱。这个明显原因除外。):

  • 1. 我们没有卖出任何东西;
  • 2. 我们没有卖出任何东西;
  • 3. 我们没有卖出任何东西;
  • 4. 市场大门尚未开启;
  • 5. 我们过于注重技术;
  • 6. 我们的商业模式错误;

详细解析:

一、我们没有卖出任何东西(第一部分)

我们之所以没有卖出任何东西,是因为我们没有产品可卖。我们一直在招优秀的工程师,一直等到产品做完。产品完成后,我们才开始销售。我们曾在中途时出 售产品,不过是接近1.0的版本。这一举措导致过多注意力放在开发上,没有充分关注产品销售。因为没有一个完成产品,我们认为无法推向客户。我们慢慢学到 两件事:

  • 1. 如果你的产品是软件,并非一定等产品完成之后才开始出售。和管理层之间的第一场销售会议,完全可以用截图、模型和幻灯片想管理层展示。对我们的客户而言, 如果产品完全是陌生的,我们首先必须使客户明白那些概念(wiki、博客和标签)。没有成品,这完全就可以做到。
  • 2. 成立公司之前就开始做销售工作。现在就开始!你没有必要成立公司之后才开始向客户出售新事物。现在就开始!当人们真正需要买你的产品时,开始组建公司吧。

二、我们没有卖出任何东西(第二部分)

我们之所以没有卖出任何东西,是因为我们没有销售人员。真失败!当然了,我们一直在寻找合适的销售人员。商业计划上说:寻找销售的最好方法是组建销售 团队。组建团队费时又耗力,并且我们根本没时间和相应资源。如果你想出售产品,找一个销售当合作伙伴,或者一开始就雇佣销售。

三、我们没有卖出任何东西(第三部分)

我们之所以没有卖出任何东西,是因为客户不会买。虽然我们产品很优秀,用户也喜欢,但用户决定购买的时间太漫长了。“(潜在客户公司的)底层 -> 产品经理 -> 整个公司”,我们想通过这样的流程来出售产品。但每每一听说产品是知识管理软件,每位高管都决定放到他的工作日程中,而不是立即决定是否购买。所以,知识 管理软件进入命令传达链条中,并没有真正的决策人。

我们在非相关的人身上浪费太多的时间了,我们应当直接找决策人。在我们的销售对象中,有一些大公司,我也确认他们最后会买,但我们创业公司不能等啊。比如,和我们产品对比而言,SAP有时间等待,甚至可以等一年。卖企业软件需要耗费很多时间。

四、市场大门尚未开启

市场大门尚未开启。当时没人听说过博客、wiki和标签。我们不得不向客户解释wiki的好处(每个人都可以编辑!每个人!),博客的好处(每个人都可以发表观点!每个人!)和标签的好处。如果是几年之后,出售博客、wiki和标签平台会更容易。

五、我们过于注重技术

所有的创始人都沉迷于技术。我们使用的是EJB(EJB那时候还不是很成熟),我们把所有的东西输出为XML,然后用XSLT把XML转化为 HTML(转化速度还不够快),编写自己的OR映射器 – 多么愚蠢的想法(当时还没有Hibernate),尝试CSS驱动网站(那时候也没用相关知识)。这导致代码重写,这耗费我们大量时间。我们向客户之间的 技术讨论也同样费时,讨论结果令人沮丧。(编者注:为什么要和客户讨论开发技术呢?有必要吗?)

六、我们的商业模式错误

简而言之:我们的商业模式错误。卖出软件最终能收获不少钱,但这需要时间。在没有进账的情况下,我们有前期成本,达成出售交易耗时不短并且一直在烧钱。

更好的模式应当是:做知识管理相关的咨询,并以开源产品开头。

我们的确向某些公司咨询过如何做知识管理和如何使用wiki等。但我们根本没在咨询商花一分钱,因为这是我们销售计划的一部分。关注咨询和收费人群将带来稳定收入。

我后来的确涉入开源,并做了一个开源产品SnipSnap。SnipSnap采用(一小部分)创业点子(仅wiki和博客)。很多人下载并安装了这款 软件。我们真正简化SnipSnap的安装,故它才能快速传播。我曾和一家非常大的软件咨询公司的老板讨论过,他告诉我,他们根本用不上wiki,因为它 太乱,结构性不好。呵呵,事实上我知道他公司的好几台电脑都安装了SnipSnap。正如其他人现在所做的一样,我们也可以从开源项目开始,然后基于它再 提供付费支持和企业级功能。后来有公司付费给我们,要求在SnipSnap中添加新功能,使其和其他公司抗衡。但是在1999年,我们对商业模式的了解, 远没有现在这么多。

你能从我的失误中学到什么呢?

在软件管理、产品、商业模式、资金和做CTO这些方面,我已经学到了很多。你能从我的失误中学到什么呢?有一点可以肯定:尽早考虑销售、尽快销售出公司的服务或产品。

感谢你能耐心看完。

 

平面设计师的10款搜索利器

作为平面设计师经常需要寻找很多各种各样的素材,例如标志、图标、矢量图片、材质和字体等。这些对于设计师而言都是很重要的资源,因为不是每一样东西都要我们自己做出来的,开始一个方案之前总是先要搜索一番。今天我们为大家分享10款平面资源的搜索利器,以便助能够助你一臂之力,达到事半功倍的效果。


1) Iconlet

2) Vector Stock

3) Font Stock

4) Vectorials

5) Logopond

6) Icon Seeker

7) Free Fonts

8 ) Veryicon

9) daFont

10) Logofury

 

转载自:http://www.fisherv.com

Joel Spolsky在耶鲁大学的演讲

Joel Spolsky是一个美国的软件工程师,他的网络日志“Joel谈软件”(Joel on Software)非常有名,读者人数可以排进全世界前100名。

上个月28号,他回到母校耶鲁大学,与计算机系的学生座谈。他发表了一个演讲,回顾自己的人生经历,并总结了一些个人的体会。

我读完他的演讲稿,很受触动,觉得他的人生体会非常具有启示性。这篇演讲非常长,分为三个部分()。我没有时间全文翻译,就摘录一些精彩的段落,一共有四段。

大学里最有用的课程

Joel说,他在大学里上过的最有用的课,是一门他只上了一回,然后就再也没有去过的课。

由于父母都是大学教授,亲戚朋友都是学术界里的,大多有博士学位,所以Joel从小就认定自己也会去读博士,将来搞学术。可是,有一门课程改变了他的想法,使他最终没有去报考研究生院。

这门课程叫做“动态逻辑”(Dynamic Logic)。在第一堂课上,教授证明了一个命题。假定有一个程序“f := not f,”
f是表示真假的逻辑值,那么结论是程序运行偶数次后,f的值保持不变。整个证明过程非常冗长,要花几个小时讲解,一共有几十步。课后习题则是,证明如果f
值保持不变,那么程序必然运行了偶数次。

课后,Joel花了很多时间做题,还去图书馆借来了参考书。但是,他逐渐感到这样做没有意义:用大量琐碎的、容易出错的步骤,去证明一个凭直觉就能
认定成立的命题,这不是一个富有实效的工作方法。在Joel看来,计算机更应该用来解决错误,而不是让人们陷入逻辑的陷阱,去产生错误。(I
decided that this Dynamic Logic stuff was really not a fruitful way of
proving things about actual, interesting computer programs, because
you’re more likely to make a mistake in the proof than you are to make
a mistake in your own
intuition.)通过这件事,他认识到,自己不适合做纯思辨性的学术研究。因此,他就退掉了这门课,并且以后也没有选择去上研究生院。

Joel认为,就是这门只上了一次的课,恰恰成为了他在大学中上过的最有用的课,因为它帮助他选择了正确的人生道路。

所以,Joel的第一个结论是:人生中重要的是,关注那些真正的问题(real problem),不要陷入那些细枝末节的问题(trivial problem)。就像苏格拉底说的,“认识你自己”。

此外,Joel说,还有一门叫做CS 323的课,也很有用。这门课有大量的课后习题,都是关于编程的,平均每星期要花40个小时来做题。

Joel发现他能够做出大部分的题目,更重要的是,他发现自己喜欢做这些题。这样一来,他就明白自己是适合编程的。另一方面,很多其他学生对这门课
感到无比头疼,觉得编程既枯燥又痛苦,每周40小时做这种题简直是一种刑罚。这些人于是明白,虽然同样是计算机系的学生,但是他们并不适合编程。这是一件
好事,因为这样他们就避免了以后选择错误的职业。否则,让一个不喜欢编程的人,一生都与程序打交道,这是多么悲惨的一件事啊!

在Viacom的日子

毕业以后,Joel先在微软公司干了一段日子,然后回到纽约,进入维亚康母公司(Viacom),为这家巨型的娱乐传播公司编写软件,成为IT部门里一个程序员(in-house programmer)。

后来,Joel回忆起来,认为这是他一生中最痛苦的日子,并且劝告计算机系的学生尽可能不要去做“in-house programmer”。

原因有三个。

首先,你永远没有办法正确地编写软件,你不得不用最方便的方法编写软件。因为软件支出非常高昂,所以公司会要求尽可能节省成本,你不可能试用新技术,只能使用现有的最成熟、最保守的技术。

其次,你没有办法将一个项目做到尽善尽美。一旦程序可以正常运行,你的工作也就结束了,可以接下去干公司的下一个项目了。你的作用是解决问题,而不
是将软件写得尽可能好。如果你是在一个专业的技术性公司,比如Google或Facebook,情况就完全不一样,你的软件写得越好,公司就会越成功,所
以公司会支持你在一个项目上不断做下去。

最后,传统公司IT部门里的程序员,只属于公司内部的维护人员,而不是直接从事核心业务的人员。因此,你永远办法进入管理层。但是,在技术性公司,程序员会变成CEO。

因为这三个原因,Joel觉得in-house
programmer不是一个好的职业,不幸的是,80%的程序员属于这一类,年复一年,很多人的生命就是这样被耗干的。(it’s
frightening because this is what probably 80% of programming jobs are
like, and if you’re not very, very careful when you graduate, you might
find yourself working on in-house software, by accident, and let me
tell you, it can drain the life out of you.)

Joel的第二个结论是:选择职业时,不要只考虑职位是否专业对口,应该尽量选择业务方向与你专业相同的公司。

虽然,维亚康母公司(Viacom)口头表示很重视互联网,但是,分配给程序员的工作间,总是很小的屋子,光线黯淡,而且还用搁板分割出小间,供三个人使用。经理们各自的办公室则完全不同,都有大玻璃窗,可以俯视哈德逊河。

在一次公司内部的圣诞晚会上,Joel见到了负责互联网战略的执行董事。Joel问他,公司打算怎么使用互联网,后者只是泛泛地说,互联网很重要,
这是未来的发展方向。Joel感到很失望,他相信这个执行董事其实对互联网毫无认识,只不过是人云亦云。说到底,这个董事对这一切可能根本无所谓,反正他
每年都有200万美元的年薪,保持现状就是最好。对他来说,Joel就是一个打字员似的“写网页的人”,Joel做了什么和工作中的付出,他并不关
心。(It convinced me that he had no flipping idea whatsoever what it was
that was happening and what the internet meant or what I did as a
programmer, and he was a little bit scared of it all, but who cares,
because he’s making 2 million dollars a year and I’m just a typist or
“HTML operator” or whatever it is that I did, how hard can it be, his
teenage daughter can do that.)

所以,Joel决定辞职了。

管理人员的作用

离开维亚康母以后,Joel进了一家叫做Juno Online Services的互联网公司,这家公司提供网上免费电子邮件服务。那个时候是90年代中期,hotmail和gmail都还没有成立。

作为程序员,Joel在这里工作得很愉快,但是公司本身的经营却不成功。虽然是一家互联网公司,但是,Juno Online
Services完全采用传统的“从上至下”的管理方式,就是领导想出来一个主意,然后命令程序员负责实现,结果就是对技术细节一无所知的人,决定了一
切。

这同硅谷的方式完全不同,在那里,管理人员只负责创造一个良好的工作环境,然后让真正的聪明人把东西做出来。(What I was used
to from the west coast was an attitude that management is just an
annoying, mundane chore someone has to do so that the smart people can
get their work done.)硅谷公司内部的运作更像大学里的学术讨论会,会议主席的作用只是主持会议而已。

Joel的第三个结论是,公司管理层的作用就是搬动家具、清理出空间,让有才华的研究人员做出一流产品。(Managers
exist to get furniture out of the way so the real talent can do
brilliant work.)

Juno Online Services经营得不成功,以及对员工才华的不尊重,使得Joel在2000年下定决心,不再为别人打工了,开始创业。

表达能力的重要性

在创业之初,Joel并不知道该去做什么。他看到许多很蠢的人,拿着很蠢的商业计划,开办互联网公司。他想,这样的公司都能开出来,那么我也能开公
司,只要我比他们少蠢10%就可以了,我要按照我的想法来管理,对每一个程序员都给予最大的尊重,那样就有机会做出高质量的产品。我们不关心风险资本家怎
么说,也没有高高在上的领导,我们只关心客户的感受,用软件解决客户的问题,从而获得报酬,生存下去。(In those days, I was
seeing lots of really dumb people with really dumb business plans
making internet companies, and I thought, hey, if I can be, say, 10%
less dumb than them, that should be easy, maybe I can make a company
too, and in my company, we’d do things right for a change.) We’d treat
programmers with respect, we’d make high quality products, we wouldn’t
take any shit from VCs or 24-year-olds playing President, we’d care
about our customers and solve their problems when they called, instead
of blaming everything on Microsoft, and we’d let our customers decide
whether or not to pay us.)

在这种想法的鼓励下,Joel创办了Fog Creek软件公司。

从创业之初,Joel就开始将自己的想法和遇到的事情,写成文章,发表在互联网上。当时还没有Blog这种东西,但是他其实已经在写了。Joel慢
慢发现,他的文章真的有人看,并且读者越来越多,其中很多人最终都接受了他的想法。实际上,Joel写的很多东西都不是原创性的,其中还时不时包括一些笑
话,但是读者不在乎,“Joel谈软件”成了一个热门网站,平均每篇文章都有几十万、甚至上百万的读者。

这对Joel的创业帮助极大,Fog Creek本来是一家无名的小软件公司,但是由于很多人读Joel的文章,因此他们也了解并且相信Joel的公司。这使得Fog Creek从创业的第一年起就是盈利的,并且每年都在发展。

Joel将创业的成功,部分归功于他在大学里受过的写作训练,那时有一个教授每周都要布置写论文,并且对平庸的文章恨之入骨,不给学分。这使得Joel学会了将复杂的话题说得清晰易懂,并且引人入胜。

因此,Joel的第四个结论是,一个普通工作人员和一个领袖之间的差别,就是有没有良好的表达能力。(Being
able to write clearly on technical topics is the difference between
being a grunt individual contributor programmer and being a leader.)

IT人和管理者的最大分别

有一个迷路的人正向对面走来的一位路人问路道:“对不起!请问这儿是哪里?”
“你现在正在一条分岔路上,”路人说。
“先生,我猜你一定是从事IT行业的。”迷路人道。
“对啊!你为什么会知道?”
“因为你给我的答复很技术性,但完全没有用?”
“先生,我也猜猜你的职业吧!你一定是做管理的。”路人说。
“对呀!你为什么也能知道?”
“因为你不知自己在哪?也不知自己应往哪儿走,但你却希望我帮你解决问题,你现在的处境和先前没有两样,但责任已归咎在我身上!”