SQL查询基础-源动力

2021-07-19  本文已影响0人  苦难_69e0

遇事不会查文档:

https://docs.microsoft.com/zh-cn/sql/sql-server/?view=sql-server-ver15

单表查询

Select语句的元素

USE AdventureWorks2014;
GO
SELECT SH.SalesPersonID,
       YEAR(SH.OrderDate) AS OrderYear,
       COUNT(*) NumOrders
FROM Sales.SalesOrderHeader SH
WHERE SH.CustomerID = 29825
GROUP BY SH.SalesPersonID,
         YEAR(SH.OrderDate)
HAVING COUNT(*) > 1
ORDER BY SH.SalesPersonID,
         OrderYear;
执行顺序.png

谓词和运算符

TSQL可以使用逻辑表达式

逻辑表达式可以使用的谓词(取值为True/False/Unknown)

比较运算符
=, >,<,>=, <=, <> (!=, !>, !<为非标准写法)

逻辑运算符
or, and, not

算术运算符
+,-,*,/,%(取模)

运算符优先级

CASE表达式

标量表达式, 基于条件逻辑返回一个值

USE Test;
GO
SELECT *,
       CASE gender
           WHEN 'male' THEN
               N'男生'
           WHEN 'female' THEN
               N'女生'
       END genderInChinese
FROM dbo.student;
USE Test;
GO
SELECT *,
       CASE
           WHEN DATEDIFF(YEAR, birthday, GETDATE()) <= 10 THEN
               N'小于10岁'
           ELSE
               N'超过10岁'
       END ageDesc
FROM dbo.student;

NULL值

NULL是Unkown

NULL与任何值进行运算结果是NULL

NULL取反仍是NULL

NULL的判断

SQL Server对于唯一约束中, 多个NULL视作一个NULL

处理字符数据

1.两种数据类型

处理日期和时间数据

1.日期类型

2.字符串到日期的转换

隐式转换依赖于

显式转换

3.常用日期函数

联接查询

交叉联接

image.png
USE Test;
GO
SELECT *
FROM dbo.student
CROSS JOIN dbo.class;

USE Test;
GO
SELECT *
FROM dbo.student,dbo.class;

内连接

USE Test;
GO
SELECT *
FROM dbo.student
INNER JOIN dbo.class
ON class.id=student.classid;

USE Test;
GO
SELECT *
FROM dbo.student,dbo.class
Where class.id=student.classid;

特殊的联接实例

 USE Test;
GO
SELECT *
FROM dbo.T1
INNER JOIN dbo.T2
ON T1.col1=T2.col1 and T1.col2=T2.col2;
USE Test;
GO
SELECT *
FROM dbo.T1
INNER JOIN dbo.T2
ON T1.col1<T2.col1; 
USE Test;
GO
SELECT *
FROM dbo.T1
INNER JOIN dbo.T2
ON T1.col1=T2.col1
INNER JOIN dbo.T3
ON T1.col1=T3.col1;

外联接

1.笛卡尔积+ON过滤+外部行

2.3种类型

USE Test;
GO
SELECT *
FROM dbo.class
Left JOIN dbo.student
ON class.id=student.classid;
USE Test;
GO
SELECT *
FROM dbo.class
right JOIN dbo.student
ON class.id=student.classid;
USE Test;
GO
SELECT *
FROM dbo.class
full JOIN dbo.student
ON class.id=student.classid;

子查询

独立子查询

USE AdventureWorks2014;
GO
SELECT s.SalesOrderNumber,
       s.OrderDate,
       s.CustomerID,
       s.SalesPersonID
FROM sales.SalesOrderHeader s
WHERE s.SalesOrderID =
(
    SELECT MAX(SalesOrderID) 
    FROM sales.SalesOrderHeader
);

相关子查询

USE AdventureWorks2014;
GO
SELECT SH.CustomerID,
       SH.SalesOrderID,
       SH.SalesPersonID
