笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-02 单表查询

SELECT子句中的别名

SELECT子句是在FROM、WHERE、GROUP BY,以及HAVING子句后处理的,这意味着对于SELECT子句之前处理的那些子句,在SELECT子句中为表达式分配的别名并不存在。例如:

SELECT orderid, YEAR(orderdate) AS orderyear
FROM Sales.Orders
WHERE orderyear > 2006;

这是错误的,WHERE子句中并不能识别orderyear别名,应该改为:

SELECT orderid, YEAR(orderdate) AS orderyear
FROM Sales.Orders
WHERE YEAR(orderdate) > 2006;

关于WITH TIES选项

先看下面这段代码:

SELECT TOP (5) orderid, orderdate, custid, empid
FROM Sales.Orders
ORDER BY orderdate DESC, orderid DESC;

执行查询结果如图:


加上WITH TIES选项后:

SELECT TOP (5) WITH TIES orderid, orderdate, custid, empid
FROM Sales.Orders
ORDER BY orderdate DESC;

再看执行结果:

也就是说WITH TIES选项能够返回与TOP n 行中最后一行(在这个例子中式2008年5月5日)的排序值(在这个例子中是orderdate)相同的其他所有行。

OVER子句

先看下面这段代码:

SELECT orderid, custid, val,
  SUM(val) OVER() AS totalvalue,
  SUM(val) OVER(PARTITION BY custid) AS custtotalvalue
FROM Sales.OrderValues;

执行结果:

再看下面的代码:

SELECT  SUM(val) AS totalvalue
FROM    Sales.OrderValues;

执行结果:

对比可知,使用OVER就不必对数据进行分组,还能够在同一行中同时返回基础行的列和聚合列。

再看一段代码:

SELECT orderid, custid, val,
  100. * val / SUM(val) OVER() AS pctall,
  100. * val / SUM(val) OVER(PARTITION BY custid) AS pctcust
FROM Sales.OrderValues;

执行结果:

注意上面这段代码中的一个小细节,就是100后面加个点,而不是直接使用整数100,因为这样可以隐式将整数值val和SUM(val)转换成十进制实数值,否则表达式中的除法将是“整数除法”,会截去数值的小数部分。

OVER子句也支持四种排名函数:ROW_NUMBER(行号)、RANK(排名)、DENSE_RANK(密集排名)、NTILE,看下面的代码:

SELECT orderid, custid, val,
  ROW_NUMBER() OVER(ORDER BY val) AS rownum,
  RANK()       OVER(ORDER BY val) AS rank,
  DENSE_RANK() OVER(ORDER BY val) AS dense_rank,
  NTILE(10)   OVER(ORDER BY val) AS ntile
FROM Sales.OrderValues
ORDER BY val;

执行结果:

简单解释一下上面的各个函数。

ROW_NUMBER用于为查询的结果集中的各行分配递增的序列号,其逻辑顺序通过OVER子句中的ORDER BY语句进行指定。ROW_NUMBER生成的是唯一的行号值。RANK和DENSE_RANK的区别是:RANK表示之前有多少具有更低的排序值,而DENSE_RANK则表示之前有多少更低的排序值。NTILE函数可以把结果中的行关联到组,并为每一行分配一个所属的组的编号。NTILE函数接受一个表示组数量的输入参数,并要在OVER子句中指定逻辑顺序。上面代码例子中是分为10组。

在OVER子句中使用PARTITION BY语句:

SELECT orderid, custid, val,
  ROW_NUMBER() OVER(PARTITION BY custid
                    ORDER BY val) AS rownum
FROM Sales.OrderValues
ORDER BY custid, val;

执行结果:

从结果中可以看出,行号是为每一个客户独立计算的。

注意一点,如果在SELECT处理阶段指定了开窗函数,开窗计算会在DISTINCT子句(如果有)之前进行处理。

谓词和运算符

常见的谓词有:IN、BETWEEN、LIKE等。

CASE表达式

先看一个简单的:

SELECT productid, productname, categoryid,
  CASE categoryid
    WHEN 1 THEN ‘Beverages‘
    WHEN 2 THEN ‘Condiments‘
    WHEN 3 THEN ‘Confections‘
    WHEN 4 THEN ‘Dairy Products‘
    WHEN 5 THEN ‘Grains/Cereals‘
    WHEN 6 THEN ‘Meat/Poultry‘
    WHEN 7 THEN ‘Produce‘
    WHEN 8 THEN ‘Seafood‘
    ELSE ‘Unknown Category‘
  END AS categoryname
FROM Production.Products;

执行结果:

如果CASE表达式中没有ELSE子句,则默认将其视为ELSE NULL。

看一个复杂一点的:

SELECT orderid, custid, val,
  CASE NTILE(3) OVER(ORDER BY val)
    WHEN 1 THEN ‘Low‘
    WHEN 2 THEN ‘Medium‘
    WHEN 3 THEN ‘High‘
    ELSE ‘Unknown‘
  END AS titledesc
FROM Sales.OrderValues
ORDER BY val;

执行结果:

CASE搜索表达式:

SELECT orderid, custid, val,
  CASE
    WHEN val < 1000.00                   THEN ‘Less then 1000‘
    WHEN val BETWEEN 1000.00 AND 3000.00 THEN ‘Between 1000 and 3000‘
    WHEN val > 3000.00                   THEN ‘More than 3000‘
    ELSE ‘Unknown‘
  END AS valuecategory
FROM Sales.OrderValues;

执行结果:

排序规则

如果想在列的排序规则是不区分大小写的前提下,让过滤条件是区分大小写的,则可以按如下方法修改表达式的排序规则:

SELECT empid, firstname, lastname
FROM HR.Employees
WHERE lastname COLLATE Latin1_General_CS_AS = N‘davis‘;

日期和时间

先看下面代码:

SELECT GETDATE()

SELECT CURRENT_TIMESTAMP

上面两句代码返回的日期是一样的,但是CURRENT_TIMESTAMP是标准SQL,所以优先推荐使用CURRENT_TIMESTAMP。

时间: 2024-10-05 06:17:46

笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-02 单表查询的相关文章

笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-08 数据修改

插入数据 T-SQL提供了几种数据插入的语句:INSERT VALUES.INSERT SELECT.INSERT EXEC.SELECT INTO及BULK INSERT. INSERT VALUES语句: INSERT INTO dbo.Orders(orderid, orderdate, empid, custid) VALUES(10001, '20090212', 3, 'A'); SQL Server 2008增强了VALUES语句的功能,允许在一条语句中指定由逗号分隔开的多行记录:

笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-10 可编程对象

关于批处理 下列语句不能在同一批处理中和其他语句同时编译:CREATE DEFAULT.CREATE FUNCTION.CREATE PROCEDURE.CREATE RULE.CREATE SCHEMA.CREATE TRIGGER及CREATE VIEW.例如,以下代码包含一个IF语句,之后在同一批处理中跟着一个CREATE VIEW语句,SQL Server将会报错: IF OBJECT_ID('Sales.MyView', 'V') IS NOT NULL DROP VIEW Sales

笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-07 透视、逆透视及分组集

透视转换 透视数据是一种把数据从行的状态旋转为列的状态的处理.每个透视转换将涉及分组.扩展及聚合三个逻辑处理阶段,每个阶段都有相关的元素:分组阶段处理相关的分组或行元素,扩展阶段处理相关的扩展或列元素,聚合阶段处理相关的聚合元素和聚合函数.现在假设有一张表数据如下: 我现在需要查询出下面的结果: 需求分析:需要在结果中为每一个雇员生成一行记录,这就需要对Orders表中的行按照其empid列进行分组:从结果看,还需要为每一个客户生成一个不同的结果列,那么扩展元素就是custid列:最后还需要对数

笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-06 集合运算

T-SQL支持3种集合运算:并集(UNION).交集(INTERSECT)和差集(EXCEPT).集合运算涉及的两个查询不能包含ORDER BY子句. UNION ALL集合运算 UNION ALL不会对行进行比较,也不会删除重复行.假设查询Query1返回m行,查询Query2返回n行,则Query1 UNION ALL Query2返回(m+n)行. SELECT country, region, city FROM HR.Employees UNION ALL SELECT country

笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-05 表表达式

一般来说,表表达式既不会对性能产生正面影响,也不会对性能产生负面影响. 注意下面这种代码风格: SELECT orderyear, COUNT(DISTINCT custid) AS numcusts FROM (SELECT YEAR(orderdate), custid FROM Sales.Orders) AS D(orderyear, custid) GROUP BY orderyear; 公用表表达式 公用表表达式(CTE,Common table expression)是用WITH子

笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-03 联接查询

联接有三种基本类型:交叉联接.内联接和外联接.交叉联接只有一个步骤——笛卡尔积:内联接有两个步骤——笛卡尔积.过滤:外联接有三个步骤——笛卡尔积.过滤.添加外部行. 内联接 代码: SELECT E.empid, E.firstname, E.lastname, O.orderid FROM HR.Employees AS E JOIN Sales.Orders AS O ON E.empid = O.empid; 另一种写法: SELECT E.empid, E.firstname, E.la

笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-09 事务和并发

事务必须有四个属性:原子性.一致性.隔离性.持久性,这四个属性的首字母可以缩写为ACID. 以下代码定义了一个事务,插入新订单数据: -- Start a new transaction BEGIN TRAN; -- Declare a variable DECLARE @neworderid AS INT; -- Insert a new order into the Sales.Orders table INSERT INTO Sales.Orders (custid, empid, ord

学习Microsoft SQL Server 2008技术内幕:T-SQL语法基础--第4章

第4章 子查询 4.2.1 Exist 谓语: use TSQLFundamentals2008 select * from Sales.Customers as C where c.country=N'Spain' select * from Sales.Customers as C where c.country=N'Spain' and exists(select * from Sales.Orders as O where o.custid=C.custid) select * from

学习Microsoft SQL Server 2008技术内幕:T-SQL语法基础

第 2 章: 单表查询 use TSQLFundamentals2008; select * from Sales.orders; select empid, year(orderdate) as orderyear, Count(*) as numorders from Sales.Orders where custid='71' group by empid, year(orderdate) having count(*) >1 order by empid, orderyear; sele