-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathChapter 3.sql
210 lines (179 loc) · 6.32 KB
/
Chapter 3.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
--3.1.1 Window aggregate examples
SELECT CustomerID, SalesOrderID,
CAST(MIN(OrderDate) OVER() AS DATE) AS FirstOrderDate,
CAST(MAX(OrderDate) OVER() AS DATE) AS LastOrderDate,
COUNT(*) OVER() OrderCount,
FORMAT(SUM(TotalDue) OVER(),'C') TotalAmount
FROM Sales.SalesOrderHeader
ORDER BY CustomerID, SalesOrderID;
--3.1.2 Use PARTITION BY
SELECT CustomerID, SalesOrderID,
CAST(MIN(OrderDate) OVER(PARTITION BY CustomerID) AS DATE)
AS FirstOrderDate,
CAST(MAX(OrderDate) OVER(PARTITION BY CustomerID) AS DATE)
AS LastOrderDate,
COUNT(*) OVER(PARTITION BY CustomerID) OrderCount,
FORMAT(SUM(TotalDue) OVER(PARTITION BY CustomerID),'C') AS TotalAmount
FROM Sales.SalesOrderHeader
ORDER BY CustomerID, SalesOrderID;
--3.2.1 Use different OVER clauses
SELECT CustomerID, SalesOrderID, FORMAT(TotalDue,'c') AS TotalDue,
FORMAT(SUM(TotalDue) OVER(PARTITION BY CustomerID),'c') AS CustomerSales,
FORMAT(SUM(TotalDue) OVER(),'c') AS TotalSales
FROM Sales.SalesOrderHeader
WHERE OrderDate >= '2013-01-01' AND OrderDate < '2014-01-01'
ORDER BY CustomerID, SalesOrderID;
--3-3-1 Using window functions in expressions
SELECT CustomerID, SalesOrderID,
CAST(OrderDate AS Date) AS OrderDate,
MIN(SalesOrderID/CustomerID)
OVER(PARTITION BY CustomerID) AS Expr1,
CAST(MIN(DATEADD(d,1,OrderDate)) OVER() AS DATE) AS Expr2,
AVG((SELECT COUNT(*)
FROM Sales.SalesOrderDetail AS SOD
WHERE SalesOrderID = SOH.SalesOrderID)) OVER() AS Expr3
FROM Sales.SalesOrderHeader AS SOH;
--3-4.1 Add a window aggregate to an aggregate query
SELECT CustomerID, SUM(TotalDue) AS CustomerTotal,
SUM(TotalDue) OVER() AS GrandTotal
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;
--3-5.1 How to add a window aggregate to an aggregate query
SELECT CustomerID, SUM(TotalDue) AS CustomerTotal,
SUM(SUM(TotalDue)) OVER() AS GrandTotal
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;
--3.6.1 Using a CTE
WITH SALES AS (
SELECT CustomerID, SUM(TotalDue) AS CustomerTotal
FROM Sales.SalesOrderHeader
GROUP BY CustomerID)
SELECT CustomerID, CustomerTotal,
SUM(CustomerTotal) OVER() AS GrandTotal
FROM Sales;
--3-7.1 Window aggregate to multiple group by
SELECT YEAR(OrderDate) AS OrderYear,
CustomerID, SUM(TotalDue) AS CustTotalForYear,
SUM(SUM(TotalDue)) OVER(PARTITION BY CustomerID) AS CustomerTotal
FROM Sales.SalesOrderHeader
GROUP BY CustomerID, YEAR(OrderDate)
ORDER BY CustomerID, OrderYear;
--3-8.1 Calculate the percent of sales
SELECT P.ProductID,
FORMAT(SUM(OrderQty * UnitPrice),'C') AS ProductSales,
FORMAT(SUM(SUM(OrderQty * UnitPrice)) OVER(),'C') AS TotalSales,
FORMAT(SUM(OrderQty * UnitPrice)/
SUM(SUM(OrderQty * UnitPrice)) OVER(), 'P') AS PercentOfSales
FROM Sales.SalesOrderDetail AS SOD
JOIN Production.Product AS P ON SOD.ProductID = P.ProductID
JOIN Production.ProductSubcategory AS SUB ON P.ProductSubcategoryID
= SUB.ProductSubcategoryID
JOIN Production.ProductCategory AS CAT ON SUB.ProductCategoryID
= CAT.ProductCategoryID
WHERE CAT.Name = 'Bikes'
GROUP BY P.ProductID
ORDER BY PercentOfSales DESC;
--3-9.1 Create the partition function
CREATE PARTITION FUNCTION testFunction (DATE)
AS RANGE RIGHT
FOR VALUES ('2011-01-01','2012-01-01','2013-01-01','2014-01-01');
GO
--3-9.2 Create the partition scheme
CREATE PARTITION SCHEME testScheme
AS PARTITION testFunction ALL TO ('Primary');
GO
--3-9.3 Create a partitioned table
CREATE TABLE dbo.Orders(CustomerID INT, SalesOrderID INT,
OrderDate DATE, TotalDue MONEY)
ON testScheme(OrderDate);
GO
--3-9.4 Populate the table
INSERT INTO dbo.Orders(customerID, SalesOrderID,
OrderDate, TotalDue)
SELECT CustomerID, SalesOrderID,
OrderDate, TotalDue
FROM Sales.SalesOrderHeader;
GO
--3-9.5 Create another partitioned table
CREATE TABLE dbo.Customer (CustomerID INT, ModifiedDate DATE)
ON testScheme(ModifiedDate);
GO
--3-9.6 Populate the table
INSERT INTO dbo.Customer(CustomerID, ModifiedDate)
SELECT CustomerID, ModifiedDate
FROM Sales.Customer
--3-10.1 The query from my collegue
SELECT OBJECT_NAME(p.OBJECT_ID) TableName,
ps.partition_number, ps.Row_count
FROM sys.data_spaces d
JOIN sys.indexes i
JOIN (SELECT DISTINCT OBJECT_ID
FROM sys.partitions
WHERE partition_number > 1) p
ON i.OBJECT_ID = p.OBJECT_ID
ON d.data_space_id = i.data_space_id
JOIN sys.dm_db_partition_stats ps
ON i.OBJECT_ID = ps.OBJECT_ID and i.index_id = ps.index_id
WHERE i.index_id < 2;
--3-10.2 The solution to find the percent of rows by table
SELECT OBJECT_NAME(p.OBJECT_ID) TableName,
ps.partition_number, ps.Row_count,
--My solution starts here
FORMAT(ps.row_count * 1.0 /
SUM(ps.row_count) OVER(PARTITION BY p.OBJECT_ID),'p')
As PercentOfRows
--and ends here
FROM sys.data_spaces d
JOIN sys.indexes i
JOIN (SELECT DISTINCT OBJECT_ID
FROM sys.partitions
WHERE partition_number > 1) p
ON i.OBJECT_ID = p.OBJECT_ID
ON d.data_space_id = i.data_space_id
JOIN sys.dm_db_partition_stats ps
ON i.OBJECT_ID = ps.OBJECT_ID and i.index_id = ps.index_id
WHERE i.index_id < 2;
--3-11 Drop objects created in this section
DROP TABLE dbo.Customer;
DROP TABLE dbo.Orders;
DROP PARTITION SCHEME testScheme;
DROP PARTITION FUNCTION testFunction;
--3-12.1 Enable CRL
EXEC sp_configure 'clr_enabled', 1;
GO
RECONFIGURE;
GO
--3-12.2 Enable an unsigned assembly
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'clr strict security',0
GO
RECONFIGURE;
--3-12.3 Register the DLL
CREATE ASSEMBLY CustomAggregate FROM
'C:\Custom\CustomAggregate.dll' WITH PERMISSION_SET = SAFE;
GO
--3-12.4 Create the function
CREATE Aggregate Median (@Value INT) RETURNS INT
EXTERNAL NAME CustomAggregate.Median;
GO
--3-12.5 Test the function
WITH Orders AS (
SELECT CustomerID, SUM(OrderQty) AS OrderQty, SOH.SalesOrderID
FROM Sales.SalesOrderHeader AS SOH
JOIN Sales.SalesOrderDetail AS SOD
ON SOH.SalesOrderID = SOD.SalesOrderDetailID
GROUP BY CustomerID, SOH.SalesOrderID)
SELECT CustomerID, OrderQty, dbo.Median(OrderQty) OVER(PARTITION BY CustomerID) AS Median
FROM Orders
WHERE CustomerID IN (13011, 13012, 13019);
--3-13.1 Drop the objects
DROP AGGREGATE Median;
DROP ASSEMBLY CustomAggregate;
GO
--3-13.2 Reset CLR integration to the defaults
EXEC sp_configure 'clr_enabled', 0;
GO
RECONFIGURE;
EXEC sp_configure 'clr strict security',1;
GO