FROM sales.SalesOrderHeader SH
WHERE SH.SalesOrderID =
(
    SELECT MAX(SH2.SalesOrderID)
    FROM sales.SalesOrderHeader SH2
    WHERE SH.CustomerID = SH2.CustomerID
);

表表达式

派生表

1.在外部查询的FROM子句中定义
2.存在范围为定义它的外部查询,只要外部查询一结束,派生表就不存在了
3.派生表可以嵌套
4.查询语句满足的条件

USE AdventureWorks2014;
GO
SELECT *
FROM
(
    SELECT s.SalesOrderID,
           s.CustomerID,
           s.SalesPersonID
    FROM sales.SalesOrderHeader s
    WHERE s.TerritoryID = 5
) AS T;

CTE

CTE:公用表表达式

用途

注意

USE AdventureWorks2014;
GO
WITH source
AS (SELECT s.SalesOrderID,
           s.CustomerID,
           s.SalesPersonID
    FROM sales.SalesOrderHeader s
    WHERE s.TerritoryID = 5)
SELECT *
FROM source;

USE AdventureWorks2014;
GO
WITH subq (n, factorial)
AS (SELECT 1,
           1
    UNION ALL
    SELECT n + 1,
           factorial * (n + 1)
    FROM subq
    WHERE n < 5)
SELECT *
FROM subq;

内联表值函数

USE AdventureWorks2014;
GO
CREATE FUNCTION dbo.fn_getCustOrder
(
    @cid INT
)
RETURNS TABLE
AS
RETURN SELECT SH.SalesOrderID,
              SH.CustomerID,
              SH.SalesPersonID
       FROM sales.SalesOrderHeader SH
       WHERE SH.CustomerID = @cid;
GO
Select * from db.fn_getCustOrder(1);

APPLY运算符

两种形式

USE AdventureWorks2014;
GO
SELECT SH.CustomerID, A.SalesOrderID, A.OrderDate
FROM sales.Customer SH
CROSS/OUTER APPLY(
SELECT TOP 3 SH2.SalesOrderID, SH2.OrderDate
FROM sales.SalesOrderHeader SH2
WHERE SH.CustomerID=SH2.CustomerID
ORDER BY SH2.OrderDate DESC, SH2.SalesOrderID DESC
) A;

集合运算

并集UNION

并集.png
USE AdventureWorks2014;
GO
SELECT 1 id,
       'a' name
UNION
SELECT 1,
       ‘a';
USE AdventureWorks2014;
GO
SELECT 1 id,
       'a' name
UNION ALL
SELECT 2,
       'b';

交集InsertSect

返回两个集合中共同的部分

交集.png
USE AdventureWorks2014;
GO
SELECT d.ProductID
FROM sales.SalesOrderHeader h
    INNER JOIN sales.SalesOrderDetail d
        ON h.SalesOrderID = d.SalesOrderID
WHERE h.CustomerID = 29825
INTERSECT
SELECT d.ProductID
FROM sales.SalesOrderHeader h
    INNER JOIN sales.SalesOrderDetail d
        ON h.SalesOrderID = d.SalesOrderID
WHERE h.CustomerID = 29672;

差集except

返回两个集合不同的部分

差集.png
USE AdventureWorks2014;
GO
SELECT *
FROM (
SELECT 1 id, 'a' name
UNION ALL
SELECT 2 id, 'b' name
) A
EXCEPT
SELECT *
FROM
(
SELECT 1 id, 'a' name
UNION ALL
SELECT 3 id, 'c' name
) B

集合运算的优先级

With A as (
SELECT 1 id, 'a' name
UNION ALL
SELECT 2 id, 'b' name
),B as (
SELECT 1 id, 'a' name
UNION ALL
SELECT 3 id, 'c' name
),C as (
SELECT 1 id, 'a' name
UNION ALL
SELECT 2 id, 'b' name
UNION ALL
SELECT 3 id, 'c' name
)
select *
from A
except
select *
from B
intersect 
select *
from C

思维导图

思维导图.png

实战

