显示标签为“Oracle/PLSQL”的博文。显示所有博文
显示标签为“Oracle/PLSQL”的博文。显示所有博文

星期三, 八月 12, 2009

GROUP BY, HAVING, SUM, AVG, and COUNT(*) 转载

Welcome to the Database Programmer!

Good programming skills do not lead magically to good database skills. Masterful use of the database requires knowledge of the database in its own terms. Step 1 is knowing your table design patterns, and Step 2 is knowing how to fashion efficient queries. Learning how to code good queries can lead to faster performance and better application code.

There is a new entry in this series every Monday morning, and the Complete Table of Contents is here.

Aggregation

You can use a SQL SELECT to aggregate data. Aggregation combines rows together and performs some operation on their combined values. Very common aggregations are COUNT, SUM, and AVG.

The simplest use of aggregations is to examine an entire table and pull out only the aggregations, with no other columns specified. Consider this SQL:

SELECT COUNT(*) as cnt       ,SUM(sale_amount) as sum       ,AVG(sale_amount) as avg   FROM orders 

If you have a very small sales order table, say about 7 rows, like this:

ORDER |  DATE      | STATE | SALE_AMOUNT ------+------------+-------+-------------  1234 | 2007-11-01 | NY    |       10.00  1235 | 2007-12-01 | TX    |       15.00  1236 | 2008-01-01 | CA    |       20.00  1237 | 2008-02-01 | TX    |       25.00  1238 | 2008-03-01 | CA    |       30.00  1237 | 2008-04-01 | NY    |       35.00  1238 | 2008-05-01 | NY    |       40.00 

Then the simple query above produces a one-row output:

CNT  | SUM  | AVG -----+------+-----   7  | 175  |  25 

Some Notes on The Syntax

When we use COUNT(*) we always put the asterisk inside.

I have used the "as SUM" to specify a column name of the output. Without that I will get whatever the database server decides to call it, which will vary from platform to platform, so it is a good idea to learn to use the "AS" clause. Some folks would frown at using "SUM" as the name, since that is the name of the function and might be confusing, but I think we're all big kids and we can probably handle it.

The WHERE Clause Does What You Think

If you want to get just the sales from New York state, you can put a WHERE clause in:

SELECT COUNT(*) as cnt       ,SUM(sale_amount) as sum       ,AVG(sale_amount) as avg   FROM orders  WHERE state = 'NY' 

...and you will get only the results for NY:

CNT | SUM  | AVG ----+------+----------   3 |  85  |  28.33333 

Notice of course that the average has a repeating decimal. Most databases have a ROUND function of some sort, so I can correct that with:

SELECT COUNT(*) as cnt       ,SUM(sale_amount) as sum       ,ROUND(AVG(sale_amount),0) as avg   FROM orders  WHERE state = 'NY' 

The Fun Begins With GROUP BY

The query above is fine, but it would be very laborious if you had to issue the query (or write a program to do it) for every possible state. The answer is the GROUP BY clause. The GROUP BY clause says that the aggregations should be performed for the distinct values of a column or columns. It looks like this:

SELECT state,       ,COUNT(*) as cnt       ,SUM(sale_amount) as sum       ,ROUND(AVG(sale_amount),0) as avg   FROM orders  GROUP BY state 

Which gives us this result:

STATE | CNT | SUM  | AVG ------+-----+------+---- NY    |  3  |  85  |  28 TX    |  2  |  40  |  20 CA    |  2  |  50  |  25   

Note that if you try to include a column that you are not grouping on, such as zip code, most database servers will reject the query because there may be different values of zip code for the same value of state, and they have no way to know which one to pick for a given value of state.

HAVING Clause is Like WHERE after GROUP BY

The HAVING clause lets us put a filter on the results after the aggregation has taken place. If your Sales Manager wants to know which states have an average sale amount of $25.00 or more. Now our query looks like this:

