避免使用select *
当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用 ‘*’ 是一个方便的方法.不幸的是,这是一个非常低效的方法. 实际上,SQL在解析的过程中, 会将’*’ 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间.
为了描述逻辑查询处理和各种SELECT查询子句,我们使用以下事例为大家介绍。
例:查询出加拿大市场的所有绑定1个以上手机的用户,并且按用户ID排序。
select ACCTID,count(*) numPhones
from IFD_PHONE_LIST
where NATION_CODE='CA'
group by ACCTID
having count(*) >1
order by ACCTID
执行顺序如下:
1. FROM
2. WHERE
3. GTOUP BY
4. HAVING
5. SELECT
6. ORDER BY
这条查询语句会完成以下功能
1. 从IFD_PHONE_LIST表中查询数据行
2. 对表中数据进行过滤,只保留市场为CA的记录
3. 按照用户ID对数据进行分组
4. 对分组后的数据进行过滤,只保留绑定多个手机的用户
5. 返回每个分组用户ID和手机数目
6. 按照用户ID对输出结果进行排序
所以如果sql改为
select ACCTID,count(*) numPhones
from IFD_PHONE_LIST
where NATION_CODE='CA' and numPhones >1
group by ACCTID
having count(*) >1
order by ACCTID
那么该sql会报错,因为这时字段还没有起别名,该操作是在where语句执行后才会执行。
SELECT指令可以查出我们想要的所有数据,但是在这些数据中可能有很多重复的值。
当需要查询某个表格中有哪些不同的值,而每个值出现的次数并不重要,那么这时就可以使用DISTINCT
使用方法
SELECT DISTINCT “字段名” FROM “表格名”
Group by 阶段可以将前面逻辑查询处理阶段返回的行按“组”进行组合。
例:查询某个用户的近6月账单
select CYCLE_START as CycleStart,
CYCLE_END as CycleEnd,
sum(TOLL_CHARGE) as TollCharge,
sum(Credit) as Credit,
sum(Debit) as Debit,
min(Due_Date) as DueDate
from CYCLE_CALL_FEE_HISTORY
where acctid = 39129 and cycle_start>='2010-1-1' and cycle_end<='2010-6-1'
group by CYCLE_START, CYCLE_END
因为聚合函数只为每个组返回一个值,所以一个元素如果不在group by 里表中出现,就只能作为聚合函数(COUNT,SUM,AVG,MIN,MAX)的输入。但是所有的聚合函数都会忽略NULL值,只有一个例外 COUNT(*)。例如某列的值为 30,10,NULL,10.COUNT(*)会返回4,而COUNT(列名) 将返回3.
在一个表中的数据不一定是排序存放的。所以到需要排序时
ORDER BY 语句用于根据指定的列对结果集进行排序。
ORDER BY 语句默认按照升序对记录进行排序。
如果您希望按照降序对记录进行排序,可以使用 DESC 关键字。
当要查询一个字段为null的记录时,要使用 is null 而不是 != nul
NOT运算符用于对搜索条件的布尔值求反。这里讨论NOT运算符的使用、应用场合及其与<>运算符的区别。
与其他运算符不同,表示否定的NOT运算符不能单独应用,而经常与其他运算符联合使用。例如,NOT IN运算符实际上就是IN运算符与NOT运算符的联合使用
例: 使用NOT运算符实现查询
SELECT TNAME, DNAME,AGE, TSEX FROM TEACHER WHERE NOT DNAME='计算机' ORDER BY DNAME
NOT运算符对紧跟其后的条件取反,NOT DNAME=‘计算机’实际上就等价于DNAME<>‘计算机’或者DNAME!=‘计算机’。
需要强调一点,NULL值进行取反,结果仍是NULL.
例 NULL值的取反
如下面的代码:
SELECT * FROM TEACHER WHERE NOT SAL >1500 OREDR BY SAL
上述实例代码实际上是查询所有工资不高于1500的教师信息,从结果中发现,工资为NULL的教师记录并没有包括在结果表中。因为当SAL为NULL时,“SAL >1500”的执行结果也为NULL,而NOT NULL的运算结果仍然为NULL,也就不满足查询条件。
使用BETWEEN...AND 操作符可以选中排列于两值之间的数据。这些数据可以是数字,文字或是日期。在SQL中 使用相当于 >= 和 <=
例:查询出前10掉记录
select top 10 account_id,plan_id,status
from account_extension
order by account_id
这里要注意执行顺序,查询出的数据会先进行排序再查出前10行记录
在SQL Server 2005之前的传统SQL语句中,top语句是不支持局部变量的。此时可以使用Set RowCount,但是在SQL Server 2005/2008中,TOP通常执行得更快,所以应该用TOP关键字来取代Set RowCount。
Declare @percentage floatset
@percentage=1
select Top (@percentage) percent PName from [Demo_Top] order by PName
例:利用top 和 percent分页
查出前1%的数据
select Top 1 percent OrderID from Orders order by OrderID
查出前2%的数据
select Top 2 percent * from Orders where OrderID not in
( select Top 1 percent OrderID from Orders order by OrderID) order by OrderID
数据库结构和索引的是否合理在很大程度上影响了数据库的性能,但是随着数据库信息负载的增大,对数据库的性能也发生了很大的影响。可能我们的数据库在一开始有着很高的性能,但是随着数据存储量的急速增长—例如通话记录数据—数据的性能也受到了极大的影响,一个很明显的结果就是查询的反应会非常慢。在这个时候,除了你可以优化索引及查询外,你还可以建立分区表(Table Partition),在某些场合下提高数据库的性能,在SQL Server 2008中提供了向导形式来创建分区表。
例:在fact_sales表中针对date_id 以月为单位做分区后执行以下语句。
SELECT date_id, SUM(quantity*unit_price) AS total_price
FROM fact_sales
WHERE date_id BETWEEN 20080801 AND 20080831
这时对date_id进行查询时,会从指定分区表内提取数据从而可以提高查询效率
确定在应用关联的开窗函数之前,行集的分区和排序
PARTITION BY 参数
将结果集分为多个分区。开窗函数分别应用于每个分区,并为每个分区重新启动计算。
例:
select orderid,custid,val,
sum(val) over() as totalvalue,
sum(val) over(partition by custid) as custtotalval
from ordervalues
查询结果:
orderid |
custid |
val |
totalvalue |
custtotalval |
10001 |
1 |
800.50 |
1232323.23 |
4343.00 |
10002 |
1 |
340.23 |
1232323.23 |
4343.00 |
10003 |
1 |
123.31 |
1232323.23 |
4343.00 |
10004 |
2 |
343.34 |
1232323.23 |
1343.00 |
10005 |
2 |
123.32 |
1232323.23 |
1343.00 |
在Over中 使用 PARTITION BY,并且按照特定字段排序
例2:
select orderid,custid,val,
row_number() over(partition by custid
order by val) as rownum
from ordervalues
order by custid,val
查询结果:
orderid |
custid |
val |
rownum |
10001 |
1 |
100.50 |
1 |
10002 |
1 |
340.23 |
2 |
10003 |
1 |
444.23 |
3 |
10004 |
2 |
123.32 |
1 |
10005 |
2 |
234.23 |
2 |
10006 |
2 |
435.34 |
3 |