从AdventureWorks2014数据库,写一个单表聚合查询,表示某一年的所有地区的,产品大类的销量统计

USE AdventureWorks2014
GO
SELECT st.Name AS customTerritory,pc.Name AS productcategory,SUM(sd.OrderQty) AS totalqty
FROM Sales.SalesOrderHeader SH
INNER JOIN Sales.SalesOrderDetail SD
ON SD.SalesOrderID = SH.SalesOrderID
INNER JOIN Sales.Customer SC
ON SC.CustomerID = SH.CustomerID
INNER JOIN Sales.SalesTerritory ST
ON ST.TerritoryID = SC.TerritoryID
INNER JOIN Production.Product PP
ON PP.ProductID = SD.ProductID
INNER JOIN Production.ProductSubcategory PS
ON PS.ProductSubcategoryID = PP.ProductSubcategoryID
INNER JOIN Production.ProductCategory PC
ON PC.ProductCategoryID = PS.ProductCategoryID
WHERE SH.OrderDate BETWEEN CAST('20110101' AS DATETIME) AND CAST('20111231' AS DATETIME)
GROUP BY st.Name,pc.Name
ORDER BY totalqty desc

查看Color有多少null

SELECT 
SUM(CASE WHEN pp.Color IS NULL THEN 1 ELSE 0 END) AS totalnull,
SUM(CASE WHEN pp.Color IS NOT NULL THEN 1 ELSE 0 END) AS NOTNULL
FROM Production.Product pp

展开各种颜色都有多少

SELECT pp.Color,SUM(CASE WHEN pp.Color IS NULL THEN 1 ELSE 0 END) AS total
FROM Production.Product pp
GROUP BY pp.Color

打印九九乘法表

WITH nums
AS (SELECT number
    FROM master..spt_values
    WHERE type = 'P'
          AND number
          BETWEEN 1 AND 9)
SELECT a.number,
       (
           SELECT CAST(b.number AS VARCHAR) + '*'+CAST(a.number AS VARCHAR)+ '=' + CAST(a.number*b.number AS VARCHAR) + ' '
           FROM nums b
           WHERE b.number <= a.number
           ORDER BY b.number
           FOR XML PATH('')
       )
FROM nums a;

ABCD*E=FGHI 解题 0<A~I<=9

WITH nums
AS (SELECT number
    FROM master..spt_values
    WHERE type = 'P'
          AND number
          BETWEEN 1 AND 9)
SELECT a.number,
       (
        select cast(a.number*1000+b.number*100+c.number*10+d.number as varchar) + '*' + cast(e.number as varchar) +'='+ cast(f.number*1000+g.number*100+h.number*10+i.number as varchar)
        from nums b,nums c,nums d,nums e,nums f,nums g,nums h,nums i 
        where a.number not in (b.number,c.number,d.number,e.number,f.number,g.number,h.number,i.number) and
        b.number not in (c.number,d.number,e.number,f.number,g.number,h.number,i.number) and
        c.number not in (d.number,e.number,f.number,g.number,h.number,i.number) and
        d.number not in (e.number,f.number,g.number,h.number,i.number) and
        e.number not in (f.number,g.number,h.number,i.number) and
        f.number not in (g.number,h.number,i.number) and
        g.number not in (h.number,i.number) and
        h.number not in (i.number) and
        (a.number*1000+b.number*100+c.number*10+d.number)*e.number = (f.number*1000+g.number*100+h.number*10+i.number)
     ORDER BY e.number
     FOR XML PATH('')
        )
FROM nums a;

拆分字符串

DECLARE @LongStr VARCHAR(MAX) = '';
WITH nums
AS (SELECT number
    FROM master..spt_values
    WHERE type = 'P'
          AND number
          BETWEEN 1 AND 9)
SELECT @LongStr = @LongStr + CAST(number AS VARCHAR) + ','
FROM nums;

PRINT @LongStr;

