T-SQL基础教程Day3

Posted SQL Server学习

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了T-SQL基础教程Day3相关的知识,希望对你有一定的参考价值。

第三章 联接
3.1交叉联接
交叉联接是最简单的联接类型。
交叉联接仅执行一个逻辑查询处理阶段——笛卡尔乘积
将一个输入表的每一行与另一个表的所有行匹配
SQL Server支持交叉联接的两种标准语法:
ANSI SQL-92和ANSI SQL-89语法,
建议使用ANSI SQL-92语法
3.1.1 ANSI SQL-92语法
SELECT C.custid, E.empid
FROM Sales.Customers AS C
CROSS JOIN HR.Employees AS E;
使用关键字CROSS JOIN
可以对表使用别名,如果未使用别名,需要使用完整的源表名称作为前缀。
3.1.2 ANSI SQL-89语法
SELECT C.custid, E.empid
FROM Sales.Customers AS C, HR.Employees AS E;
简单地在表名称之间制定一个逗号
两种语法之间没有逻辑或性能差异。
3.1.3 自交叉联接
可以联接同一个表的多个实例,此功能称为自联接,并且被所有基本联接类型支持(交叉联接、内部联接和外部联接)。
SELECT
E1.empid, E1.firstname, E1.lastname,
E2.empid, E2.firstname, E2.lastname
FROM HR.Employees AS E1
CROSS JOIN HR.Employees AS E2;
在自联接中,为表指定别名不是可选项。没有表别名,联接结果中的所有列名都将不明确。
3.1.4 生成数字表
交叉联接的一种用途是,生成一个整数数列结果集。
先创建一个名为Digits的表,其中包含名为digit的列,并且以数字0~9填充该表。
CREATE TABLE dbo.Digits(digit INT NOT NULL PRIMARY KEY);
INSERT INTO dbo.Digits(digit)
VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
SELECT digit FROM dbo.Digits;
SELECT D3.digit * 100 + D2.digit * 10 + D1.digit + 1 AS n
FROM dbo.Digits AS D1
CROSS JOIN dbo.Digits AS D2
CROSS JOIN dbo.Digits AS D3
ORDER BY n;
SQL Server 2022支持新语法:
SELECT * FROM GENERATE_SERIES(1, 1000);
3.2 内部联接
内部联接应用两个逻辑查询处理阶段——首先对作为交叉联接的两个输入表应用一个笛卡尔乘积,然后按指定的谓词筛选行。
也有两个标准语法:ANSI SQL-92和ANSI SQL-89
3.2.1 ANSI SQL-92语法
在表名称之间指定INNER JOIN关键字。
由于内部联接是默认联接,所以INNER关键字是可选的,可以仅指定JOIN关键字。指定的谓词用用于在名为ON的特定子句中筛选行,该谓词也称为联接条件。
SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E
INNER JOIN Sales.Orders AS O
ON E.empid = O.empid;
对大多数人来说,思考内部联接的最简单方式是,内部联接匹配每个雇员行到与其具有相同雇员ID的所有订单行,这是联接的一个简单思考方式。
联接的更正式思考方式是基于关系代数的,联接首先执行两个表的笛卡尔乘积,然后基于谓词E.empid = O.empid筛选行。
3.2.2 ANSI SQL-89语法
像交叉联接一样在表名称之间指定一个逗号,并在查询的WHERE子句中指定联接条件。
SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E, Sales.Orders AS O
WHERE E.empid = O.empid;
注意,ANSI SQL-89语法没有ON子句。
3.2.3 内部联接安全性
建议使用ANSI SQL-92联接语法,因为它在几个方面都是安全的。
假设打算写一个内部联接查询,并且失误忘记了指定联接条件。对于ANSI SQL-92语法,查询将无效,解析器会生成一个错误。
如果使用ANSI SQL-89语法时忘记指定联接条件,你会得到一个执行交叉联接的有效查询。因为查询不会失败,一段时间内可能不会注意到逻辑错误,你的应用程序哦用户可能最终使用了错误结果。对于简单的查询,程序员不太坑你会忘记指定联接条件,然而,多数生产查询更为复杂并具有多个表、筛选和其他查询元素,在这些情况下,忘记指定联接条件的可能性就增加了。
3.3.1 复合联接
复合联接是谓词涉及每侧多个属性的简单联接。
当需要联接两个基于主外键关系并且是复合关系(即基于多个属性)的表时,通常需要复合联接。
FROM dbo.Table1 AS T1
INNER JOIN dbo.Table2 AS T2
ON T1.col1 = T2.col1
AND T1.col2 = T2.col2
3.3.2 不等联接
当联接条件仅涉及等号运算时,称为相等联接。
当联接条件涉及除等号之外的任何运算符时,称为不等联接。
下面是一个不等联接的示例,此查询联接Employees表的两个实例,生成唯一的雇员对。
SELECT
E1.empid, E1.firstname, E1.lastname,
E2.empid, E2.firstname, E2.lastname
FROM HR.Employees AS E1
INNER JOIN HR.Employees AS E2
ON E1.empid < E2.empid;
3.3.3 多联接查询
当FROM子句中出现多个表运算符时,表运算符从左到右进行逻辑处理。也就是说,第一个表运算符的结果表将被视为第二个表运算符的左侧输入,第二个表运算符的结果将被视为第三个表运算符的左侧输入,以此类推。
SELECT
C.custid, C.companyname, O.orderid,
OD.productid, OD.qty
FROM Sales.Customers AS C
INNER JOIN Sales.Orders AS O
ON C.custid = O.custid
INNER JOIN Sales.OrderDetails AS OD
ON O.orderid = OD.orderid;
3.4.1 外部联接的基础知识
外部联接是在ANSI SQL-92中引入的,并且与内部联接和交叉联接不同,它只有一个标准语法——在表名之间制定一个JOIN关键字,并且在ON子句中指定联接条件。外部联接应用内部联接锁应用的两个逻辑处理阶段,再加上一个叫做“添加外部行”的第三个阶段,此阶段是此联接类型唯一具有的阶段。
在外部联接中,需要在表名之间使用关键字LEFT OUTER JOIN、RIGHT OUTER JOIN或FULL OUTER JOIN标记一个表为“保留表”。
OUTER关键字是可选的。LEFT关键字表示保留左侧表中的行,RIGHT表示保留右侧表中的行,FULL表示左侧和右侧表中的行都保留。
3.4.2 超越外部联接基础知识(可选内容)
1 包含缺失值
SELECT DATEADD(day, Nums.n - 1, CAST(\'20140101\' AS DATE)) AS orderdate,
O.orderid, O.custid, O.empid
FROM dbo.Nums
LEFT OUTER JOIN Sales.Orders AS O
ON DATEADD(day, Nums.n - 1, CAST(\'20140101\' AS DATE)) = O.orderdate
WHERE Nums.n <= DATEDIFF(day, \'20140101\', \'20161231\') + 1
ORDER BY orderdate;
2 从外部联接的非保留侧筛选属性
SELECT C.custid, C.companyname, O.orderid, O.orderdate
FROM Sales.Customers AS C
LEFT OUTER JOIN Sales.Orders AS O
ON C.custid = O.custid
WHERE O.orderdate >= \'20160101\';
3 在多联接查询中使用外部联接
4 在外部联接使用COUNT聚合
SELECT C.custid, COUNT(*) AS numorders
FROM Sales.Customers AS C
LEFT OUTER JOIN Sales.Orders AS O
ON C.custid = O.custid
GROUP BY C.custid;

章节代码

---------------------------------------------------------------------
-- Microsoft SQL Server 2012 T-SQL Fundamentals
-- Chapter 03 - Joins
-- ?Itzik Ben-Gan 
---------------------------------------------------------------------

---------------------------------------------------------------------
-- CROSS Joins
---------------------------------------------------------------------

-- ANSI SQL-92
USE TSQL2012;

SELECT C.custid, E.empid
FROM Sales.Customers AS C
  CROSS JOIN HR.Employees AS E;

-- ANSI SQL-89
SELECT C.custid, E.empid
FROM Sales.Customers AS C, HR.Employees AS E;

-- Self Cross-Join
SELECT
  E1.empid, E1.firstname, E1.lastname,
  E2.empid, E2.firstname, E2.lastname
FROM HR.Employees AS E1 
  CROSS JOIN HR.Employees AS E2;
GO

-- All numbers from 1 - 1000

-- Auxiliary table of digits
USE TSQL2012;
IF OBJECT_ID(\'dbo.Digits\', \'U\') IS NOT NULL DROP TABLE dbo.Digits;
CREATE TABLE dbo.Digits(digit INT NOT NULL PRIMARY KEY);

INSERT INTO dbo.Digits(digit)
  VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);

SELECT digit FROM dbo.Digits;
GO

-- All numbers from 1 - 1000
SELECT D3.digit * 100 + D2.digit * 10 + D1.digit + 1 AS n
FROM         dbo.Digits AS D1
  CROSS JOIN dbo.Digits AS D2
  CROSS JOIN dbo.Digits AS D3
ORDER BY n;

---------------------------------------------------------------------
-- INNER Joins
---------------------------------------------------------------------

-- ANSI SQL-92
USE TSQL2012;

SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E
  JOIN Sales.Orders AS O
    ON E.empid = O.empid;

-- ANSI SQL-89
SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E, Sales.Orders AS O
WHERE E.empid = O.empid;
GO

-- Inner Join Safety
/*
SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E
  JOIN Sales.Orders AS O;
GO
*/

SELECT E.empid, E.firstname, E.lastname, O.orderid
FROM HR.Employees AS E, Sales.Orders AS O;
GO

---------------------------------------------------------------------
-- Further Join Examples
---------------------------------------------------------------------

---------------------------------------------------------------------
-- Composite Joins
---------------------------------------------------------------------

-- Audit table for updates against OrderDetails
USE TSQL2012;
IF OBJECT_ID(\'Sales.OrderDetailsAudit\', \'U\') IS NOT NULL
  DROP TABLE Sales.OrderDetailsAudit;
CREATE TABLE Sales.OrderDetailsAudit
(
  lsn        INT NOT NULL IDENTITY,
  orderid    INT NOT NULL,
  productid  INT NOT NULL,
  dt         DATETIME NOT NULL,
  loginname  sysname NOT NULL,
  columnname sysname NOT NULL,
  oldval     SQL_VARIANT,
  newval     SQL_VARIANT,
  CONSTRAINT PK_OrderDetailsAudit PRIMARY KEY(lsn),
  CONSTRAINT FK_OrderDetailsAudit_OrderDetails
    FOREIGN KEY(orderid, productid)
    REFERENCES Sales.OrderDetails(orderid, productid)
);

SELECT OD.orderid, OD.productid, OD.qty,
  ODA.dt, ODA.loginname, ODA.oldval, ODA.newval
FROM Sales.OrderDetails AS OD
  JOIN Sales.OrderDetailsAudit AS ODA
    ON OD.orderid = ODA.orderid
    AND OD.productid = ODA.productid
WHERE ODA.columnname = N\'qty\';

---------------------------------------------------------------------
-- Non-Equi Joins
---------------------------------------------------------------------

-- Unique pairs of employees
SELECT
  E1.empid, E1.firstname, E1.lastname,
  E2.empid, E2.firstname, E2.lastname
FROM HR.Employees AS E1
  JOIN HR.Employees AS E2
    ON E1.empid < E2.empid;

---------------------------------------------------------------------
-- Multi-Join Queries
---------------------------------------------------------------------

SELECT
  C.custid, C.companyname, O.orderid,
  OD.productid, OD.qty
FROM Sales.Customers AS C
  JOIN Sales.Orders AS O
    ON C.custid = O.custid
  JOIN Sales.OrderDetails AS OD
    ON O.orderid = OD.orderid;

---------------------------------------------------------------------
-- Fundamentals of Outer Joins 
---------------------------------------------------------------------

-- Customers and their orders, including customers with no orders
SELECT C.custid, C.companyname, O.orderid
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON C.custid = O.custid;

-- Customers with no orders
SELECT C.custid, C.companyname
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON C.custid = O.custid
WHERE O.orderid IS NULL;
GO

---------------------------------------------------------------------
-- Beyond the Fundamentals of Outer Joins
---------------------------------------------------------------------

---------------------------------------------------------------------
-- Including Missing Values
---------------------------------------------------------------------

SELECT DATEADD(day, n-1, \'20060101\') AS orderdate
FROM dbo.Nums
WHERE n <= DATEDIFF(day, \'20060101\', \'20081231\') + 1
ORDER BY orderdate;

SELECT DATEADD(day, Nums.n - 1, \'20060101\') AS orderdate,
  O.orderid, O.custid, O.empid
FROM dbo.Nums
  LEFT OUTER JOIN Sales.Orders AS O
    ON DATEADD(day, Nums.n - 1, \'20060101\') = O.orderdate
WHERE Nums.n <= DATEDIFF(day, \'20060101\', \'20081231\') + 1
ORDER BY orderdate;

---------------------------------------------------------------------
-- Filtering Attributes from Non-Preserved Side of Outer Join
---------------------------------------------------------------------

SELECT C.custid, C.companyname, O.orderid, O.orderdate
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON C.custid = O.custid
WHERE O.orderdate >= \'20070101\';

---------------------------------------------------------------------
-- Using Outer Joins in a Multi-Join Query
---------------------------------------------------------------------

SELECT C.custid, O.orderid, OD.productid, OD.qty
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON C.custid = O.custid
  JOIN Sales.OrderDetails AS OD
    ON O.orderid = OD.orderid;

-- Option 1: use outer join all along
SELECT C.custid, O.orderid, OD.productid, OD.qty
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON C.custid = O.custid
  LEFT OUTER JOIN Sales.OrderDetails AS OD
    ON O.orderid = OD.orderid;

-- Option 2: change join order
SELECT C.custid, O.orderid, OD.productid, OD.qty
FROM Sales.Orders AS O
  JOIN Sales.OrderDetails AS OD
    ON O.orderid = OD.orderid
  RIGHT OUTER JOIN Sales.Customers AS C
     ON O.custid = C.custid;

-- Option 3: use parentheses
SELECT C.custid, O.orderid, OD.productid, OD.qty
FROM Sales.Customers AS C
  LEFT OUTER JOIN
      (Sales.Orders AS O
         JOIN Sales.OrderDetails AS OD
           ON O.orderid = OD.orderid)
    ON C.custid = O.custid;

---------------------------------------------------------------------
-- Using the COUNT Aggregate with Outer Joins
---------------------------------------------------------------------

SELECT C.custid, COUNT(*) AS numorders
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON C.custid = O.custid
GROUP BY C.custid;

SELECT C.custid, COUNT(O.orderid) AS numorders
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON C.custid = O.custid
GROUP BY C.custid; 

 

练习代码

---------------------------------------------------------------------
-- Microsoft SQL Server 2012 T-SQL Fundamentals
-- Chapter 03 - Joins
-- Solutions
-- ?Itzik Ben-Gan 
---------------------------------------------------------------------

-- 1 
-- 1-1 
-- Write a query that generates 5 copies out of each employee row
-- Tables involved: TSQL2012 database, Employees and Nums tables

--Desired output
empid       firstname  lastname             n
----------- ---------- -------------------- -----------
1           Sara       Davis                1
2           Don        Funk                 1
3           Judy       Lew                  1
4           Yael       Peled                1
5           Sven       Buck                 1
6           Paul       Suurs                1
7           Russell    King                 1
8           Maria      Cameron              1
9           Zoya       Dolgopyatova         1
1           Sara       Davis                2
2           Don        Funk                 2
3           Judy       Lew                  2
4           Yael       Peled                2
5           Sven       Buck                 2
6           Paul       Suurs                2
7           Russell    King                 2
8           Maria      Cameron              2
9           Zoya       Dolgopyatova         2
1           Sara       Davis                3
2           Don        Funk                 3
3           Judy       Lew                  3
4           Yael       Peled                3
5           Sven       Buck                 3
6           Paul       Suurs                3
7           Russell    King                 3
8           Maria      Cameron              3
9           Zoya       Dolgopyatova         3
1           Sara       Davis                4
2           Don        Funk                 4
3           Judy       Lew                  4
4           Yael       Peled                4
5           Sven       Buck                 4
6           Paul       Suurs                4
7           Russell    King                 4
8           Maria      Cameron              4
9           Zoya       Dolgopyatova         4
1           Sara       Davis                5
2           Don        Funk                 5
3           Judy       Lew                  5
4           Yael       Peled                5
5           Sven       Buck                 5
6           Paul       Suurs                5
7           Russell    King                 5
8           Maria      Cameron              5
9           Zoya       Dolgopyatova         5

(45 row(s) affected)

-- Solution
SELECT E.empid, E.firstname, E.lastname, N.n
FROM HR.Employees AS E
  CROSS JOIN dbo.Nums AS N 
WHERE N.n <= 5
ORDER BY n, empid;

-- 1-2  (Optional, Advanced)
-- Write a query that returns a row for each employee and day 
-- in the range June 12, 2009 ?June 16 2009.
-- Tables involved: TSQL2012 database, Employees and Nums tables

--Desired output
empid       dt
----------- -----------------------
1           2009-06-12 00:00:00.000
1           2009-06-13 00:00:00.000
1           2009-06-14 00:00:00.000
1           2009-06-15 00:00:00.000
1           2009-06-16 00:00:00.000
2           2009-06-12 00:00:00.000
2           2009-06-13 00:00:00.000
2           2009-06-14 00:00:00.000
2           2009-06-15 00:00:00.000
2           2009-06-16 00:00:00.000
3           2009-06-12 00:00:00.000
3           2009-06-13 00:00:00.000
3           2009-06-14 00:00:00.000
3           2009-06-15 00:00:00.000
3           2009-06-16 00:00:00.000
4           2009-06-12 00:00:00.000
4           2009-06-13 00:00:00.000
4           2009-06-14 00:00:00.000
4           2009-06-15 00:00:00.000
4           2009-06-16 00:00:00.000
5           2009-06-12 00:00:00.000
5           2009-06-13 00:00:00.000
5           2009-06-14 00:00:00.000
5           2009-06-15 00:00:00.000
5           2009-06-16 00:00:00.000
6           2009-06-12 00:00:00.000
6           2009-06-13 00:00:00.000
6           2009-06-14 00:00:00.000
6           2009-06-15 00:00:00.000
6           2009-06-16 00:00:00.000
7           2009-06-12 00:00:00.000
7           2009-06-13 00:00:00.000
7           2009-06-14 00:00:00.000
7           2009-06-15 00:00:00.000
7           2009-06-16 00:00:00.000
8           2009-06-12 00:00:00.000
8           2009-06-13 00:00:00.000
8           2009-06-14 00:00:00.000
8           2009-06-15 00:00:00.000
8           2009-06-16 00:00:00.000
9           2009-06-12 00:00:00.000
9           2009-06-13 00:00:00.000
9           2009-06-14 00:00:00.000
9           2009-06-15 00:00:00.000
9           2009-06-16 00:00:00.000

(45 row(s) affected)

-- Solution
SELECT E.empid,
  DATEADD(day, D.n - 1, \'20090612\') AS dt
FROM HR.Employees AS E
  CROSS JOIN Nums AS D
WHERE D.n <= DATEDIFF(day, \'20090612\', \'20090616\') + 1
ORDER BY empid, dt;

-- 2
-- Return US customers, and for each customer the total number of orders 
-- and total quantities.
-- Tables involved: TSQL2012 database, Customers, Orders and OrderDetails tables

--Desired output
custid      numorders   totalqty
----------- ----------- -----------
32          11          345
36          5           122
43          2           20
45          4           181
48          8           134
55          10          603
65          18          1383
71          31          4958
75          9           327
77          4           46
78          3           59
82          3           89
89          14          1063

(13 row(s) affected)

-- Solution
SELECT C.custid, COUNT(DISTINCT O.orderid) AS numorders, SUM(OD.qty) AS totalqty
FROM Sales.Customers AS C
  JOIN Sales.Orders AS O
    ON O.custid = C.custid
  JOIN Sales.OrderDetails AS OD
    ON OD.orderid = O.orderid
WHERE C.country = N\'USA\'
GROUP BY C.custid;

-- 3
-- Return customers and their orders including customers who placed no orders
-- Tables involved: TSQL2012 database, Customers and Orders tables

-- Desired output
custid      companyname     orderid     orderdate
----------- --------------- ----------- ------------------------
85          Customer ENQZT  10248       2006-07-04 00:00:00.000
79          Customer FAPSM  10249       2006-07-05 00:00:00.000
34          Customer IBVRG  10250       2006-07-08 00:00:00.000
84          Customer NRCSK  10251       2006-07-08 00:00:00.000
...
73          Customer JMIKW  11074       2008-05-06 00:00:00.000
68          Customer CCKOT  11075       2008-05-06 00:00:00.000
9           Customer RTXGC  11076       2008-05-06 00:00:00.000
65          Customer NYUHS  11077       2008-05-06 00:00:00.000
22          Customer DTDMN  NULL        NULL
57          Customer WVAXS  NULL        NULL

(832 row(s) affected)

-- Solution
SELECT C.custid, C.companyname, O.orderid, O.orderdate
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON O.custid = C.custid;

-- 4
-- Return customers who placed no orders
-- Tables involved: TSQL2012 database, Customers and Orders tables

-- Desired output
custid      companyname
----------- ---------------
22          Customer DTDMN
57          Customer WVAXS

(2 row(s) affected)

-- Solution
SELECT C.custid, C.companyname
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON O.custid = C.custid
WHERE O.orderid IS NULL;

-- 5
-- Return customers with orders placed on Feb 12, 2007 along with their orders
-- Tables involved: TSQL2012 database, Customers and Orders tables

-- Desired output
custid      companyname     orderid     orderdate
----------- --------------- ----------- -----------------------
66          Customer LHANT  10443       2007-02-12 00:00:00.000
5           Customer HGVLZ  10444       2007-02-12 00:00:00.000

(2 row(s) affected)

-- Solution
SELECT C.custid, C.companyname, O.orderid, O.orderdate
FROM Sales.Customers AS C
  JOIN Sales.Orders AS O
    ON O.custid = C.custid
WHERE O.orderdate = \'20070212\';

-- 6 (Optional, Advanced)
-- Return customers with orders placed on Feb 12, 2007 along with their orders
-- Also return customers who didn\'t place orders on Feb 12, 2007 
-- Tables involved: TSQL2012 database, Customers and Orders tables

-- Desired output
custid      companyname     orderid     orderdate
----------- --------------- ----------- -----------------------
72          Customer AHPOP  NULL        NULL
58          Customer AHXHT  NULL        NULL
25          Customer AZJED  NULL        NULL
18          Customer BSVAR  NULL        NULL
91          Customer CCFIZ  NULL        NULL
...
33          Customer FVXPQ  NULL        NULL
53          Customer GCJSG  NULL        NULL
39          Customer GLLAG  NULL        NULL
16          Customer GYBBY  NULL        NULL
4           Customer HFBZG  NULL        NULL
5           Customer HGVLZ  10444       2007-02-12 00:00:00.000
42          Customer IAIJK  NULL        NULL
34          Customer IBVRG  NULL        NULL
63          Customer IRRVL  NULL        NULL
73          Customer JMIKW  NULL        NULL
15          Customer JUWXK  NULL        NULL
...
21          Customer KIDPX  NULL        NULL
30          Customer KSLQF  NULL        NULL
55          Customer KZQZT  NULL        NULL
71          Customer LCOUJ  NULL        NULL
77          Customer LCYBZ  NULL        NULL
66          Customer LHANT  10443       2007-02-12 00:00:00.000
38          Customer LJUCA  NULL        NULL
59          Customer LOLJO  NULL        NULL
36          Customer LVJSO  NULL        NULL
64          Customer LWGMD  NULL        NULL
29          Customer MDLWA  NULL        NULL
...

(91 row(s) affected)

-- Solution
SELECT C.custid, C.companyname, O.orderid, O.orderdate
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON O.custid = C.custid
    AND O.orderdate = \'20070212\';

-- 7 (Optional, Advanced)
-- Return all customers, and for each return a Yes/No value
-- depending on whether the customer placed an order on Feb 12, 2007
-- Tables involved: TSQL2012 database, Customers and Orders tables

-- Desired output
custid      companyname     HasOrderOn20070212
----------- --------------- ------------------
1           Customer NRZBB  No
2           Customer MLTDN  No
3           Customer KBUDE  No
4           Customer HFBZG  No
5           Customer HGVLZ  Yes
6           Customer XHXJV  No
7           Customer QXVLA  No
8           Customer QUHWH  No
9           Customer RTXGC  No
10          Customer EEALV  No
...

(91 row(s) affected)

-- Solution
SELECT DISTINCT C.custid, C.companyname, 
  CASE WHEN O.orderid IS NOT NULL THEN \'Yes\' ELSE \'No\' END AS [HasOrderOn20070212]
FROM Sales.Customers AS C
  LEFT OUTER JOIN Sales.Orders AS O
    ON O.custid = C.custid
    AND O.orderdate = \'20070212\';

  

JAVA入门零基础小白教程day06-类和对象

4day06-JAVAOOP

课程目标

1. 【理解】 什么是面向对象
2. 【理解】 类和对象的关系
3. 【掌握】 类的定义和使用
4. 【掌握】 三大特征之封装
5. 【掌握】 this关键字的使用

一.面向对象概述

1.1什么是面向对象

Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的指引下, 使用Java语言去设计、开发计算机程序。 这里的对象泛指现实中一切事物,每种事物都具备自己的属性行为。面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算 机事件的设计思想。 它区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。

1.2面向过程与面向对象

面向过程

完成一个功能时,功能的每一个步骤,都需要我们进行参与,每一个细节都需要了解清楚,才能完成。强调的是过程。

面向对象

强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去 操作实现

举例

  • 洗衣服

    • 面向过程

      把衣服脱下来–>找一个盆–>放点洗衣粉–>加点水–>浸泡10分钟–>揉一揉–>清洗衣服–>拧干–>晾起来

    • 面向对象

      衣服脱下来 --> 打开全自动洗衣机 -->扔衣服 --> 按钮 ,洗衣机运作–>取出衣服, 晾起来

  • 吃饭

    • 面向过程

      买菜 --> 切菜 --> 洗菜 --> 上锅烧油 爆炒(调料) --> 上盘 --> 开吃 --> 洗碗

    • 面向对象

      饭馆 --> 老板娘来一盘饺子 --> 客户开吃

1.3三大特征

封装 继承 多态

层层递进 互为前提

1.4小结

做事情 首先第一想到的是对象,那个对象能帮我们做事情
	有对象: 直接用
	没有对象: 我们自己造对象在进行使用

二.类和对象

2.1什么是类

是一组相关属性行为的集合。类就是现实生活的一个事物(java语言就是对于现实生活的描述),事物由属性和行为组成。

【类就是描述现实生活中的某一个事物,这个事物是由属性和行为组成】

    • 属性:就是该事物的状态信息。
    • 行为:就是该事物能够做什么。
  • 举例:小猫

    • 属性:名字、体重、年龄、颜色
    • 行为:走、跑、叫。

2.2什么是对象

对象:是一类事物的具体体现。对象是类的一个实例(对象并不是找个女朋友),必然具备该类事物的属性和行为

  • 现实中,一类事物的一个实例:一只小花猫。

  • 举例:一只小猫。

    • 属性:tom、5kg、2 years、yellow。
    • 行为:溜墙根走、蹦跶的跑、喵喵叫。

2.3类与对象的关系

类是对一类事物的描述,是抽象的
对象是一类事物的实例,是具体的
类是对象的模板,对象是类的实体

类:学生                             汽车图纸
对象: 班长,一个具体的对象        大众   宝马   MG

三.类的定义和使用

3.1类的定义

  • 类的组成是由属性和行为两部分组成
    • 属性:在类中通过成员变量来体现(类中方法外的变量)
    • 行为:在类中通过成员方法来体现(和前面的方法相比去掉static关键字即可)

3.1.1语法格式

public class 类名 
	//成员变量 --属性
	//成员方法 --行为

3.1.2定义学生类

public class Student     //成员变量
    String name;//姓名    
    int age;//年龄
    // 成员方法
    // 学习的方法
    public void study() 
        System.out.println("好好学习,天天向上"); 
    
    //吃饭的方法
    public void eat() 
        System.out.println("学习饿了要吃饭");
    

3.2对象的使用

3.2.1创建对象格式

 类名 对象名 = new 类名();

3.2.2访问类中的成员

对象名.成员变量;
对象名.成员方法();

代码演示

public class Test01_Student 
    public static void main(String[] args) 
        //创建对象格式:类名 对象名 = new 类名();
        Student s = new Student();
        System.out.println("s:"+s); //
        //直接输出成员变量值
        System.out.println("姓名:"+s.name); //null
        System.out.println("年龄:"+s.age); //0
        System.out.println("‐‐‐‐‐‐‐‐‐‐");
        //给成员变量赋值
        s.name = "赵丽颖";
        s.age = 18;
        //再次输出成员变量的值
        System.out.println("姓名:"+s.name); //赵丽颖
        System.out.println("年龄:"+s.age); //18
        System.out.println("‐‐‐‐‐‐‐‐‐‐");

        //调用成员方法
        s.study(); // "好好学习,天天向上"
        s.eat(); // "学习饿了要吃饭"
     

3.3成员变量的默认值

3.4类与对象的练习

  • 定义手机类

    public class Phone 
        // 成员变量
        String brand; //品牌
        int price; //价格
        String color; //颜色
        // 成员方法
        //打电话
        public void call(String name) 
            System.out.println("给"+name+"打电话");  
        //发短信
        public void sendMessage() 
            System.out.println("群发短信");
        
    
    
  • 测试类

    public class Test02Phone 
        public static void main(String[] args) 
            //创建对象
            Phone p = new Phone();
    
            //输出成员变量值
            System.out.println("品牌:"+p.brand);//null    
            System.out.println("价格:"+p.price);//0
            System.out.println("颜色:"+p.color);//null
            System.out.println("‐‐‐‐‐‐‐‐‐‐‐‐");
    
            //给成员变量赋值
            p.brand = "锤子";
            p.price = 2999;
            p.color = "棕色";
    
            //再次输出成员变量值
            System.out.println("品牌:"+p.brand);//锤子    
            System.out.println("价格:"+p.price);//2999     
            System.out.println("颜色:"+p.color); //棕色   
            System.out.println("‐‐‐‐‐‐‐‐‐‐‐‐");
    
            //调用成员方法
            p.call("紫霞");
            p.sendMessage();
        
    
    

四.成员变量和局部变量的区别

  • 1在类中的位置不同

    • 成员变量:类中,方法外
    • 局部变量:方法中或者方法声明上(形式参数)
  • 2作用范围不一样

    • 成员变量:类中
    • 局部变量:方法中
  • 3初始化值的不同

    • 成员变量:有默认值
    • 局部变量:没有默认值。必须先定义,在使用前定要初始化
  • 4在内存中的位置不同

    • 成员变量:堆内存
    • 局部变量:栈内存
  • 5生命周期不同

    • 成员变量:随着对象的创建而存在,随着对象的消失而消失
    • 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失

五.封装

5.1什么是封装

   面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。 封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的方式。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。

5.2封装的引入

/*
	定义一个学生类:
		成员变量:name,age
		成员方法:show()方法
	private:私有的。可以修饰成员变量和成员方法。
		注意:被private修饰的成员只能在本类中访问。

	其实我讲到现在讲解的是一个封装的思想。
		封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
*/
public class Student 
    //姓名
    String name;
    //年龄
    private int age;

    /**
     * 为了年龄的正确性,写一个方法给年龄进行赋值
     * 两个明确:  1、需要一个int类型的参数
     *            2、需要不需要返回值类型
     * @param a
     */
    public void setAge(int a)
        if( a <=0 || a >= 100)
            System.out.println("您给出的年龄有问题!!");
        else
            age = a;
        
    

    public void show()
        System.out.println("姓名:"+name);
        System.out.println("年龄:"+age);
    

public class StudentDemo 
    public static void main(String[] args) 
        //创建对象
        Student s = new Student();
        s.show();
        System.out.println("=========================");

        //给成员变量赋值
        s.name = "小江";
        // s.age = 27;
        s.show();
        System.out.println("=========================");

       
        s.name = "小燕";
        //这次给成员变量赋值一个 负数
        // s.age = -27;
        //年龄给一个负数不合理,那如何是好呢?
        //解决办法:不让用户直接赋值(private),然后方法(setAge())进行判断
        s.setAge(27);
        s.show();
    

5.3封装的原则

属性隐藏起来,若需要访问某个属性,提供公共方法对其访问。

5.3.1如何封装

  • 使用 private 关键字来修饰成员变量。
  • 对需要访问的成员变量,提供公共对应的一对 getXxx 方法 、 setXxx 方法。

5.3.2private 关键字

  • 什么是private关键字

    1. private是一个权限修饰符,代表最小权限。 
    2. 可以修饰成员变量和成员方法。 
    3. 被private修饰后的成员变量和成员方法,只在本类中才能访问
    
  • private的使用格式

    private 数据类型 变量名 ;

  • 使用 private 修饰成员变量,代码如下

    public class Student 
        //private修饰成员变量
        private int num = 10;
    
        public void show()
            //private 只能在本类中使用
            System.out.println(num);
        
        //private修饰成员
        private void method()
            System.out.println("我是method");
        
        public void function()
            //private 只能在本类中使用
            method();
        
    
    

public class StudentTest 
    public static void main(String[] args) 

        Student s = new Student();

        //不能访问私有的成员变量
        // System.out.println(s.num);

        s.show();

        //不能访问私有的成员方法
        // s.method();

        s.function();
    


  • 提供 getXxx 方法 / setXxx 方法,可以访问成员变量,代码如下

    public class Student 
        //姓名
        private String name;
        //年龄
        private int age;
    
        //姓名获取值
        public String getName()
            return name;
        
        //姓名设置值
        public void setName(String n)
            name = n;
        
        //年龄获取值
        public int getAge()
            return age;
        
        //年龄设置值
        public void setAge(int a)
            age = a;
        
    
    
    
  public class StudentDemo 
      public static void main(String[] args) 
  
          //创建对象
          Student s = new Student();
  
          //使用成员变量
          //错误: 私有的成员变量是不能被访问的
          // System.out.println(s.name);
          // System.out.println(s.age);
  
          //通过方法访问成员变量
          System.out.println(s.getName()+" : "+s.getAge());
  
          //给成员变量赋值
          s.setName("一燕");
          s.setAge(18);
          System.out.println(s.getName()+" : "+s.getAge());
  
      
  

5.3.3 this 关键字

  • 问题描述

    我们发现 setXxx 方法中的形参名字并不符合见名知意的规定,那么如果修改与成员变量名一致,是否就见名知意 了呢?代码如下:

    public class Student 
        private String name;
        private int age;
        
        public void setName(String name)    
            name = name;
        
        public void setAge(int age) 
            age = age;
        
    
    

    ​ 经过修改和测试,我们发现新的问题,成员变量赋值失败了。也就是说,在修改了 setXxx() 的形参变量名后,方法并没有给成员变量赋值!这是由于形参变量名与成员变量名重名,导致成员变量名被隐藏,方法中的变量名,无 法访问到成员变量,从而赋值失败。所以,我们只能使用this关键字,来解决这个重名问题。

  • this 的含义

    this代表所在类的当前对象的引用(地址值),即对象自己的引用。

    • 记住 :方法被哪个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁。
  • this 的使用格式

    this.成员变量名;

  • 代码修改

    public class Student 
        private String name;
        private int age;
    
        public void setName(String name)  
            //name = name;
            this.name = name;
        
        public String getName() 
            return name;//其实这里隐含this
        
        public void setAge(int age) 
            //age = age;
            this.age = age;
        
        public int getAge() 
            return age;
        
    
    
    • 小贴士:方法中只有一个变量名时,默认也是使用 this 修饰,可以省略不写。

六.构造方法

6.1构造方法概述

构造方法: 用于对象数据初始化

小贴士:无论你与否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个无参数构造方法,

一旦自己定义了构造方法,Java自动提供的默认无参数构造方法就会失效。

6.2构造方法的定义格式

/*
	构造方法名与类名相同
	没有返回值类型,连void
	没有具体的返回值
*/

修饰符 构造方法名(参数列表) 
    // 方法体 

6.3构造方法的使用

构造方法的写法上,方法名与它所在的类名相同。它没有返回值,所以不需要返回值类型,甚至不需要void。使用

构造方法后,代码如下

public class Student 
    private String name;
    private int age;
    
    // 无参数构造方法
    public Student() 
        System.out.println("我是无参构造方法");
     
    
    // 有参数构造方法
    public Student(String name,int age)     
        this.name = name;
        this.age = age; 
    

public class StudentDemo 
    public static void main(String[] args) 

        //无参构造
        Student s = new Student();
        System.out.println(s);

        //有参构造
        Student s1 = new Student("小燕",27);
        System.out.println(s1.getName());
        System.out.println(s1.getAge());
    

6.3构造方法重载

// 构造方法是可以重载的
public class Student 

    public Student() 
    

    public Student(String name, int age) 
        this.name = name;
        this.age = age;
    

    public Student(String name) 
        this.name = name;
    

    public Student(int age) 
        this.age = age;
    
   

6.4构造方法的注意事项

1. 如果你不提供构造方法,系统会给出无参数构造方法。√
2. 如果你提供了构造方法,系统将不再提供无参数构造方法。
3. 构造方法是可以重载的,既可以定义参数,也可以不定义参数。

需求: 现在类是可以创建对象,但是有些情况下不让别人创建对象,请问怎么办?

​ 构造方法私有

标准JavaBean编写

JavaBean 是 Java语言编写类的一种标准规范。

符合 JavaBean 的类,有构造方法 , 提供操作属性的set get方法

public class ClassName  
    //成员变量
    //构造方法
    	//无参构造方法【必须】  
    	//有参构造方法【建议】  
    //成员方法    
    	//getXxx()
    	//setXxx()

编写Student类

public class Student 
    //成员变量
    private String name;
    private int age;

    //构造方法
    public Student() 

    public Student(String name,int age)     
        this.name = name;
        this.age = age;
    

    //成员方法
    publicvoid setName(String name) 
        this.name = name;
    

    public String getName() 
        return name;
    

    publicvoid setAge(int age) 
        this.age = age;
    

    publicint getAge() 
        return age;
    

测试

public class TestStudent 
    public static void main(String[] args) 
        //无参构造使用
        Student s= new Student();
        s.setName("柳岩");
        s.setAge(18);
        System.out.println(s.以上是关于T-SQL基础教程Day3的主要内容,如果未能解决你的问题,请参考以下文章

T-SQL基础教程Day1

后端开发MySQL基础知识 - day3笔记

JAVA零基础入门系列Day3 Java基本数据类型

python基础day3

Day3 python基础3

Python基础篇-day3