T-SQL笔记1:SELECT及SELECT高级应用

本文深入探讨了SQL查询的基础概念与高级应用,涵盖了从安装AdventureWorks数据库到使用各种运算符、表达式、子查询和联接等核心内容。详细介绍了如何运用SQL进行数据筛选、聚合、分组、排序以及复杂查询,旨在帮助读者全面掌握SQL查询技能。

T-SQL笔记1:SELECT及SELECT高级应用

 

本章摘要

1:安装AdventureWorks

2:基本运算符和表达式

3:between

4:like

5:escape

6:TOP

7:GROUP BY

   7.1:GROUP BY ALL

   7.2:HAVING

8:SELECT字句技术

   8.1:使用DISTINCT消除重复值

   8.2:返回拼接的结果

   8.3使用INTO字句

9:子查询

   9.1:子查询类型

   9.2:代替表达式的查询

  9.3:多层嵌套

10:比较使用 EXISTS 和 IN 的查询

11:联接
  11.1:使用衍生表

   11.2:UNION

12:TABLESAMPLE

13:公共表表达式common_table_expression

 

1:安装AdventureWorks

     本系列笔记均基于AdventureWorks数据库,有关AdventureWorks的安装帮助如下:

    在 Management Studio 工具栏上,单击“文件”,指向“打开”,然后单击“文件”

    浏览到文件 instawdb.sql,并单击“打开”。该文件的默认位置为 C:\Program Files\Microsoft SQL Server\90\Tools\Samples\AdventureWorks OLTP。

    运行脚本之前,在脚本中找到语句 SET @data_path = @sql_path + 'AWDB\';,并更改该语句使其指向 instawdb.sql 脚本的位置。例如,SET @data_path = 'C:\Program Files\Microsoft SQL Server\90\Tools\Samples\AdventureWorks OLTP\';

    执行脚本。

 

2:基本运算符和表达式

运算符描述
!=
!>
!<
<
<=
<>
=
>
>=
ALL比较标量值和单列集中的值。
ANY比较标量值和单列集中的值。SOME 和 ANY 是等效的
BETWEEN自动根据SQL的型别进行取值
CONTAINS为单词或短语执行模糊搜索
ESCAPE指定要以字面值形式搜索,而不是被解释为通配符
EXISTS指定一个子查询,测试行是否存在
FREETEXT根据意思,而不是字面值来搜索数据中的单词
INWHERE color in (‘red’,‘blue’)
IS NOT NULL
IS NULL检测NULL值
LIKE根据通配符进行模式匹配
NOT BETWEEN
NOT IN
NOT LIKE
SOME比较标量值和单列集中的值。SOME 和 ANY 是等效的

 

3:between

    使用:

select SalesOrderID, ShipDate from Sales.SalesOrderHeader
where ShipDate between '7/28/2002' and '7/29/2002'

    结果:将会返回17条语句。

    也许有人会用,使用:

where'7/28/2002' < ShipDate and ShipDate < '7/29/2002'

    不行吗?答案是不行。结果会返回0。

   

4:like

     存在如下通配符,

     %:0~N个任意字符;

     _:1个字符;

     []:指定范围或列表中的任何单个字符;

     [^]:指定不再范围中的任何单个字符;

 

5:escape

    where name like ‘b/B%’ escape ‘/’

    解析:表示全部以‘b/B’开头的name,其中/不理解为通配符。

 

6:TOP

    top允许根据定义的行的数量或者百分比查询出开始的N行。如:

    select top 10 from …

    或者:

    declare @percentage float

    set @percentage =1

    select top (@percentage)  percent * from Sales.SalesOrderHeader

 

7:GROUP BY

    指定用来放置输出行的组。如果 SELECT 子句 <select list> 中包含聚合函数,则 GROUP BY 将计算每组的汇总值。

    上面这句话不太好理解,更好的理解应该解释为:

    “由于在SELECT字句中使用了聚合函数,未聚合的列必须出现在GROUP BY子句中。”

select OrderDate, sum(totalDue) TotalDueByOrderDate from Sales.SalesOrderHeader
where ShipDate between '7/28/2002' and '7/29/2002'
group by OrderDate

    结果:

    (2 行受影响)

   

7.1:GROUP BY ALL

     在上面的代码中,加入ALL,即:

select OrderDate, sum(totalDue) TotalDueByOrderDate from Sales.SalesOrderHeader
where ShipDate between '7/28/2002' and '7/29/2002'
--group by OrderDate
group by all OrderDate

     结果:

Warning: Null value is eliminated by an aggregate or other SET operation.