SELECT state,       ,COUNT(*) as cnt       ,SUM(sale_amount) as sum       ,ROUND(AVG(sale_amount),0) as avg   FROM orders  GROUP BY state HAVING AVG(sale_amount) >= 25 

Which gives us this result, notice that Texas is now missing, as they were just not selling big enough orders (sorry 'bout that Rhonda).

STATE | CNT | SUM  | AVG ------+-----+------+---- NY    |  3  |  85  |  28 CA    |  2  |  50  |  25   

The Hat Trick: All Three

You can pull some pretty nice results out of a database in a single query if you know how to combine the WHERE, GROUP BY, and HAVING. If you have ever worked with a Sales Manager, you know they constantly want to know strange numbers, so let's say our Sales Manager says, "Can you tell me the average order size by state for all orders greater than 20? And don't bother with any average less 30.00" We say, "Sure, don't walk away, I'll print it out right now."

SELECT state       ,COUNT(*)       ,SUM(sale_amount) as sum       ,ROUND(AVG(sale_amount) as avg   FROM orders  WHERE sale_amount > 20  GROUP BY state HAVING avg(sale_amount) >= 30 

How to Do a Weighted Average

Consider the case of a table that lists test, homework and quiz scores for the students in a certain course. Each particular score is worth a certain percentage of a student's grade, and the teacher wants the computer to calculate each student's file score. If the table looks like:

STUDENT     | WEIGHT | SCORE ------------+--------+------- NIRGALAI    |     40 |    90 NIRGALAI    |     35 |    95 NIRGALAI    |     25 |    85 JBOONE      |     40 |    80 JBOONE      |     35 |    95 JBOONE      |     25 |    70 PCLAYBORNE  |     40 |    70 PCLAYBORNE  |     35 |    80 PCLAYBORNE  |     25 |    90 

Then we can accomplish this in one pull like so:

SELECT student       ,SUM(weight * score) / 100 as final   FROM scores  GROUP BY student 

The nice thing about this query is that it works even if data is missing. If a student missed a test, they automatically get a zero averaged in.

Conclusion: Queries Are Where It's At

The only reason to put data into a database is to take it out again. The modern database has powerful strategies for ensuring the correctness of data going in (the primary key, foreign key and other constraints) and equally powerful tools for pulling the data back out.

Next Week: Joins Part Two, The Many Forms of JOIN

星期四, 七月 16, 2009

sqlldr 关键词详解

节录重要部分 详情请见:
http://camden-www.rutgers.edu/help/Documentation/Oracle/server.815/a67792/ch06.htm
sqlldr ... Valid Keywords:
userid -- Oracle username/password control -- Control file name log -- Log file name bad -- Bad file name data -- Data file name discard -- Discard file name discardmax -- Number of discards to allow (Default all) skip -- Number of logical records to skip (Default 0) load -- Number of logical records to load (Default all) errors -- Number of errors to allow (Default 50) rows -- Number of rows in conventional path bind array or between direct path data saves (Default: Conventional Path 64, Direct path all) bindsize -- Size of conventional path bind array in bytes (System-dependent default) silent -- Suppress messages during run (header, feedback, errors, discards, partitions, all) direct -- Use direct path (Default FALSE) parfile -- Parameter file: name of file that contains parameter specifications parallel -- Perform parallel load (Default FALSE) readsize -- Size (in bytes) of the read buffer file -- File to allocate extents from

Using Command-Line Keywords

Keywords are optionally separated by commas. They are entered in any order. Keywords are followed by valid arguments.

For example:

SQLLDR CONTROL=foo.ctl, LOG=bar.log, BAD=baz.bad, DATA=etc.dat     USERID=scott/tiger, ERRORS=999, LOAD=2000, DISCARD=toss.dis,    DISCARDMAX=5

星期二, 五月 26, 2009

HPUX上Oracle 11g client安装笔记

OS:HPUX
hardware:安腾CPU
安装对象:
Oracle 11.1.0.6 client
sqlldr,sqlplus
Oracle 11.1.0.7 patch

sqlldr和sqlplus安装后,文件在$ORACLE_HOME/bin 下面
runtime安装会自动包含sqlplus
sqlldr在custome安装下面的oracle database utilities组件里,有其他东西,据说蛮有用,都装了
admin安装会包含sqlldr

安装界面出来,welcome下面有一步Inventory Directory,是临时安装文件存放的地方。保持这个路径为空或者删掉最后一级路径都可以。每次安装oracle都会重新copy内容进去的。

sqlldr起不起来的原因:
1. /u01/app/oracle/product/11.1.0.6/client_1/bin 这个路径要有rrr权限
2. sqlldr文件要有xxx权限
3. ORACLE_HOME要设进.profile

查看是否安腾处理器方法:
machinfo(Itanium机器可用)或者 ioscan,dmesg,model(非Itanium机器)

用unix连接XWindow以显示图形界面:
1.打开软件ReflectionX或者Xwindow软件,不要任何设置或者连接
2.export DISPLAY=16.100.129.5:0.0(在unix上直接输入这段命令,红色部分填你的电脑IP,这样执行runInstaller的时候unix会去连你电脑上的ReflectionX)
3.在安装文件解压的路径下:
cd client 
./runInstaller -ignoreSysPrereqs
安装7patch的时候
cd Disk1
./runInstaller

星期日, 三月 29, 2009

oracle中繁体字显示成靠靠乱码

之前用sqlldr上传UTF-8的文件到oracle,里面是一些繁体字的数据,在TOAD和PLSQL developer里面都是显示靠靠靠靠。。。我还以为是数据文件问题,google发现很多人都有相关问题。
解决方法是修改注册表中Local Machine->Software->Oracle下Home0(数字零)里nlslang的设置。
我原先是AMERICAN_AMERICA.WE8MSWIN1252,所以显示靠靠靠靠。。。
修改成论坛里建议的AMERICAN_AMERICA.UTF8后,出现的是很奇怪和中文相似的乱码。
最后找了个能正确显示的同事的注册码信息,改成SIMPLIFIED CHINESE_CHINA.ZHS16GBK,就可以显示出繁体字了。

星期四, 三月 26, 2009

archive log space

今天遇到这个问题:
SQL*Loader-128: unable to begin a session
ORA-00257: archiver error. Connect internal only, until freed.
结果是archive log空间不够了。找DBA clear一下就行了。

星期三, 三月 25, 2009

zz Sqlldr的使用

http://blog.oracle.com.cn/index.php/266780/viewspace-26695

Sqlldr也就是SQL*LOADER,它是oracle的高速批量数据加载工具,可以将外部文件的数据导入到oracle数据库中。可以用于从多种平面文件格式向oracle数据库中加载数据。

它有两种操作模式:传统路径(conventional path):利用sql插入为我们加载的数据。直接路径(direct path):不使用sql,而是直接格式化数据库块。利用直接路径加载,能从一个平面文件读取数据,并将其直接写至格式化的数据库块,而绕过整个sql引擎和undo生成,同时还可能避开redo生成,要在一个没有任何数据的数据库中充分加载数据,这是最好的方法。

SQLLDR包括五个文件:控制文件(*.ctl)、数据文件(*.dat)、日志文件(*.log)、错误文件(*.bad)、废弃文件(*.dsc)

   其中我们最常用的为前四中:导入方式为:

Sqlldr userid=user/password@SID controlpath\xx.ctl log=path\xx.log bad=path\ xx.bad

注意SID就是数据库名,path就是路径名,不要加’’,一般不用加数据文件,因为在control就包含了数据或者数据路径,log是需要的,它可以告诉你导入的详细信息,而bad则存放者错误的文件,discard(废弃文件)则存放者不满足导入条件的数据。

控制文件它的作用是告诉oracle如何的读取和加载信息,并提供数据的路径,加载的方式以及加载的规则的。具体格式如下“

Load data

Infile‘数据路径’

Into table table_name

Truncate

Fields terminated by‘’

column_name1column_name2,······)

具体含义:1Load data的意义就是说载入数据2Infile‘数据路径’就是指明了载入数据的位置,其中数据默认的扩展名是.dat,我们也可以更改比如.txt.csv(逗号分割值形式)都可以,还有这里不仅可以导入数据文件,也可以导入错误文件或者废弃文件,格式如:badfilepath\xx.bad’或者discardfilepath\xx.dsc3Into table table_name把数据导入到的什么表,这里可以插入多个表,用when condition条件分割就可以了4Truncate它的含义是当sqlldr执行这个控制文件是,表在开始加载前就给截断了。用Truncate是不能回退的一定要谨慎,除此之外,还可以使用append(用于在表中增加行)、insert(用于在空表中增加行,如果不为空,加载就会错误)、replace(用于清空表,然后在增加新行,但是用户必须有该表的delete权限),前提注意,执行加载的用户必须具有表的insert权限,如果没有该参数,系统默认的为insert5Fields terminated by‘’数据的分割符,首先先要明白sqlldr加载数据我们常用的有两种装载定长数据和装载变长数据。例子如下:

装载定长数据

load data
infile ‘xx.txt’

into table table_name append

(column_name1 position(01:10) character,

column_name2 position(11:12) character,

column_name3 position(13:14) character,

column_name4 position(15:16) character,)

它是装载了未知固定好的数据。

装载定长数据

load data
infile ‘x.dat’

into table table_name append

(column_name1 char terminated by ‘ ‘,

column_name2 char terminated by ‘ ‘,

column_name3 char enclosed by ‘ ‘,

column_name4 char terminated by whitespace)

或者

load data
infile ‘x.dat’

into table table_name append

Fields terminated by“”

(column_name1,column_name2,····)

这里注意一下Fields terminated by‘’,里面的‘’表示分割符号,比如说‘/’、‘;’,也可以FIELDS TERMINATED BY X‘09’(制表符), FIELDS TERMINATED whitespace(空格)等等,还可以在后面加上OPTIONALLY ENCLOSED BY“”,它的意思实说每个选定的字段是用“”表示的。LINES TERMINATED\t‘ 表示每行记录之间用什么分隔默认的为\n(可以不加的)6、(column_name1column_name2,······)就是把数据加入到表中的哪些字段。7、还可以加一个选项trailing nullcols指没有的数据用NULL填充。

我们在看一个有选择条件的加载多个表方式

Load data

infile 'x.txt'

replace into table table1

when column_name = 'condition1'

(column_name1column_name2,····)

when column_name =condition2’

into table table2

(column_name1column_name2,····)

导入EXCEL,可以把EXCEL文件另存为CSV(逗号分隔)(*.csv),控制文件就改为用逗号分隔

LOAD DATA

INFILE 'x.csv'

APPEND INTO TABLE table

FIELDS TERMINATED BY ","

(column_name1, column_name2,····)

使用filler跳过在导入数据文本中不想进行导入的列。在控制文件中还可以使用concatenate语句将多个物理行合成一个逻辑行插入到表中,在文件中加注释是用――后根语句来注释的。理想的情况下我们加载数据都希望不是完全的成功就是完全的失败这样便于第二次加载,但是实际上往往是部分成功和部分失败,一次要利用日志文件判断出失败的地方,日志文件会记录提交点和错误产生点。所有被拒绝的记录保存在坏文件和废弃文件中,因此我们必须活用sqlldr的选现来实现数据的加载。

如果加载的数据过多,我们可以作一个.bat的批处理文件把所有的sqlldr加载语句放入其中,最后直接执行批处理文件就可以。

最后一个就是并行并发操作:比如

sqlldr userid=/ control=result1.ctl direct=true parallel=true
   sqlldr userid=/ control=result2.ctl direct=true parallel=true
   sqlldr userid=/ control=result2.ctl direct=true parallel=true
   
当加载大量数据时(大约超过10GB),最好抑制日志的产生:

SQL>ALTER TABLE RESULTXT nologging;

这样不产生REDO LOG,可以提高效率。然后在CONTROL文件中load data上面加一行:unrecoverable(不可恢复)此选项必须要与DIRECT共同应用。

因为sqlldr在加载数据时会产生大量的insert语句,因此使用direct path先格式化数据快,在把数据块快数插入表中。提高性能。使用了direct path就可以使用unrecoverable关键字提高数据加载性能。可以不必生成重做日志项。同时可以使用parallel direct path加载选项将数据加载工作分为多个进程。因此并行的direct path加载操作比单个的direct path加载效率快很多。

Sqlldr选项参考工作图中的sqlldr.jpg

另外还要注意一个使TRAILING NULLCOLS,因为在引导数据中,比如说你向往5列中引入数据,但数据每行只有4个,而第5列之前前四行之和,但是在处理中sqlldr会告诉你,没有等处理完所有的列,记录中就没有数据了。因此我们就必须使用TRAILING NULLCOLS,这样一来,如果数据记录中不存在某列的数据,sqlldr就会先为该列绑定一个null值,因此我们执行第5列之前,实际上它的值就使null,而不会报错了。(注意,在加载数据时可以使用sql连接运算符)

加载有内嵌换行符的数据,一种方法可以用非换行符的其他字符来表示换行符比如说在文本中应该出现换行符的位置上放上一个\n,并在加载时使用一个SQL函数用以chr10)来替换该文本。二种是使用FIX属性,但是这种方法,输入数据必须出现在定长记录中,每个记录与输入数据集中所有其他记录的长度都相同,既有相同的字节数。使用FIX属性,必须使用一个INFILE子句,因为FIXINFILE一个选项,而且,数据必须在外部存储,而并非存储在控制文件本身,如:INFILE TEST.DAT “FIX 80”指定一个输入数据文件,这个文件每个记录都有80个字节,包括尾部的换行符。在这种情况下,输入文件中提供给sqlldr的记录设置就以非\n结束的。第三种情况,可以使用VAR属性,这种格式,每个记录必须以某个固定的字节数开始,这标识这个记录的总长度。可以加载包含内嵌换行符的变长记录,但是每个记录的开始处必须有一个记录长度的字段。如:infile test.dakvar 3”这里指出了每个输入记录的前3个字节是该输入记录的长度。还有一种情况是使用STR属性,这算是最灵活的一种,可以指定一个新的行结束字符(或字符序列)。这样就能创建一个输入数据文件,其中每一行的最后有某个特殊字符,换行符不再有特殊含义。STR属性是以16进制指定的,因此要得到所需的具体16进制串,最容易的办法是使用SQLUTL_RAW来生成16进制串,可以直接导入在unix平台下的数据。总结一下:要注意在windowsunix两个平台的不同,结束符是不同的unxi上是\n,而windows上是\r\n\r是记录的一部分,控制文件必须适应这一点,比如,如果取一个.dat文件只包含\n当传输到windows上是,要将各个\n转换为\r\n。那么原来unix种的控制文件就不能记载数据了。