--SELECT CHARINDEX(',',@LongStr);
--GO
CREATE TABLE #T( ID INT IDENTITY(1,1),ELE VARCHAR(100));
DECLARE @LongStr VARCHAR(MAX) = 'asfgjhajkshfgkljas';
DECLARE @x VARCHAR(MAX);
DECLARE @i INT=1
WHILE @i<= LEN(@LongStr)
BEGIN
    SELECT @x = SUBSTRING(@LongStr,@i,CHARINDEX(SUBSTRING(@LongStr,@i,1),@LongStr)-1)
    INSERT INTO #T
    (
        ELE
    )
    VALUES
    (@x)
    --SET @LongStr=
    SET @i=@i+1
END
SELECT * FROM #T
DROP TABLE #T;

身份证号统计90后

with source as (
select 1 id, 'a' name,  '42092219900101000' code union all
select 2 id, 'b' name,  '42092219910101000' code union all
select 3 id, 'c' name,  '42092219920101000' code union all
select 4 id, 'd' name,  '42092219930101000' code union all
select 5 id, 'e' name,  '42092219940101000' code union all
select 6 id, 'f' name,  '42092220000101000' code union all
select 7 id, 'g' name,  '42092220100101000' code union all
select 8 id, 'h' name,  '42092220200101000' code union all
select 9 id, 'i' name,  '42092220300101000' code union all
select 10 id, 'j' name, '42092219950101000' code union all
select 11 id, 'k' name, '42092219960101000' code union all
select 12 id, 'l' name, '42092219970101000' code union all
select 13 id, 'm' name, '42092219980101000' code 
)
select *
from source;

给定一个父级节点,找到该节点的所有子孙节点;给定一个节点, 找到该节点的所有祖宗

WITH source AS (
SELECT 1  id, NULL AS parentid, 'a' name UNION ALL
SELECT 2  id, 1    AS parentid, 'b' name UNION ALL
SELECT 3  id, 1           AS parentid, 'c' name UNION ALL
SELECT 4  id, 2    AS parentid, 'd' name UNION ALL
SELECT 5  id, 2    AS parentid, 'e' name UNION ALL
SELECT 6  id, 2    AS parentid, 'f' name UNION ALL
SELECT 7  id, 3 AS parentid, 'g' name UNION ALL
SELECT 8  id, 3 AS parentid, 'h' name UNION ALL
SELECT 9  id, 4 AS parentid, 'i' name UNION ALL
SELECT 10 id, 4 AS parentid, 'j' name UNION ALL
SELECT 11 id, 5 AS parentid, 'k' name UNION ALL
SELECT 12 id, 5 AS parentid, 'l' name UNION ALL
SELECT 13 id, 6 AS parentid, 'm' name UNION ALL
SELECT 14 id, 7 AS parentid, 'n' name UNION ALL
SELECT 15 id, 14 AS parentid, 'o' name 
)
SELECT * INTO employee
FROM source;
GO
SELECT * FROM dbo.employee;

--1,给定一个父级节点,找到该节点的所有子孙节点
DECLARE @NodeId INT = 14;

WITH mycte (parentid, ID, level, name)
AS (SELECT parentid,
           id,
           0 level,
           name
    FROM employee
    WHERE id = @NodeId
    UNION ALL
    SELECT p.parentid,
           p.id,
           o.level + 1,
           p.name
    FROM mycte o
        INNER JOIN employee p
            ON o.ID = p.parentid)
SELECT *
FROM mycte
where level>0

--2,给定一个节点, 找到该节点的所有祖宗
DECLARE @NodeId1 INT = 15;

WITH mycte (parentid, ID, level, name)
AS (SELECT parentid,
           id,
           0 level,
           name
    FROM employee
    WHERE id = @NodeId1
    UNION ALL
    SELECT p.parentid,
           p.id,
           o.level + 1,
           p.name
    FROM mycte o
        INNER JOIN employee p
            ON o.parentid = p.ID)
SELECT *
FROM mycte
where level>0
ORDER BY mycte.parentid

上一篇 下一篇

猜你喜欢

热点阅读