(1124 行受影响)

     这说明:ALL包含所有组和结果集,甚至包含那些其中任何行都不满足 WHERE 子句指定的搜索条件的组和结果集。如果指定了 ALL,将对组中不满足搜索条件的汇总列返回空值。

 

7.2:HAVING

     指定组或聚合的搜索条件。HAVING 只能与 SELECT 语句一起使用。HAVING 通常在 GROUP BY 子句中使用。如果不使用 GROUP BY 子句,则 HAVING 的行为与 WHERE 子句一样。

     相当于对GROUP之前的查询内容进行再一次的条件检索。

     以下示例使用简单 HAVING 子句从 SalesOrderDetail 表中检索超过 $100000.00 的每个 SalesOrderID 的总计。

SELECT SalesOrderID, SUM(LineTotal) AS SubTotal
FROM Sales.SalesOrderDetail
--where ModifiedDate between '7/28/2002' and '7/29/2002'
GROUP BY SalesOrderID
HAVING SUM(LineTotal) > 100000.00
--HAVING SalesOrderID = 43875
--HAVING ModifiedDate between '7/28/2002' and '7/29/2002' --error
ORDER BY SalesOrderID ;

 

8:SELECT字句技术

        SELECT字句技术有很多,除了最简单的拼接等,下面介绍个人认为最有用的。

 

8.1:使用DISTINCT消除重复值

select * FROM HumanResources.Employee

      结果:(290 行受影响)
select DISTINCT HireDate FROM HumanResources.Employee

      结果:(164 行受影响)

      说明已经将重复的抵消了。

 

8.2:返回拼接的结果

DECLARE @Shifts varchar(20)
SET @Shifts = ''
SELECT @Shifts = @Shifts + s.Name + ',' FROM HumanResources.Shift s
SELECT @Shifts

      返回的结果为:Day,Evening,Night,

      这对于我们处理简单的查询并提高效率有很大的好处。

 

8.3使用INTO字句

    INTO字句用来创建新表(对我来说便是备份数据)。

    一种典型的用法是复制数据到新表(这个新表可以被创建为永久表、临时表或全局临时表),如下代码:

SELECT CustomerID, Name, SalesPersonID, Demographics
INTO  Store_Archive
FROM Sales.Store

    结果:(701 行受影响)

    说明,1:创建了新表Store_Archive,2:有701行数据被复制到了Store_Archive。

    当然,如果你仅仅想创建新表,而不想复制任何数据,有一个简洁的方法是:

SELECT CustomerID, Name, SalesPersonID, Demographics
INTO  Store_Archive
FROM Sales.Store
WHERE 1=0

 

9:子查询

    子查询是一个嵌套在 SELECT、INSERT、UPDATE 或 DELETE 语句或其他子查询中的查询。任何允许使用表达式的地方都可以使用子查询。

    联接总是可以表示为子查询。子查询经常(但不总是)可以表示为联接。这是因为联接是对称的:无论以何种顺序联接表 A 和 B,都将得到相同的结果。而对子查询来说,情况则并非如此。

    使用联接而不使用子查询处理该问题及类似问题的一个不同之处在于,联接使您可以在结果中显示多个表中的列。例如,如果要在结果中包括产品子类别的名称,则必须使用联接版本。

 

9.1:子查询类型

     可以在许多位置指定子查询(必须全部掌握):

9.2:代替表达式的查询

     必须着重说说代替表达式的子查询。在 Transact-SQL 中,除了在 ORDER BY 列表中以外,在 SELECT、UPDATE、INSERT 和 DELETE 语句中任何能够使用表达式的地方都可以用子查询替代。

     以下示例说明如何使用此增强功能。此查询找出所有山地车产品的价格、平均价格以及两者之间的差价。

USE AdventureWorks;
GO
SELECT Name, ListPrice, 
(SELECT AVG(ListPrice) FROM Production.Product) AS Average, 
    ListPrice - (SELECT AVG(ListPrice) FROM Production.Product)
    AS Difference
FROM Production.Product
WHERE ProductSubcategoryID = 1
 
9.3:多层嵌套

     子查询自身可以包括一个或多个子查询。一个语句中可以嵌套任意数量的子查询。

     以下查询将查找作为销售人员的雇员的姓名。

