标题SELECT查询的应用
日期:    作者:   来源:
文章打印自:
访问文章完全地址:
头部广告
SELECT查询的应用
比如我们要从很多文章的标题中找到所有包含"MySQL"这个字眼的文章。这就应该在 WHERE 子句中用到 "LIKE",就是模糊查询。
  首先交待一下SQL语言中的统配符,统配符就是用一个字符统一匹配任何字符,SQL中,一个字符"_"匹配单个的任何字符;一个字符"%"匹配任何零个到多个字符。举例来说,"A_" 可以匹配诸如 "AA"、"AB"、"A2"、"A$"……等等;而 "A%" 可以匹配 "ABCD"、"A"、"AG$Bng0"、"An apple is just an apple."……等等。
  怎么用呢?还是举个实际的例子:工厂仓库里的东东,很多、很杂,要分成几大类来管理:比如A类代表机配件,B类代表工具,C类代表包装材料……等等,每一类下面的东东再分别编号,如"A0001"、"A1065"、"B1014"等。在管理这个数据库的时候,编号作为一个字段,这个字段不仅作为该物品的代号,同时也表明了它的类别。当你要查询所有的工具时,可以这样:

SELECT * FROM goods WHERE code LIKE 'B%' ORDER BY code'

这样就是查询code这个字段(就是编号)为字母B打头的所有记录。注意这里'B%'表示字母B是出现在字段的开头,与下一个例子不同:查找文章标题中含有"MySQL"这个字眼的所有文章,因为要查找的目标"MySQL"不一定出现在文章标题的什么位置上,所以应该:

SELECT * FROM articles WHERE title LIKE '%MySQL%'

'%MySQL%'的意思是"MySQL"这个字眼出现在标题中,它的前面可能有文字,后面也可能有文字。
  既然查"MySQL"可以,查别的字眼未尝不可以。可以让浏览者自己输入他要搜索的关键字,就是这样:

<!--input.php:-->
<form method="get" action="search.php">
关键字:<input type="text" size=10 name="key"> <input type="submit" value="查询">
</form>

<!--search.php:-->
<?
...
$query="select * from article where title like '%$key%'";
$result=$mysql_query($query,$db);
...
?>

  注意在使用模糊查询时,有一种情况应该小心,就是当一个字段是类似 '2,13,25,33' 这样的值时,若要查询它其中是否包含'2'这一项,就不能简单的用 '%2%' 来查询。因为如果这样,一个这样的值也会被查询到:'1,6,21,27'。这并不是我们所希望的。所以在处理这样的问题时,应该将该字段存为 '.2.13.25.33.' 的形式。这样当需要查询包含'2'这一项的记录,就可以放心的用 '%.2.%' 了。


  时间仓促,草草成稿;如有不确,务请指正。
SELECT查询的应用
JOIN子句的用法
  JOIN是很好用的一个SELECT查询的子句,虽然有了它以后你的查询语句变得非常的长,写错的概率也增大了;可是四分之一柱香以后,你就会彻底的爱上它,因为我决定把它的优点全部展示给你!
  为了便于读者接受,我们还是先来建一个数据库吧。

#货物表
create table goods (
id int auto_increment,
code varchar(10) not null,
name varchar(20),
spec varchar(40),
grade varchar(10),
primary key(id) );

#业务员表
create table staff (
id int auto_increment,
name varchar(20),
depart int not null,
primary key(id) );

#部门表
create table depart (
id int auto_increment,
name varchar(20),
primary key(id) );

#客户表
create table customer (
id int auto_increment,
name varchar(60) not null,
association varchar(20),
tel varchar(30),
fax varchar(30),
addr varchar(80),
postcode varchar(10),
email varchar(40),
primary key(id) );

#销售记录表
create table sales (
id int auto_increment,
inputime datetime not null,
staff int not null,
customer int not null,
good_code varchar(10) not null,
amount decimal(10,2) not null default 0.00,
price decimal(8,2) not null default 0.00,
memo text,
primary key(id) );