星期五, 三月 13, 2009

zz case语句两个常用用法

http://blog.csdn.net/zshengli/archive/2008/10/28/3166002.aspx
用法1:
case 字段 when '值1' then '结果1'
when '值2 'then '结果2'
else '结果3'
end
说明:这种用法跟C#的switch语句的功能有点相似,通过判断‘字段’不同值返回对应的‘结果’。
它在select语句中用得比较多,如:

select x,y,case z when '1' then '假' when '0' then '真' from table_v

这语句查询出来第三列会是无名列,可以这样为它取名:

select x,y,case z when '1' then '假' when '0' then '真' as 'new_z' from table_v


用法2:
case when 表达式1 then '结果1'
when 表达式2 then '结果2'
else '结果3'
end
说明:这也是很常用的用法,如:

select x, y , case when z>0 and z<60>60 and z<80>80 and z<100 then '优秀' else '成绩无效' from table_v

同样第三列也是无名列,可以用用法一中的办法为其取名。



总结:case的这两种用法都很实用,了解了它的用法后可以用它去处理一些比较复杂的逻辑。要记住的是,这两种case用法最终都返回了一个值,就像一个有返回值的方法一样,所以它不能单独执行。
发表

星期四, 六月 28, 2007

Oracle连接不识别的格式问题

