-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpgsetup.sql
More file actions
471 lines (393 loc) · 11.1 KB
/
pgsetup.sql
File metadata and controls
471 lines (393 loc) · 11.1 KB
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
DO
$do$
BEGIN
IF NOT EXISTS (
SELECT -- SELECT list can stay empty for this
FROM pg_catalog.pg_user
WHERE usename = 'spurioususer') THEN
CREATE USER spurioususer WITH
LOGIN
NOSUPERUSER
INHERIT
NOCREATEDB
NOCREATEROLE
NOREPLICATION;
END IF;
END
$do$;
CREATE DATABASE spurious
WITH
OWNER = spurioususer
ENCODING = 'UTF8'
CONNECTION LIMIT = -1;
DO
$do$
BEGIN
IF NOT EXISTS (
SELECT -- SELECT list can stay empty for this
FROM pg_extension
WHERE extname = 'adminpack') THEN
create extension adminpack;
END IF;
END
$do$;
DO
$do$
BEGIN
IF NOT EXISTS (
SELECT -- SELECT list can stay empty for this
FROM pg_extension
WHERE extname = 'postgis') THEN
create extension postgis;
END IF;
END
$do$;
create table IF NOT EXISTS boundary_incoming (
id integer not null,
boundary_gml text,
name text,
province text,
CONSTRAINT bi_firstkey PRIMARY KEY (id)
);
ALTER TABLE boundary_incoming
OWNER TO spurioususer;
create table IF NOT EXISTS population_incoming (
id integer not null,
population integer,
name text,
CONSTRAINT pi_firstkey PRIMARY KEY (id)
);
ALTER TABLE population_incoming
OWNER TO spurioususer;
create table IF NOT EXISTS store_incoming (
id integer not null,
latitude decimal,
longitude decimal,
name text,
city text,
CONSTRAINT si_firstkey PRIMARY KEY (id)
);
ALTER TABLE store_incoming
OWNER TO spurioususer;
create table IF NOT EXISTS product_incoming (
id integer NOT NULL,
name text,
category text,
volume integer,
CONSTRAINT pri_firstkey PRIMARY KEY (id)
);
ALTER TABLE product_incoming
OWNER TO spurioususer;
CREATE TABLE IF NOT EXISTS inventory_incoming
(
product_id integer NOT NULL,
store_id integer NOT NULL,
quantity integer,
CONSTRAINT inventory_incoming_pkey PRIMARY KEY (product_id, store_id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE inventory_incoming
OWNER TO spurioususer;
create table IF NOT EXISTS subdivisions (
id integer NOT NULL,
population integer NOT NULL DEFAULT 0,
boundary geography,
beer_volume bigint NOT NULL DEFAULT 0,
wine_volume bigint NOT NULL DEFAULT 0,
spirits_volume bigint NOT NULL DEFAULT 0,
province text COLLATE pg_catalog."default",
name text COLLATE pg_catalog."default",
average_income integer NOT NULL DEFAULT 0,
median_income integer NOT NULL DEFAULT 0,
median_after_tax_income integer NOT NULL DEFAULT 0,
average_after_tax_income integer NOT NULL DEFAULT 0,
geographic_centre geography,
alcohol_density numeric(9,2),
beer_density numeric(9,2),
wine_density numeric(9,2),
spirits_density numeric(9,2),
CONSTRAINT firstkey PRIMARY KEY (id)
);
ALTER TABLE subdivisions
OWNER TO spurioususer;
CREATE INDEX IF NOT EXISTS idx_boundary
ON subdivisions
USING gist
(boundary);
-- Table: stores
-- DROP TABLE stores;
CREATE TABLE IF NOT EXISTS stores
(
id integer NOT NULL,
name text,
city text,
beer_volume integer,
wine_volume integer,
spirits_volume integer,
location geography,
CONSTRAINT stores_pkey PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE stores
OWNER TO spurioususer;
CREATE INDEX IF NOT EXISTS idx_location
ON stores
USING gist
(location);
CREATE TABLE IF NOT EXISTS products
(
id integer NOT NULL,
name text,
category text,
volume integer,
PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE products
OWNER TO spurioususer;
CREATE TABLE IF NOT EXISTS inventories
(
product_id integer NOT NULL,
store_id integer NOT NULL,
quantity integer,
CONSTRAINT inventories_pkey PRIMARY KEY (product_id, store_id),
CONSTRAINT inventories_product_id_fkey FOREIGN KEY (product_id)
REFERENCES products (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE CASCADE,
CONSTRAINT inventories_store_id_fkey FOREIGN KEY (store_id)
REFERENCES stores (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE CASCADE
)
WITH (
OIDS=FALSE
);
ALTER TABLE inventories
OWNER TO spurioususer;
-- Index: fki_inventories_stores_id_fkey
-- DROP INDEX fki_inventories_stores_id_fkey;
CREATE INDEX IF NOT EXISTS fki_inventories_stores_id_fkey
ON inventories
USING btree
(store_id);
CREATE TABLE public.inventory_pages
(
content text COLLATE pg_catalog."default" NULL,
product_id integer NOT NULL,
compressed_content bytea null,
CONSTRAINT inventory_pages_pkey PRIMARY KEY (product_id)
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public.inventory_pages
OWNER to spurioususer;
-- Performs a bulk insert/update/delete based on http://dba.stackexchange.com/questions/73066/efficient-way-to-insert-update-delete-table-records-from-complex-query-in-postgr
CREATE OR REPLACE procedure update_boundaries_from_incoming()
LANGUAGE 'sql'
AS $BODY$
DELETE FROM subdivisions s -- with EXISTS semi-anti-join
WHERE NOT EXISTS (
SELECT 1 FROM boundary_incoming bi
WHERE bi.id = s.id
);
insert into subdivisions
(id, name, boundary, province)
select id, bi.name, (select ST_Transform(ST_GeomFromGML(bi.boundary_gml, 3347), 4326)), bi.province
from boundary_incoming bi
left join subdivisions s using (id)
where s.id is null;
update subdivisions s
set (boundary, province) = (select ST_Transform(ST_GeomFromGML(bi.boundary_gml, 3347), 4326), bi.province)
from boundary_incoming bi
where s.id = bi.id;
update subdivisions
set geographic_centre = ST_centroid(boundary);
$BODY$;
ALTER procedure public.update_boundaries_from_incoming()
OWNER TO spurioususer;
CREATE OR REPLACE procedure public.update_populations_from_incoming()
LANGUAGE 'sql'
AS $BODY$
DELETE FROM subdivisions s -- with EXISTS semi-anti-join
WHERE NOT EXISTS (
SELECT 1 FROM population_incoming pi
WHERE pi.id = s.id
);
insert into subdivisions
(id, name, population)
select id, pi.name, pi.population
from population_incoming pi
left join subdivisions s using (id)
where s.id is null;
update subdivisions s
set (population)
= (select pi.population)
from population_incoming pi
where s.id = pi.id;
$BODY$;
ALTER procedure public.update_populations_from_incoming()
OWNER TO spurioususer;
CREATE OR REPLACE procedure public.update_stores_from_incoming()
LANGUAGE 'sql'
AS $BODY$
DELETE FROM stores s -- with EXISTS semi-anti-join
WHERE NOT EXISTS (
SELECT 1 FROM store_incoming si
WHERE si.id = s.id
);
insert into stores
(id, name, city, location)
select id, si.name, si.city, (select ST_SetSRID(ST_MakePoint(si.longitude, si.latitude), 4326))
from store_incoming si
left join stores s using (id)
where s.id is null;
update stores s
set (name, city, location)
= (select si.name, si.city, (select ST_SetSRID(ST_MakePoint(si.longitude, si.latitude), 4326)))
from store_incoming si
where s.id = si.id;
$BODY$;
ALTER procedure public.update_stores_from_incoming()
OWNER TO spurioususer;
CREATE OR REPLACE procedure public.update_products_from_incoming()
LANGUAGE 'sql'
AS $BODY$
DELETE FROM products p -- with EXISTS semi-anti-join
WHERE NOT EXISTS (
SELECT 1 FROM product_incoming pi
WHERE pi.id = p.id
);
insert into products
(id, name, category, volume)
select id, pi.name, pi.category, pi.volume
from product_incoming pi
left join products p using (id)
where p.id is null;
update products p
set (name, category, volume)
= (select pi.name, pi.category, pi.volume)
from product_incoming pi
where p.id = pi.id;
$BODY$;
ALTER procedure public.update_products_from_incoming()
OWNER TO spurioususer;
CREATE OR REPLACE procedure public.update_inventories_from_incoming()
LANGUAGE 'sql'
AS $BODY$
DELETE FROM inventories i -- with EXISTS semi-anti-join
WHERE NOT EXISTS (
SELECT 1 FROM inventory_incoming ii
WHERE ii.product_id = i.product_id
AND ii.store_id = i.store_id
);
insert into inventories
(product_id, store_id, quantity)
select ii.product_id, ii.store_id, ii.quantity
from inventory_incoming ii
left join inventories i using (product_id, store_id)
where i.product_id is null and i.store_id is null;
update inventories i
set (quantity)
= (select ii.quantity)
from inventory_incoming ii
where i.product_id = ii.product_id and i.store_id = ii.store_id;
$BODY$;
ALTER procedure public.update_inventories_from_incoming()
OWNER TO spurioususer;
-- FUNCTION: public.update_store_volumes()
-- DROP FUNCTION public.update_store_volumes();
CREATE OR REPLACE procedure public.update_store_volumes()
LANGUAGE 'sql'
AS $BODY$
update stores
set (beer_volume, wine_volume, spirits_volume) =
(
(select sum(i.quantity * p.volume)
from inventories i
inner join products p on p.id = i.product_id
where i.store_id = stores.id
and p.category = 'Beer')
,(select sum(i.quantity * p.volume)
from inventories i
inner join products p on p.id = i.product_id
where i.store_id = stores.id
and p.category = 'Wine')
,(select sum(i.quantity * p.volume)
from inventories i
inner join products p on p.id = i.product_id
where i.store_id = stores.id
and p.category = 'Spirits')
)
$BODY$;
ALTER procedure public.update_store_volumes()
OWNER TO spurioususer;
CREATE OR REPLACE PROCEDURE public.update_subdivision_volumes(
)
LANGUAGE 'sql'
AS $BODY$
update subdivisions sd
set (beer_volume, wine_volume, spirits_volume) =
(
(select coalesce (sum(s.beer_volume), 0)
from stores s
where ST_Intersects(sd.boundary, ST_Transform(s.location::geometry, 4326))),
(select coalesce (sum(s.wine_volume), 0)
from stores s
where ST_Intersects(sd.boundary, ST_Transform(s.location::geometry, 4326))),
(select coalesce (sum(s.spirits_volume), 0)
from stores s
where ST_Intersects(sd.boundary, ST_Transform(s.location::geometry, 4326)))
)
where sd.population > 0;
update subdivisions sd
set (alcohol_density, beer_density, wine_density, spirits_density) =
(
(sd.beer_volume + sd.wine_volume + sd.spirits_volume) * 1.0 / sd.population,
sd.beer_volume * 1.0 / sd.population,
sd.wine_volume * 1.0 / sd.population,
sd.spirits_volume * 1.0 / sd.population
)
where sd.population > 0;
$BODY$;
ALTER procedure public.update_subdivision_volumes()
OWNER TO spurioususer;
CREATE OR REPLACE FUNCTION public.get_densities(
_alcohol_volume text,
_sort_order text,
_limit integer)
RETURNS TABLE(id integer, population integer, name text, centre text, volume numeric, density numeric)
LANGUAGE 'plpgsql'
COST 100
VOLATILE
ROWS 1000
AS $BODY$
BEGIN
IF upper(_sort_order) IN (N'ASC', N'DESC', N'ASCENDING', N'DESCENDING') THEN
-- proceed
ELSE
RAISE EXCEPTION 'Unexpected value for parameter _sort_order.
Allowed: ASC, DESC, ASCENDING, DESCENDING.';
END IF;
RETURN QUERY EXECUTE format(
'SELECT "id",
"population",
"name",
St_AsGeoJSON("geographic_centre") AS centre,
%I AS "volume",
%I AS "density"
FROM "subdivisions"
WHERE %I > 0
ORDER BY "density" %s
LIMIT %s'
,_alcohol_volume, _alcohol_volume, _alcohol_volume, _sort_order, _limit);
END
$BODY$;
ALTER FUNCTION public.get_densities(text, text, integer)
OWNER TO spurioususer;