#插入数据
insert into goods (code,name,spec,grade)
values ('A0001','显示器','PHILIPS 105B','优');
insert into goods (code,name,spec,grade)
values ('A0002','显示器','PHILIPS 107B','优');
insert into depart (name)
values ('业务一部');
insert into depart (name)
values ('业务二部');
insert into depart (name)
values ('业务三部');
insert into staff (name,depart)
values ('王老五',2);
insert into staff (name,depart)
values ('张三',3);
insert into staff (name,depart)
values ('李四',1);
insert into staff (name,depart)
values ('赵二楞',3);
insert into customer (name,association,tel,fax,email)
values ('丁胖子电脑公司','丁胖子','12345678','12345679','fatding@fat.org');
insert into sales (inputime,staff,customer,good_code,amount,price)
values (now(),2,1,'A0001',10,1200.00);
insert into sales (inputime,staff,customer,good_code,amount,price)
values (now(),6,2,'A0001',10,1200.00);

  想必不用我一个一个字段地解释,其中用的字段名字都是很普通的啊。我们这样做的目的是为了在庞大的销售记录表中不要直接记录货物的名称、规格、客户的名称、业务员的姓名等重复性的东西——那样太浪费。我们把所有可能牵扯到的货物、业务员、客户等等分别做为一个表,他们在各自的表中有一个唯一标识的编号,而在销售记录表中,就只填写这个编号。
  在查看销售记录的时候,要把其中的货物代码转换成它对应的货物名称和规格、等级等等;还有把客户的编号转换成客户的名称;业务员的编号换成他的名字……。我们就用JOIN子句,注意看下面这条查询:

SELECT sales.id,sales.inputime,sales.amount,sales.price,sales.memo,
staff.name as staff,depart.name as depart,customer.name as customer,
goods.name as good_name,goods.spec as good_spec,goods.grade as good_grade
FROM sales INNER JOIN staff ON staff.id=sales.staff
INNER JOIN depart ON depart.id=staff.depart
INNER JOIN customer ON customer.id=sales.customer
INNER JOIN goods ON goods.code=sales.good_code
ORDER BY inputime desc

注意这是不是几条,是一条SELECT语句!!嗯,比较长。由于查询的结果也比较长,写出来大家也不一定能看清楚,所以就请自己试一下吧。查询的结果,各个字段对应的分别是:

inputime 录入的时间
amount 销售数量
price 价格
memo 备注
staff 业务员姓名
depart 业务员所属部门
customer 客户名称
good_name 货物名称
good_spec 货物规格
good_grade 货物等级

  当sales表中的staff字段的值,在staff表中找不到对应的业务员记录时,这可能是两钟原因造成的:一为误删除了这个业务员,二为这一条销售记录填入sales表时出现了失误。在这种情况下,使用上面的一条查询就不能将这一条记录取出。刚才我建的数据库sales表中故意留了一条业务员ID是6的记录——业务员表中没有ID是6的!所以按照上面的那条查询,就没有查询到这条记录。如果要避免这种情况发生,可以使用“左连接”:无论匹配与否,取出左侧的表中的所有记录,不能匹配的右侧的表的记录一律为NULL。上述的查询应改为:

SELECT sales.id,sales.inputime,sales.amount,sales.price,sales.memo,
staff.name as staff,depart.name as depart,customer.name as customer,
goods.name as good_name,goods.spec as good_spec,goods.grade as good_grade
FROM sales LEFT JOIN staff ON staff.id=sales.staff
LEFT JOIN depart ON depart.id=staff.depart
LEFT JOIN customer ON customer.id=sales.customer
LEFT JOIN goods ON goods.code=sales.good_code
ORDER BY inputime desc

  再用这个语句查询一次,是不是比刚才查到的多了一条业务员和所属部门是NULL的记录?业务员被误删是应该绝对禁止的,填写sales表时的失误也应该避免。但是一旦发生了,就应该不使它影响到整个销售记录数据的正常存取。所以用“左连接”是必要的。

  时间仓促,草草成稿;如有不确,务请指正。