Use AdventureWorks;
GO
SELECT LastName, FirstName
FROM Person.Contact
WHERE ContactID IN
    (SELECT ContactID
     FROM HumanResources.Employee
     WHERE EmployeeID IN
        (SELECT SalesPersonID
         FROM Sales.SalesPerson)
 

10:比较使用 EXISTS 和 IN 的查询

    以下示例比较了两个语义等同的查询。第一个查询使用 EXISTS,第二个查询使用 IN

USE AdventureWorks ;
GO
SELECT a.FirstName, a.LastName
FROM Person.Contact AS a
WHERE EXISTS
(SELECT * 
 FROM HumanResources.Employee AS b
 WHERE a.ContactId = b.ContactID
 AND a.LastName = 'Johnson');
GO

    下面的查询使用 IN

USE AdventureWorks ;
GO
SELECT a.FirstName, a.LastName
FROM Person.Contact AS a
WHERE a.LastName IN
(SELECT a.LastName
 FROM HumanResources.Employee AS b
 WHERE a.ContactId = b.ContactID
 AND a.LastName = 'Johnson');
GO

    以下是其中任一查询的结果集。

FirstName                                          LastName
-------------------------------------------------- ----------
Barry                                              Johnson
David                                              Johnson
Willis                                             Johnson
(3 row(s) affected)
 
11:联接
   通过联接,可以从两个或多个表中根据各个表之间的逻辑关系来检索数据。
   联接条件中用到的列不必具有相同的名称或相同的数据类型。但如果数据类型不相同,则必须兼容,或者是可由 SQL Server 进行隐式转换的类型。

     联接可分为以下几类:

  • 内部联接(典型的联接运算,使用类似于 = 或 <> 的比较运算符)。内部联接包括同等联接和自然联接。
    内部联接使用比较运算符根据每个表的通用列中的值匹配两个表中的行。例如,检索 studentscourses 表中学生标识号相同的所有行。
  • 外部联接。外部联接可以是左向外部联接、右向外部联接或完整外部联接。
    在 FROM 子句中可以用下列某一组关键字来指定外部联接:
    • LEFT JOIN 或 LEFT OUTER JOIN。
      左向外部联接的结果集包括 LEFT OUTER 子句中指定的左表的所有行,而不仅仅是联接列所匹配的行。如果左表的某一行在右表中没有匹配行,则在关联的结果集行中,来自右表的所有选择列表列均为空值。
    • RIGHT JOIN 或 RIGHT OUTER JOIN
      右向外部联接是左向外部联接的反向联接。将返回右表的所有行。如果右表的某一行在左表中没有匹配行,则将为左表返回空值。
    • FULL JOIN 或 FULL OUTER JOIN
      完整外部联接将返回左表和右表中的所有行。当某一行在另一个表中没有匹配行时,另一个表的选择列表列将包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。
  • 交叉联接
    交叉联接将返回左表中的所有行。左表中的每一行均与右表中的所有行组合。交叉联接也称作笛卡尔积。

11.1:使用衍生表

     衍生表是指在FROM字句中作为表的SELECT语句。

SELECT DISTINCT s.PurchaseOrderNumber
FROM Sales.SalesOrderHeader s
INNER JOIN ( SELECT SalesOrderID
    FROM Sales.SalesOrderDetail
    WHERE UnitPrice BETWEEN 1000 AND 2000) d ON
    s.SalesOrderID = d.SalesOrderID

 

11.2:UNION

   将两个或更多查询的结果合并为单个结果集,该结果集包含联合查询中的所有查询的全部行。

     下面列出了使用 UNION 合并两个查询结果集的基本规则:

  • 所有查询中的列数和列的顺序必须相同。
  • 数据类型必须兼容。

SELECT ProductModelID, Name FROM Production.ProductModel WHERE ProductModelID NOT IN (3, 4) UNION SELECT ProductModelID, Name FROM dbo.Gloves ORDER BY Name ;

 

12:TABLESAMPLE

     TABLESAMPLE 子句将从 FROM 子句中的表返回的行数限制到样本数或行数的某一百分比。例如:

SELECT FirstName, LastName FROM Person.Person TABLESAMPLE (10 PERCENT) ;

SELECT FirstName, LastName FROM Person.Person TABLESAMPLE (100 ROWS) ;

 

13:公共表表达式common_table_expression

     指定临时命名的结果集,这些结果集称为公用表表达式 (CTE)。该表达式源自简单查询,并且在单条 SELECT、INSERT、UPDATE 或 DELETE 语句的执行范围内定义。该子句也可用在 CREATE VIEW 语句中,作为该语句的 SELECT 定义语句的一部分。公用表表达式可以包括对自身的引用。这种表达式称为递归公用表表达式。

USE AdventureWorks;
GO
WITH DirReps(ManagerID, DirectReports) AS
(
    SELECT ManagerID, COUNT(*)
    FROM HumanResources.Employee AS e
    WHERE ManagerID IS NOT NULL
    GROUP BY ManagerID
)
SELECT ManagerID, DirectReports
FROM DirReps
ORDER BY ManagerID;
GO

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值