经常我们直接手动编辑c:\oracle\ora92\network\ADMIN\tnsname.ora后会有报错不能分解服务器。比如:

 SERVICE =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = hostaddress.com)(PORT = 1234))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = SERVICE)
    )
  )

以下是解决方法(斜体字的部分用实际的域名等代替):

 

方法之一是先看看是不是在c:\oracle\ora92\network\ADMIN\sqlnet.ora下面设置了domain,

NAMES.DEFAULT_DOMAIN = domain.net

如果有,把这一行用#号注释掉。有时候这样就可行了。

 

方法二:如果不行,试试以下方法:

先用命令窗口打 tnsping SERVICE

如果出现不能分解的报错,说明是真的不能连接,否则可能是其它代码错误(尤其是用bat连oracle的时候)。

那么用UltraEdit或者记事本打开tnsname.ora,看看

 SERVICE =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = hostaddress.com)(PORT = 1234))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = SERVICE)
    )
  )

这样的设置每一个SERVICE = 前面是不是都顶格的,正确格式SERVICE前不能有空格!很多不能连接都是因为,你在手动回车添加一个service的时候,UltraEdit给自动加了一个空格在行首。用Oracle自带的配置工具就不会有这个问题。

方法三:所以,如果方法二仍旧不能解决,那就用Oracle自带的配置向导,开始-》程序-》Oracle - Oracle Home92 -》 Configuration and Migration Tools-> Net Manager -> 本地-》服务命名