SELECT查询的应用
分类汇总
  结构化查询(SQL)的另一个强大的功能是分类汇总,也就是GROUP子句;MySQL当然也提供这个功能。现在还以我在《SELECT查询的应用(二)JOIN子句的用法》中的数据库为例说说GROUP子句的用法。

  一、查询每个客户的交易次数。COUNT()是一个与GROUP子句一起使用的函数,它的作用是计数:

SELECT customer,COUNT(*) AS sale_count FROM sales GROUP BY customer

返回的查询可能结果为:

---------- ------------
| customer | sale_count |
---------- ------------
| 1 | 1 |
---------- ------------
| 2 | 1 |
---------- ------------

表示了代码为1和2的两个客户分别有一次交易。

  二、查询每个客户的交易总额。SUM()是一个与GROUP子句一起使用的函数,它的作用是求和:

SELECT customer,SUM(price*amount) AS total_price FROM sales GROUP BY customer

返回的查询结果可能为:

---------- -------------
| customer | total_price |
---------- -------------
| 1 | 12000.00 |
---------- -------------
| 2 | 12000.00 |
---------- -------------

表示了代码为1和2的两个客户各有12000元的交易额。其中SUM(price*amount)表示先将price和amount即单价和数量相乘后再求和,亦即总价。

  三、查询每个客户的平均每次交易额。AVG()是求平均值的函数:

SELECT customer,AVG(price*amount) AS avg_price FROM sales GROUP BY customer

返回的查询结果可能为:

---------- -----------
| customer | avg_price |
---------- -----------
| 1 | 12000.00 |
---------- -----------
| 2 | 12000.00 |
---------- -----------

表示了代码为1和2的两个客户的平均每次交易的交易额都是12000元。由于我预设的数据量比较小,查询的结果不甚明显,请读者谅解。可以随意向sales表中添加一些数据,数据量越大,结果越明显。

  四、查询每个客户最大的和最小的一笔成交额。MAX()和MIN()函数分别是取最大值和最小值的函数:

SELECT customer,MAX(price*amount) AS max_price,MIN(price*amount) AS min_price FROM sales GROUP BY customer

返回的查询结果可能为:

---------- ----------- -----------
| customer | max_price | min_price |
---------- ----------- -----------
| 1 | 12000.00 | 12000.00 |
---------- ----------- -----------
| 2 | 12000.00 | 12000.00 |
---------- ----------- -----------
  
  五、查询每一种货物售出的平均价格。

SELECT good_code,avg(price) AS avg_price FROM sales GROUP BY good_code

对么?不对!这样查询到的是每种货物各条销售记录中价格的平均值,并不是实际售出的所有该货物的平均价格;对我们来说,有用的是按照销售数量加权平均的价格:

SELECT good_code,sum(price*amount)/sum(amount) AS avg_price FROM sales GROUP BY good_code

返回的查询结果可能为:

----------- -----------
| good_code | avg_price |
----------- -----------
| A0001 | 1200.00 |
----------- -----------

  六、查询售给不同客户的每一种货物售出的平均价格。只要在GROUP子句中多加一个关键字:

SELECT good_code,customer,sum(price*amount)/sum(amount) AS avg_price FROM sales GROUP BY good_code,customer

返回的查询结果可能为:

----------- ---------- -----------
| good_code | customer | avg_price |
----------- ---------- -----------
| A0001 | 1 | 1200.00 |
----------- ---------- -----------
| A0001 | 2 | 1200.00 |
----------- ---------- -----------

所有客户和所售货物两项相同的记录汇总到一起来求平均,就形成了售给不同客户的每一种货物售出的平均价格。

责任编辑:semirock