-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy path02_EAV.sql
174 lines (139 loc) · 4.63 KB
/
02_EAV.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
-- =============================================
-- Author: Gianluca Sartori - @spaghettidba
-- Create date: 2016-09-07
-- Description: Demonstrates the sins of EAV design
-- =============================================
--:r 00_SETUP.sql
USE tempdb;
GO
IF OBJECT_ID('Values') IS NOT NULL DROP TABLE [Values];
IF OBJECT_ID('Attributes') IS NOT NULL DROP TABLE Attributes;
IF OBJECT_ID('Entities') IS NOT NULL DROP TABLE Entities;
CREATE TABLE Attributes (
attribute_id INT NOT NULL PRIMARY KEY CLUSTERED
,attribute_name NVARCHAR(128) NOT NULL
)
GO
CREATE TABLE Entities (
entity_id INT NOT NULL PRIMARY KEY CLUSTERED
,entity_name NVARCHAR(128) NOT NULL
)
GO
CREATE TABLE [Values] (
attribute_id INT NOT NULL FOREIGN KEY (attribute_id) REFERENCES Attributes(attribute_id)
,entity_id INT NOT NULL FOREIGN KEY (entity_id) REFERENCES Entities(entity_id)
,id INT NOT NULL -- Id from the referencing table
,value NVARCHAR(4000) NOT NULL
,PRIMARY KEY CLUSTERED (
attribute_id
,entity_id
,id
)
)
GO
INSERT INTO Entities VALUES
(1, 'Customers'),
(2, 'Orders');
INSERT INTO Attributes VALUES
(1, 'Delivery Date'),
(2, 'Canceled Date'),
(3, 'Email Address'),
(4, 'Telephone Number'),
(5, 'Window width');
INSERT INTO [Values] (
attribute_id,
entity_id,
id,
value
)
VALUES
(1, 2, 1, '20160401'), -- Delivery Date Order 1
(1, 2, 2, '20160409'), -- Delivery Date Order 2
(1, 2, 3, '20160612'), -- Delivery Date Order 3
(1, 2, 5, '20160230'), -- Delivery Date Order 5 -- Invalid!
(1, 2, 6, '20160725'), -- Delivery Date Order 6
(1, 2, 7, '20161920'), -- Delivery Date Order 7
(2, 2, 3, '20160522'), -- Cancellation Date Order 3
(3, 1, 1, '[email protected]'), -- Email address customer 1
(3, 1, 2, '[email protected]'), -- Email address customer 2
(3, 1, 3, '[email protected]'), -- Email address customer 3
(4, 1, 1, '3282333002'), -- Telephone number of customer 1
(4, 1, 2, '3351245963'), -- Telephone number of customer 2
(4, 1, 3, '3482386666'), -- Telephone number of customer 3
(5, 1, 1, '5,1m'), -- Window size customer 1 (depends on regional options!)
(5, 1, 2, '5.1'), -- Window size customer 2 (depends on regional options!)
(5, 1, 3, 'no window'), -- Window size customer 3
(5, 1, 4, '410'); -- Window size customer 2
SELECT *
FROM [Values];
SELECT E.entity_name, A.attribute_name, V.id, V.value
FROM [Values] AS V
INNER JOIN Attributes AS A
ON V.attribute_id = A.attribute_id
INNER JOIN Entities AS E
ON V.entity_id = E.entity_id;
-- Customers:
SELECT C.*
,Email.Value AS Email
,Telephone.Value AS Telephone
,Window.Value AS Window
FROM Customers AS C
LEFT JOIN [Values] AS Email
ON Email.attribute_id = 3
AND Email.entity_id = 1
AND Email.id = C.customer_id
LEFT JOIN [Values] AS Telephone
ON Telephone.attribute_id = 4
AND Telephone.entity_id = 1
AND Telephone.id = C.customer_id
LEFT JOIN [Values] AS Window
ON Window.attribute_id = 5
AND Window.entity_id = 1
AND Window.id = C.customer_id;
-- Orders:
SELECT O.*
,Delivery.Value AS DeliveryDate
,Cancel.Value AS CancelDate
FROM Orders AS O
LEFT JOIN [Values] AS Delivery
ON Delivery.attribute_id = 1
AND Delivery.entity_id = 2
AND Delivery.id = O.order_id
LEFT JOIN [Values] AS Cancel
ON Cancel.attribute_id = 2
AND Cancel.entity_id = 2
AND Cancel.id = O.order_id
-- All orders shipped within a week:
WHERE DATEDIFF(day, Delivery.value, O.order_date) <= 7
-- PIVOT
;
WITH CustomerAttributes AS (
SELECT *
FROM (
SELECT id, attribute_id, value
FROM [Values]
WHERE entity_id = 1
) AS src
PIVOT( MAX(value) FOR attribute_id IN ([3],[4],[5])) AS pvt
)
SELECT C.*
,CA.[3] AS Email
,CA.[4] AS Telephone
,CA.[5] AS Window
FROM Customers AS C
LEFT JOIN CustomerAttributes AS CA
ON C.customer_id = CA.id;
-- crosstab
WITH customerattributes as (
SELECT id
,email = max(case attribute_id when 3 then value end)
,telephone = max(case attribute_id when 4 then value end)
,window = max(case attribute_id when 5 then value end)
FROM [values]
WHERE entity_id = 1
GROUP BY id
)
SELECT *
FROM customers as c
LEFT JOIN customerattributes as ca
on c.customer_id = ca.id;