-
-
Notifications
You must be signed in to change notification settings - Fork 625
Expand file tree
/
Copy pathschema.sql
More file actions
790 lines (715 loc) · 30.3 KB
/
schema.sql
File metadata and controls
790 lines (715 loc) · 30.3 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
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
create table if not exists migrations
(
id serial,
migration varchar(255) not null,
batch integer not null,
primary key (id)
);
create table if not exists personal_access_tokens
(
id bigserial,
tokenable_type varchar(255) not null,
tokenable_id bigint not null,
name varchar(255) not null,
token varchar(64) not null,
abilities text,
last_used_at timestamp(0),
expires_at timestamp(0),
created_at timestamp(0),
updated_at timestamp(0),
primary key (id),
constraint personal_access_tokens_token_unique
unique (token)
);
create index if not exists personal_access_tokens_tokenable_type_tokenable_id_index
on personal_access_tokens (tokenable_type, tokenable_id);
create table if not exists password_reset_tokens
(
email varchar(255) not null,
token varchar(255) not null,
created_at timestamp,
deleted_at timestamp,
updated_at timestamp,
id bigint generated always as identity
);
create index if not exists password_reset_tokens_email_index
on password_reset_tokens (email);
create index if not exists password_reset_tokens_token_index
on password_reset_tokens (token);
create table if not exists failed_jobs
(
id bigint generated always as identity,
uuid varchar(255) not null,
connection text not null,
queue text not null,
payload text not null,
exception text not null,
failed_at timestamp(0) default CURRENT_TIMESTAMP not null,
primary key (id),
constraint failed_jobs_uuid_unique
unique (uuid)
);
create table if not exists accounts
(
id bigint generated always as identity,
currency_code varchar(3) default 'USD'::character varying not null,
timezone varchar(255),
created_at timestamp,
updated_at timestamp,
deleted_at timestamp,
name varchar not null,
email varchar not null,
stripe_account_id varchar(50),
short_id varchar(20) not null,
stripe_connect_setup_complete boolean default false,
account_verified_at timestamp,
primary key (id)
);
create table if not exists password_resets
(
email varchar(200),
token varchar(200),
created_at timestamp,
updated_at timestamp,
deleted_at timestamp,
id bigint generated always as identity,
ip_address varchar not null,
user_agent varchar
);
create table if not exists timezones
(
id bigint generated always as identity,
name varchar(64) not null,
deleted_at timestamp,
primary key (id)
);
create table if not exists roles
(
id bigint generated always as identity,
name varchar,
permissions jsonb not null,
account_id bigint,
constraint roles_pk
primary key (id),
constraint roles_accounts_id_fk
foreign key (account_id) references accounts
);
create table if not exists users
(
id bigint generated always as identity,
email varchar(255) not null,
email_verified_at timestamp(0),
password varchar(255) not null,
remember_token varchar(100),
created_at timestamp(0),
updated_at timestamp(0),
deleted_at timestamp,
first_name varchar not null,
last_name varchar,
pending_email varchar,
timezone varchar not null,
primary key (id)
);
create table if not exists event_logs
(
id bigint generated always as identity,
user_id bigint not null,
type varchar(255) not null,
entity_id bigint not null,
entity_type bigint not null,
ip_address varchar,
user_agent varchar,
data jsonb,
created_at timestamp not null,
updated_at timestamp,
deleted_at timestamp,
primary key (id),
constraint event_logs_users_id_fk
foreign key (user_id) references users
);
create table if not exists taxes_and_fees
(
id bigint generated always as identity,
name varchar(255) not null,
calculation_type varchar(20) not null,
rate numeric(10, 3) not null,
is_active boolean default true,
description text,
created_at timestamp,
deleted_at timestamp,
updated_at timestamp,
account_id bigint not null,
is_default boolean default false not null,
type varchar(20) not null,
constraint tax_and_fee_types_pkey
primary key (id),
constraint calculation_method_check
check ((calculation_type)::text = ANY
(ARRAY [('FIXED'::character varying)::text, ('PERCENTAGE'::character varying)::text])),
constraint type_check
check ((type)::text = ANY (ARRAY [('TAX'::character varying)::text, ('FEE'::character varying)::text]))
);
comment on column taxes_and_fees.is_default is 'Whether to apply to all new tickets automatically';
create index if not exists tax_and_fees_account_id_index
on taxes_and_fees (account_id);
create table if not exists images
(
id bigserial,
entity_id bigint,
entity_type varchar(120),
type varchar(40),
filename varchar(255),
disk varchar(20),
path text,
size integer,
mime_type varchar(50),
created_at timestamp default CURRENT_TIMESTAMP,
updated_at timestamp default CURRENT_TIMESTAMP,
deleted_at timestamp,
primary key (id)
);
create index if not exists idx_images_entity_id
on images (entity_id);
create index if not exists idx_images_type
on images (type);
create index if not exists idx_images_entity_type
on images (entity_type);
create table if not exists organizers
(
id bigint generated always as identity,
account_id integer not null,
name varchar(255) not null,
email varchar(255) not null,
phone varchar(20),
website varchar(255),
description text,
created_at timestamp not null,
updated_at timestamp not null,
deleted_at timestamp,
currency varchar(3) default 'USD'::character varying not null,
timezone varchar(255) not null,
primary key (id),
foreign key (account_id) references accounts
);
create table if not exists events
(
id bigint generated always as identity,
title varchar(255) not null,
account_id integer not null,
user_id integer not null,
start_date timestamp,
end_date timestamp,
description text,
status varchar,
location_details jsonb,
currency varchar(3) default 'USD'::character varying not null,
timezone varchar,
attributes jsonb,
created_at timestamp not null,
updated_at timestamp not null,
deleted_at timestamp,
location varchar(255),
organizer_id bigint,
short_id varchar(32) not null,
ticket_quantity_available integer,
primary key (id),
constraint fk_events_account_id
foreign key (account_id) references accounts
on update cascade on delete cascade,
constraint fk_events_user_id
foreign key (user_id) references users
on delete cascade,
constraint events_organizers_id_fk
foreign key (organizer_id) references organizers
);
create index if not exists events_account_id_index
on events (account_id);
create index if not exists events_user_id_index
on events (user_id);
create index if not exists events_organizer_id_index
on events (organizer_id);
create table if not exists tickets
(
id bigint generated always as identity,
title varchar(255) not null,
event_id integer not null,
sale_start_date timestamp,
sale_end_date timestamp,
max_per_order integer,
description text,
min_per_order integer,
sales_volume numeric(14, 2) default 0.00 not null,
sales_tax_volume numeric(14, 2) default 0.00 not null,
hide_before_sale_start_date boolean default false not null,
hide_after_sale_end_date boolean default false not null,
hide_when_sold_out boolean default false not null,
show_quantity_remaining boolean default false not null,
is_hidden_without_promo_code boolean default false not null,
"order" integer not null,
created_at timestamp not null,
updated_at timestamp,
deleted_at timestamp,
type varchar(20) default 'PAID'::character varying not null,
is_hidden boolean default false,
primary key (id),
constraint fk_tickets_event_id
foreign key (event_id) references events
on delete cascade
);
create table if not exists promo_codes
(
id bigint generated always as identity,
code varchar(50) not null,
discount numeric(14, 2) default 0.00 not null,
applicable_ticket_ids jsonb,
expiry_date timestamp with time zone,
event_id bigint not null,
discount_type varchar,
attendee_usage_count integer default 0 not null,
order_usage_count integer default 0 not null,
max_allowed_usages integer,
created_at timestamp not null,
updated_at timestamp,
deleted_at timestamp,
primary key (id),
constraint promo_codes_events_id_fk
foreign key (event_id) references events
);
create index if not exists promo_codes_code_index
on promo_codes (code);
create index if not exists promo_codes_event_id_index
on promo_codes (event_id);
create index if not exists promo_codes_applicable_ticket_ids_index
on promo_codes (applicable_ticket_ids);
create table if not exists orders
(
id bigint generated always as identity,
short_id varchar(20) not null,
event_id integer not null,
total_before_additions numeric(14, 2) default 0.00 not null,
total_refunded numeric(14, 2) default 0.00 not null,
total_gross numeric(14, 2) default 0.00 not null,
currency varchar(3) not null,
first_name varchar(50),
last_name varchar(50),
email varchar(255),
status varchar not null,
payment_status varchar,
refund_status varchar,
reserved_until timestamp(0),
is_manually_created boolean default false not null,
session_id varchar(40),
public_id varchar not null,
point_in_time_data jsonb,
payment_gateway varchar,
promo_code_id integer,
promo_code varchar,
address jsonb,
created_at timestamp not null,
updated_at timestamp,
deleted_at timestamp,
taxes_and_fees_rollup jsonb,
total_tax numeric(14, 2) default 0.00 not null,
total_fee numeric(14, 2) default 0.00 not null,
primary key (id),
constraint orders_pk
unique (public_id),
constraint fk_orders_event_id
foreign key (event_id) references events,
constraint orders_promo_codes_id_fk
foreign key (promo_code_id) references promo_codes
);
create index if not exists orders_promo_code_id_index
on orders (promo_code_id);
create index if not exists idx_orders_first_name_trgm
on orders using gin (first_name gin_trgm_ops);
create index if not exists idx_orders_last_name_trgm
on orders using gin (last_name gin_trgm_ops);
create index if not exists idx_orders_email_trgm
on orders using gin (email gin_trgm_ops);
create index if not exists idx_orders_public_id_trgm
on orders using gin (public_id gin_trgm_ops);
create table if not exists questions
(
id bigint generated always as identity,
event_id bigint not null,
title text not null,
required boolean default false not null,
type varchar,
options jsonb,
belongs_to varchar not null,
created_at timestamp not null,
updated_at timestamp not null,
deleted_at timestamp,
"order" integer default 1 not null,
is_hidden boolean default false not null,
primary key (id),
constraint questions_event_id_fk
foreign key (event_id) references events
);
create table if not exists stripe_payments
(
id bigint generated always as identity,
order_id bigint not null,
payment_intent_id varchar not null,
charge_id varchar,
payment_method_id varchar,
amount_received bigint,
created_at timestamp,
updated_at timestamp,
deleted_at timestamp,
last_error json,
connected_account_id varchar(50),
primary key (id),
constraint stripe_payments_orders_id_fk
foreign key (order_id) references orders
);
create table if not exists messages
(
id bigint generated always as identity,
event_id bigint not null,
subject varchar(255) not null,
message text not null,
type varchar(40) not null,
recipient_ids jsonb,
sent_at timestamp,
sent_by_user_id bigint not null,
attendee_ids jsonb,
ticket_ids jsonb,
order_id bigint,
status varchar(20) not null,
send_data jsonb,
created_at timestamp not null,
updated_at timestamp,
deleted_at timestamp,
primary key (id),
constraint messages_events_id_fk
foreign key (event_id) references events,
constraint messages_users_id_fk
foreign key (sent_by_user_id) references users
);
create table if not exists affiliates
(
id bigint generated always as identity,
code varchar not null,
event_id bigint,
sales_volume numeric(14, 2),
unique_visitors integer default 0 not null,
created_at timestamp not null,
updated_at timestamp,
deleted_at timestamp,
primary key (id),
constraint affiliates_events_id_fk
foreign key (event_id) references events
);
create unique index if not exists affiliates_code_uindex
on affiliates (code);
create index if not exists affiliates_event_id_index
on affiliates (event_id);
create table if not exists event_statistics
(
id bigint generated always as identity,
event_id bigint not null,
unique_views bigint default 0 not null,
total_views bigint default 0 not null,
sales_total_gross numeric(14, 2) default 0.00 not null,
total_tax numeric(14, 2) default 0.00 not null,
sales_total_before_additions numeric(14, 2) default 0.00 not null,
created_at timestamp not null,
deleted_at timestamp,
updated_at timestamp,
total_fee numeric(14, 2) default 0.00 not null,
tickets_sold integer default 0 not null,
version integer default 0 not null,
orders_created integer default 0 not null,
total_refunded numeric(14, 2) default 0 not null,
primary key (id),
constraint event_statistics_events_id_fk
foreign key (event_id) references events
);
create index if not exists event_statistics_event_id_index
on event_statistics (event_id);
create table if not exists event_daily_statistics
(
id bigint generated always as identity,
sales_total_gross numeric(14, 2) default 0.00 not null,
total_tax numeric(14, 2) default 0.00 not null,
sales_total_before_additions numeric(14, 2) default 0.00 not null,
tickets_sold integer default 0 not null,
orders_created integer default 0 not null,
date date not null,
created_at timestamp not null,
deleted_at timestamp,
updated_at timestamp,
total_fee numeric(14, 2) default 0 not null,
event_id bigint not null,
version integer default 0 not null,
total_refunded numeric(14, 2) default 0 not null,
total_views bigint default 0 not null,
primary key (id),
constraint event_daily_statistics_events_id_fk
foreign key (event_id) references events
);
create index if not exists event_daily_statistics_event_id_index
on event_daily_statistics (event_id);
create table if not exists ticket_taxes_and_fees
(
id integer generated always as identity,
ticket_id bigint not null,
tax_and_fee_id bigint not null,
constraint ticket_tax_and_fees_pk
primary key (id),
constraint ticket_tax_and_fees_tickets_id_fk
foreign key (ticket_id) references tickets
on delete cascade,
constraint ticket_tax_and_fees_tax_and_fees_id_fk
foreign key (tax_and_fee_id) references taxes_and_fees
on delete cascade
);
create index if not exists ticket_tax_and_fees_tax_and_fee_id_index
on ticket_taxes_and_fees (tax_and_fee_id);
create index if not exists ticket_tax_and_fees_ticket_id_index
on ticket_taxes_and_fees (ticket_id);
create table if not exists ticket_prices
(
id bigint generated always as identity,
ticket_id bigint not null,
price numeric(14, 2) not null,
label varchar(255),
sale_start_date timestamp,
sale_end_date timestamp,
created_at timestamp not null,
updated_at timestamp,
deleted_at timestamp,
initial_quantity_available integer,
quantity_sold integer default 0 not null,
is_hidden boolean default false,
"order" integer default 1 not null,
constraint pk_ticket_prices
primary key (id),
constraint fk_ticket_prices_ticket_id
foreign key (ticket_id) references tickets
on delete cascade,
constraint valid_price_range
check (price >= (0)::numeric)
);
create index if not exists idx_ticket_prices_ticket_id
on ticket_prices (ticket_id);
create index if not exists idx_ticket_prices_dates
on ticket_prices (sale_start_date, sale_end_date);
create table if not exists order_items
(
id bigint generated always as identity,
total_before_additions numeric(14, 2) not null,
quantity integer not null,
order_id integer not null,
ticket_id integer not null,
item_name varchar,
price numeric(14, 2) not null,
price_before_discount numeric(14, 2),
deleted_at timestamp,
total_tax numeric(14, 2) default 0.00 not null,
total_gross numeric(14, 2),
total_service_fee numeric(14, 2) default 0.00,
taxes_and_fees_rollup jsonb,
ticket_price_id integer not null,
primary key (id),
constraint fk_order_items_order_id
foreign key (order_id) references orders
on delete cascade,
constraint fk_order_items_ticket_id
foreign key (ticket_id) references tickets,
constraint order_items_ticket_prices_id_fk
foreign key (ticket_price_id) references ticket_prices
);
create index if not exists order_items_order_id_index
on order_items (order_id);
create index if not exists order_items_ticket_id_index
on order_items (ticket_id);
create index if not exists order_items_ticket_price_id_index
on order_items (ticket_price_id);
create table if not exists attendees
(
id bigint generated always as identity,
short_id varchar not null,
first_name varchar(255) default ''::character varying not null,
last_name varchar(255) default ''::character varying not null,
email varchar(255) not null,
order_id integer not null,
ticket_id integer not null,
event_id integer not null,
public_id varchar not null,
status varchar(20) not null,
checked_in_by bigint,
checked_in_at timestamp,
created_at timestamp not null,
updated_at timestamp not null,
deleted_at timestamp,
checked_out_by bigint,
ticket_price_id bigint not null,
primary key (id),
constraint fk_attendees_order_id
foreign key (order_id) references orders
on delete cascade,
constraint fk_attendees_ticket_id
foreign key (ticket_id) references tickets
on delete cascade,
constraint attendees_events_id_fk
foreign key (event_id) references events
on delete cascade,
constraint fk_attendees_checked_in_by_id
foreign key (checked_in_by) references users
on delete cascade,
constraint attendees_users_id_fk
foreign key (checked_out_by) references users,
constraint attendees_ticket_prices_id_fk
foreign key (ticket_price_id) references ticket_prices
);
create index if not exists idx_attendees_first_name_trgm
on attendees using gin (first_name gin_trgm_ops);
create index if not exists idx_attendees_last_name_trgm
on attendees using gin (last_name gin_trgm_ops);
create index if not exists idx_attendees_email_trgm
on attendees using gin (email gin_trgm_ops);
create index if not exists idx_attendees_public_id_trgm
on attendees using gin (public_id gin_trgm_ops);
create index if not exists idx_attendees_public_id_lower
on attendees (lower(public_id::text));
create table if not exists question_answers
(
id bigint generated always as identity,
question_id integer not null,
order_id integer not null,
attendee_id integer,
ticket_id integer,
created_at timestamp not null,
updated_at timestamp not null,
deleted_at timestamp,
answer jsonb,
primary key (id),
constraint fk_question_answers_question_id
foreign key (question_id) references questions,
constraint fk_orders_order_id
foreign key (order_id) references orders,
constraint fk_attendeed_attendee_id
foreign key (attendee_id) references attendees,
constraint fk_tickets_ticket_id
foreign key (ticket_id) references tickets
);
create index if not exists question_answers_attendee_id_index
on question_answers (attendee_id);
create index if not exists question_answers_order_id_index
on question_answers (order_id);
create index if not exists question_answers_question_id_index
on question_answers (question_id);
create table if not exists ticket_questions
(
id serial,
ticket_id integer not null,
question_id integer not null,
deleted_at timestamp,
primary key (id),
constraint fk_ticket_questions_ticket_id
foreign key (ticket_id) references tickets
on delete cascade,
constraint fk_ticket_questions_question_id
foreign key (question_id) references questions
on delete cascade
);
create unique index if not exists idx_ticket_questions_active
on ticket_questions (ticket_id, question_id)
where (deleted_at IS NULL);
create table if not exists event_settings
(
id bigint generated always as identity,
pre_checkout_message text,
post_checkout_message text,
ticket_page_message text,
continue_button_text varchar(100),
email_footer_message text,
support_email varchar(255),
event_id bigint not null,
created_at timestamp not null,
updated_at timestamp not null,
deleted_at timestamp,
require_attendee_details boolean default true not null,
order_timeout_in_minutes integer default 15 not null,
website_url varchar(400),
maps_url varchar(400),
homepage_background_color varchar(20),
homepage_primary_text_color varchar(20),
homepage_primary_color varchar(20),
homepage_secondary_text_color varchar(20),
homepage_secondary_color varchar(20),
location_details jsonb,
online_event_connection_details text,
is_online_event boolean default false not null,
allow_search_engine_indexing boolean default true not null,
seo_title varchar(255),
seo_description varchar(255),
social_media_handles jsonb,
show_social_media_handles boolean,
seo_keywords varchar(255),
notify_organizer_of_new_orders boolean default true not null,
price_display_mode varchar(255) default 'INCLUSIVE'::character varying not null,
hide_getting_started_page boolean default false not null,
show_share_buttons boolean default true not null,
constraint event_settings_pk
primary key (id),
constraint event_settings_events_id_fk
foreign key (event_id) references events
on delete cascade,
constraint event_settings_price_display_mode_check
check ((price_display_mode)::text = ANY
(ARRAY [('INCLUSIVE'::character varying)::text, ('EXCLUSIVE'::character varying)::text]))
);
create index if not exists event_settings_event_id_index
on event_settings (event_id);
create table if not exists account_users
(
id bigint generated always as identity,
account_id bigint not null,
user_id bigint not null,
role varchar(100),
created_at timestamp default now(),
deleted_at timestamp,
updated_at timestamp,
is_account_owner boolean default false not null,
invited_by_user_id bigint,
last_login_at timestamp,
status varchar(40) default 'INVITED'::character varying not null,
primary key (id),
unique (account_id, user_id, role),
constraint fk_account_users_accounts
foreign key (account_id) references accounts
on delete cascade,
constraint fk_account_users_users
foreign key (user_id) references users
on delete cascade,
constraint account_users_users_id_fk
foreign key (invited_by_user_id) references users
);
create index if not exists idx_account_users_account_id
on account_users (account_id);
create index if not exists idx_account_users_user_id
on account_users (user_id);
create index if not exists idx_account_users_role
on account_users (role);
create view question_and_answer_views
(question_id, event_id, belongs_to, question_type, first_name, last_name, attendee_id, order_id, title,
answer)
as
SELECT q.id AS question_id,
q.event_id,
q.belongs_to,
q.type AS question_type,
a.first_name,
a.last_name,
a.id AS attendee_id,
qa.order_id,
q.title,
qa.answer
FROM question_answers qa
LEFT JOIN attendees a ON a.id = qa.attendee_id
JOIN orders o ON qa.order_id = o.id
JOIN questions q ON q.id = qa.question_id;