如果服务命名里面一个都显示不出来,那就把你的tnsname.ora里面不能连上的service删掉,留下能连上的,保存,重新点击“服务命名”,就会出来服务名,然后点左边的绿加号,鼠标放上去会显示“创建”的,就会有向导教你添加了。添加的时候关闭tnsname.ora,添完打开,就可以看到系统自动按照以上的格式把service添加进去了。

星期二, 六月 26, 2007

PLSQL tips

is not null

null should use "is", not "="

(taught, but easy to forget, and important!!!)

 

group functions like AVG, SUM... will dismiss the NULL values

 

NVL (colA, -1) replace all NULL values by -1 when selection

NVL2 (colA, -1, 2) replace all NULL values by -1 when selection, and replace others by 2. 

NULLIF (A, B, C) returns NULL if A = B, else returns C

 

Oracle password is not case sensitive, and should not use characters like "&"

 

row_number() function

can solve the select numbers of lines with each restrict

 

LIKE 'Clear%' 

'%' can stand for many characters, and if '%' happens on the beginning, INDEX is no use.

'_' can stand for one characters

 

rownum

don't write:

select ... where rownum = 2;

because the first row is not selected, so the second row's rownum is still 1...

 

CONCAT is the same as '||'

 

LPAD, RPAD

add some characters to the left or right part of a string

 

CEIL, FLOOR

CEIL (4.1) = 5

FLOOR (4.9) = 4

TRUNC and used on number, time...

 

CASE in SQL

SELECT ... CASE

WHEN ... THEN ...

WHEN ... THEN ...

END

 

in OUT JOIN

LEFT OUT JOIN should mention the difference between:

LEFT OUT JOIN ... ON (... AND ...)

LEFT OUT JOIN ... ON ... WHERE ...

 

SELECT * INTO valueA WHERE ...

if there's nothing returns from SELECT, there will be ERROR, coz no value given to valueA .

but if

SELECT COUNT (*) INTO valueA WHERE

then it is ok, coz COUNT (*) returns zero.

 

update tableA

set colA = XXX

where exist

select ...

from tableA and tableB 

where tableA.x = tableB.x