alf 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/Gemfile +6 -3
  2. data/Gemfile.lock +65 -19
  3. data/README.md +77 -183
  4. data/Rakefile +25 -0
  5. data/alf.gemspec +5 -3
  6. data/alf.noespec +8 -6
  7. data/lib/alf/loader.rb +1 -0
  8. data/lib/alf/version.rb +1 -1
  9. data/spec/facade/test_query.rb +12 -0
  10. data/spec/key-inference/queries.yml +10 -0
  11. data/spec/key-inference/test_all.rb +21 -0
  12. data/{test → spec}/migrations/test_folder_migration.rb +0 -0
  13. data/{test → spec}/migrations/test_sequel_migration.rb +1 -1
  14. data/spec/operators/ungroup/grouped.json +3 -0
  15. data/spec/operators/ungroup/test_on_json_content.rb +11 -0
  16. data/spec/operators/unwrap/test_on_json_content.rb +11 -0
  17. data/spec/operators/unwrap/wrapped.json +3 -0
  18. data/spec/optimizer/project/extend.yml +20 -0
  19. data/spec/optimizer/project/intersect.yml +10 -0
  20. data/spec/optimizer/project/join.yml +20 -0
  21. data/spec/optimizer/project/matching.yml +21 -0
  22. data/spec/optimizer/project/minus.yml +9 -0
  23. data/spec/optimizer/project/not_matching.yml +21 -0
  24. data/spec/optimizer/project/project.yml +88 -0
  25. data/spec/optimizer/project/rename.yml +30 -0
  26. data/spec/optimizer/project/sort.yml +45 -0
  27. data/spec/optimizer/project/union.yml +8 -0
  28. data/spec/optimizer/restrict/clip.yml +4 -0
  29. data/spec/optimizer/restrict/compact.yml +4 -0
  30. data/spec/optimizer/restrict/generator.yml +4 -0
  31. data/spec/optimizer/restrict/intersect.yml +4 -0
  32. data/spec/optimizer/restrict/leaf_operand.yml +4 -0
  33. data/spec/optimizer/restrict/minus.yml +4 -0
  34. data/spec/optimizer/restrict/page.yml +12 -0
  35. data/spec/optimizer/restrict/project.yml +4 -0
  36. data/spec/optimizer/restrict/sort.yml +4 -0
  37. data/spec/optimizer/restrict/union.yml +4 -0
  38. data/spec/optimizer/test_all.rb +34 -0
  39. data/spec/sql/helpers.rb +25 -0
  40. data/spec/sql/queries/01-leaf-operand.yml +5 -0
  41. data/spec/sql/queries/02-clip.yml +12 -0
  42. data/spec/sql/queries/03-sort.yml +58 -0
  43. data/spec/sql/queries/04-frame.yml +57 -0
  44. data/spec/sql/queries/05-intersect.yml +23 -0
  45. data/spec/sql/queries/06-join.yml +207 -0
  46. data/spec/sql/queries/07-matching.yml +76 -0
  47. data/spec/sql/queries/08-minus.yml +23 -0
  48. data/spec/sql/queries/09-not-matching.yml +57 -0
  49. data/spec/sql/queries/10-page.yml +31 -0
  50. data/spec/sql/queries/11-project.yml +48 -0
  51. data/spec/sql/queries/12-rename.yml +24 -0
  52. data/spec/sql/queries/13-restrict.yml +114 -0
  53. data/spec/sql/queries/15-union.yml +90 -0
  54. data/spec/sql/queries/16-wrap.yml +3 -0
  55. data/spec/sql/queries/91-reuse.yml +28 -0
  56. data/spec/sql/test_sequel_compiler.rb +41 -0
  57. data/spec/sql/test_sql_compiler.rb +52 -0
  58. data/{test → spec}/test_alf.rb +0 -0
  59. data/spec/test_helpers.rb +54 -0
  60. data/tasks/doc.rake +10 -0
  61. data/tasks/fixtures.rake +52 -0
  62. data/tasks/mod.rake +50 -0
  63. data/tasks/release.rake +34 -0
  64. data/tasks/test.rake +2 -2
  65. metadata +150 -19
  66. data/test/seeding/test_seeding.rb +0 -49
  67. data/test/test_helpers.rb +0 -24
@@ -0,0 +1,76 @@
1
+ # matching with no attribute
2
+ - alf: |-
3
+ matching(suppliers, project(supplies, [:qty]))
4
+ sql:
5
+ SELECT t1.sid, t1.name, t1.status, t1.city
6
+ FROM suppliers AS t1
7
+ WHERE EXISTS(SELECT * FROM supplies AS t2)
8
+ # matching on one single attribute
9
+ - alf: |-
10
+ matching(suppliers, supplies)
11
+ sql:
12
+ SELECT t1.sid, t1.name, t1.status, t1.city
13
+ FROM suppliers AS t1
14
+ WHERE t1.sid IN (SELECT t2.sid FROM supplies AS t2)
15
+ # matching on multiple attributes
16
+ - alf: |-
17
+ matching(suppliers, parts)
18
+ sql:
19
+ SELECT t1.sid, t1.name, t1.status, t1.city
20
+ FROM suppliers AS t1
21
+ WHERE EXISTS(
22
+ SELECT t2.name, t2.city
23
+ FROM parts AS t2
24
+ WHERE t1.name = t2.name
25
+ AND t1.city = t2.city)
26
+ # matching when a with_exp at right
27
+ - alf: |-
28
+ matching(suppliers, sort(sort(suppliers, [:sid, :asc]), [:sid, :desc]))
29
+ sql:
30
+ WITH t3 AS (
31
+ SELECT t2.sid, t2.name, t2.status, t2.city
32
+ FROM suppliers AS t2
33
+ ORDER BY t2.sid ASC
34
+ )
35
+ SELECT t1.sid, t1.name, t1.status, t1.city
36
+ FROM suppliers AS t1
37
+ WHERE EXISTS(
38
+ SELECT t3.sid, t3.name, t3.status, t3.city
39
+ FROM t3 AS t3
40
+ WHERE t1.sid = t3.sid
41
+ AND t1.name = t3.name
42
+ AND t1.status = t3.status
43
+ AND t1.city = t3.city
44
+ ORDER BY t3.sid DESC)
45
+ # matching with a union at left
46
+ - alf: |-
47
+ matching(union(suppliers_in_london, suppliers_in_paris), supplies)
48
+ sql: |-
49
+ WITH t4 AS (
50
+ (SELECT t1.sid, t1.name, t1.status, t1.city
51
+ FROM suppliers AS t1
52
+ WHERE t1.city = 'London')
53
+ UNION
54
+ (SELECT t2.sid, t2.name, t2.status, t2.city
55
+ FROM suppliers AS t2
56
+ WHERE t2.city = 'Paris')
57
+ )
58
+ SELECT t4.sid, t4.name, t4.status, t4.city
59
+ FROM t4 AS t4
60
+ WHERE t4.sid IN (SELECT t3.sid FROM supplies AS t3)
61
+ # matching with a union at right
62
+ - alf: |-
63
+ matching(supplies, union(suppliers_in_london, suppliers_in_paris))
64
+ sql: |-
65
+ WITH t4 AS (
66
+ (SELECT t2.sid, t2.name, t2.status, t2.city
67
+ FROM suppliers AS t2
68
+ WHERE t2.city = 'London')
69
+ UNION
70
+ (SELECT t3.sid, t3.name, t3.status, t3.city
71
+ FROM suppliers AS t3
72
+ WHERE t3.city = 'Paris')
73
+ )
74
+ SELECT t1.sid, t1.pid, t1.qty
75
+ FROM supplies AS t1
76
+ WHERE t1.sid IN (SELECT t4.sid FROM t4 AS t4)
@@ -0,0 +1,23 @@
1
+ - alf: |-
2
+ minus(suppliers_in_london, suppliers_in_paris)
3
+ sql:
4
+ (SELECT t1.sid, t1.name, t1.status, t1.city
5
+ FROM suppliers AS t1
6
+ WHERE t1.city = 'London')
7
+ EXCEPT
8
+ (SELECT t2.sid, t2.name, t2.status, t2.city
9
+ FROM suppliers AS t2
10
+ WHERE t2.city = 'Paris')
11
+ - alf: |-
12
+ minus(minus(suppliers_in_london, suppliers_in_paris), suppliers)
13
+ sql:
14
+ ((SELECT t1.sid, t1.name, t1.status, t1.city
15
+ FROM suppliers AS t1
16
+ WHERE t1.city = 'London')
17
+ EXCEPT
18
+ (SELECT t2.sid, t2.name, t2.status, t2.city
19
+ FROM suppliers AS t2
20
+ WHERE t2.city = 'Paris'))
21
+ EXCEPT
22
+ (SELECT t3.sid, t3.name, t3.status, t3.city
23
+ FROM suppliers AS t3)
@@ -0,0 +1,57 @@
1
+ # not_matching with no attribute
2
+ - alf: |-
3
+ not_matching(suppliers, project(supplies, [:qty]))
4
+ sql:
5
+ SELECT t1.sid, t1.name, t1.status, t1.city
6
+ FROM suppliers AS t1
7
+ WHERE NOT(EXISTS(SELECT * FROM supplies AS t2))
8
+ # not matching on one single attribute
9
+ - alf: |-
10
+ not_matching(suppliers, supplies)
11
+ sql:
12
+ SELECT t1.sid, t1.name, t1.status, t1.city
13
+ FROM suppliers AS t1
14
+ WHERE NOT(t1.sid IN (SELECT t2.sid FROM supplies AS t2))
15
+ # not_matching on multiple attributes
16
+ - alf: |-
17
+ not_matching(suppliers, parts)
18
+ sql:
19
+ SELECT t1.sid, t1.name, t1.status, t1.city
20
+ FROM suppliers AS t1
21
+ WHERE NOT(EXISTS(
22
+ SELECT t2.name, t2.city
23
+ FROM parts AS t2
24
+ WHERE t1.name = t2.name
25
+ AND t1.city = t2.city))
26
+ # not_matching with a union at left
27
+ - alf: |-
28
+ not_matching(union(suppliers_in_london, suppliers_in_paris), supplies)
29
+ sql: |-
30
+ WITH t4 AS (
31
+ (SELECT t1.sid, t1.name, t1.status, t1.city
32
+ FROM suppliers AS t1
33
+ WHERE t1.city = 'London')
34
+ UNION
35
+ (SELECT t2.sid, t2.name, t2.status, t2.city
36
+ FROM suppliers AS t2
37
+ WHERE t2.city = 'Paris')
38
+ )
39
+ SELECT t4.sid, t4.name, t4.status, t4.city
40
+ FROM t4 AS t4
41
+ WHERE NOT(t4.sid IN (SELECT t3.sid FROM supplies AS t3))
42
+ # not_matching with a union at right
43
+ - alf: |-
44
+ not_matching(supplies, union(suppliers_in_london, suppliers_in_paris))
45
+ sql: |-
46
+ WITH t4 AS (
47
+ (SELECT t2.sid, t2.name, t2.status, t2.city
48
+ FROM suppliers AS t2
49
+ WHERE t2.city = 'London')
50
+ UNION
51
+ (SELECT t3.sid, t3.name, t3.status, t3.city
52
+ FROM suppliers AS t3
53
+ WHERE t3.city = 'Paris')
54
+ )
55
+ SELECT t1.sid, t1.pid, t1.qty
56
+ FROM supplies AS t1
57
+ WHERE NOT(t1.sid IN (SELECT t4.sid FROM t4 AS t4))
@@ -0,0 +1,31 @@
1
+ - alf: |-
2
+ page(suppliers, [[:city, :desc], [:sid, :asc]], 1, page_size: 10)
3
+ sql: |-
4
+ SELECT t1.sid, t1.name, t1.status, t1.city
5
+ FROM suppliers AS t1
6
+ ORDER BY t1.city DESC, t1.sid ASC
7
+ LIMIT 10 OFFSET 0
8
+ #
9
+ - alf: |-
10
+ page(suppliers, [[:city, :desc], [:sid, :asc]], -1, page_size: 10)
11
+ sql: |-
12
+ SELECT t1.sid, t1.name, t1.status, t1.city
13
+ FROM suppliers AS t1
14
+ ORDER BY t1.city ASC, t1.sid DESC
15
+ LIMIT 10 OFFSET 0
16
+ #
17
+ - alf: |-
18
+ page(suppliers, [[:city, :desc], [:sid, :asc]], 2, page_size: 10)
19
+ sql: |-
20
+ SELECT t1.sid, t1.name, t1.status, t1.city
21
+ FROM suppliers AS t1
22
+ ORDER BY t1.city DESC, t1.sid ASC
23
+ LIMIT 10 OFFSET 10
24
+ #
25
+ - alf: |-
26
+ page(suppliers, [[:city, :desc]], 2, page_size: 10)
27
+ sql: |-
28
+ SELECT t1.sid, t1.name, t1.status, t1.city
29
+ FROM suppliers AS t1
30
+ ORDER BY t1.city DESC, t1.sid ASC
31
+ LIMIT 10 OFFSET 10
@@ -0,0 +1,48 @@
1
+ # normal case
2
+ - alf: |-
3
+ project(suppliers, [:sid])
4
+ sql: |-
5
+ SELECT t1.sid
6
+ FROM suppliers AS t1
7
+ # allbut case
8
+ - alf: |-
9
+ project(suppliers, [:sid], allbut: true)
10
+ sql: |-
11
+ SELECT t1.name, t1.status, t1.city
12
+ FROM suppliers AS t1
13
+ # unique, non primary key
14
+ - alf: |-
15
+ project(suppliers, [:name])
16
+ sql: |-
17
+ SELECT t1.name
18
+ FROM suppliers AS t1
19
+ # requiring distinct
20
+ - alf: |-
21
+ project(suppliers, [:status])
22
+ sql: |-
23
+ SELECT DISTINCT t1.status
24
+ FROM suppliers AS t1
25
+ # a special case where attributes are taken in another order
26
+ - alf: |-
27
+ project(suppliers, [:status, :city, :name])
28
+ sql: |-
29
+ SELECT t1.name, t1.status, t1.city
30
+ FROM suppliers AS t1
31
+ comment: |-
32
+ The projection applies to the heading, that keeps its own order. The
33
+ ordering of fields therefore differs from what could be expected. It's
34
+ not a semantics issue, though.
35
+ # empty projection
36
+ - alf: |-
37
+ project(suppliers, [])
38
+ sql: |-
39
+ SELECT TRUE AS is_table_dee
40
+ WHERE EXISTS(SELECT * FROM suppliers AS t1)
41
+ # empty projection or empty projection
42
+ - alf: |-
43
+ project(project(suppliers, []), [])
44
+ sql: |-
45
+ SELECT TRUE AS is_table_dee
46
+ WHERE EXISTS(
47
+ SELECT TRUE AS is_table_dee
48
+ WHERE EXISTS(SELECT * FROM suppliers AS t1))
@@ -0,0 +1,24 @@
1
+ - alf: |-
2
+ rename(suppliers, :sid => :id)
3
+ sql: |-
4
+ SELECT t1.sid AS id, t1.name, t1.status, t1.city
5
+ FROM suppliers AS t1
6
+ #
7
+ - alf: |-
8
+ project(rename(suppliers, :sid => :id), [:id, :name])
9
+ sql: |-
10
+ SELECT t1.sid AS id, t1.name
11
+ FROM suppliers AS t1
12
+ #
13
+ - alf: |-
14
+ sort(rename(suppliers, :sid => :id), [[:id, :asc], [:city, :desc]])
15
+ sql: |-
16
+ SELECT t1.sid AS id, t1.name, t1.status, t1.city
17
+ FROM suppliers AS t1
18
+ ORDER BY t1.sid ASC, t1.city DESC
19
+ #
20
+ - alf: |-
21
+ rename(cities, country: :name)
22
+ sql: |-
23
+ SELECT t1.city, t1.country AS name
24
+ FROM cities AS t1
@@ -0,0 +1,114 @@
1
+ # base case
2
+ - alf: |-
3
+ restrict(suppliers, sid: 'S1')
4
+ sql: |-
5
+ SELECT t1.sid, t1.name, t1.status, t1.city
6
+ FROM suppliers AS t1
7
+ WHERE t1.sid = 'S1'
8
+ # when renamed: desalisation required
9
+ - alf: |-
10
+ restrict(rename(suppliers, sid: :id), id: 'S1')
11
+ sql: |-
12
+ SELECT t1.sid AS id, t1.name, t1.status, t1.city
13
+ FROM suppliers AS t1
14
+ WHERE t1.sid = 'S1'
15
+ # TRUE
16
+ - alf: |-
17
+ restrict(suppliers, true)
18
+ sql: |-
19
+ SELECT t1.sid, t1.name, t1.status, t1.city
20
+ FROM suppliers AS t1
21
+ WHERE TRUE
22
+ # FALSE
23
+ - alf: |-
24
+ restrict(suppliers, false)
25
+ sql: |-
26
+ SELECT t1.sid, t1.name, t1.status, t1.city
27
+ FROM suppliers AS t1
28
+ WHERE FALSE
29
+ # AND
30
+ - alf: |-
31
+ restrict(suppliers, sid: 'S1', city: 'London')
32
+ sql: |-
33
+ SELECT t1.sid, t1.name, t1.status, t1.city
34
+ FROM suppliers AS t1
35
+ WHERE t1.sid = 'S1' AND t1.city = 'London'
36
+ # OR
37
+ - alf: |-
38
+ restrict(suppliers, Alf::Predicate.or(eq(:sid, 'S1'), eq(:sid, 'S2')))
39
+ sql: |-
40
+ SELECT t1.sid, t1.name, t1.status, t1.city
41
+ FROM suppliers AS t1
42
+ WHERE t1.sid = 'S1' OR t1.sid = 'S2'
43
+ # NOT =
44
+ - alf: |-
45
+ restrict(suppliers, !eq(:sid, 'S1'))
46
+ sql: |-
47
+ SELECT t1.sid, t1.name, t1.status, t1.city
48
+ FROM suppliers AS t1
49
+ WHERE t1.sid <> 'S1'
50
+ # NOT AND
51
+ - alf: |-
52
+ restrict(suppliers, !(eq(:sid, 'S1') & eq(:status, 20)))
53
+ sql: |-
54
+ SELECT t1.sid, t1.name, t1.status, t1.city
55
+ FROM suppliers AS t1
56
+ WHERE NOT(t1.sid = 'S1' AND t1.status = 20)
57
+ # NOT EQUAL
58
+ - alf: |-
59
+ restrict(suppliers, neq(:sid, 'S1'))
60
+ sql: |-
61
+ SELECT t1.sid, t1.name, t1.status, t1.city
62
+ FROM suppliers AS t1
63
+ WHERE t1.sid <> 'S1'
64
+ # GREATER
65
+ - alf: |-
66
+ restrict(suppliers, gt(:status, 10))
67
+ sql: |-
68
+ SELECT t1.sid, t1.name, t1.status, t1.city
69
+ FROM suppliers AS t1
70
+ WHERE t1.status > 10
71
+ # GREATER OR EQUAL
72
+ - alf: |-
73
+ restrict(suppliers, gte(:status, 10))
74
+ sql: |-
75
+ SELECT t1.sid, t1.name, t1.status, t1.city
76
+ FROM suppliers AS t1
77
+ WHERE t1.status >= 10
78
+ # LESS THAN
79
+ - alf: |-
80
+ restrict(suppliers, lt(:status, 10))
81
+ sql: |-
82
+ SELECT t1.sid, t1.name, t1.status, t1.city
83
+ FROM suppliers AS t1
84
+ WHERE t1.status < 10
85
+ # LESS THAN OR EQUAL
86
+ - alf: |-
87
+ restrict(suppliers, lte(:status, 10))
88
+ sql: |-
89
+ SELECT t1.sid, t1.name, t1.status, t1.city
90
+ FROM suppliers AS t1
91
+ WHERE t1.status <= 10
92
+ # IN
93
+ - alf: |-
94
+ restrict(suppliers, Alf::Predicate.in(:sid, ['S1', 'S2']))
95
+ sql: |-
96
+ SELECT t1.sid, t1.name, t1.status, t1.city
97
+ FROM suppliers AS t1
98
+ WHERE t1.sid IN ('S1', 'S2')
99
+ # restrict(restrict)
100
+ - alf: |-
101
+ restrict(restrict(suppliers, sid: 'S1'), status: 20)
102
+ sql:
103
+ SELECT t1.sid, t1.name, t1.status, t1.city
104
+ FROM suppliers AS t1
105
+ WHERE t1.sid = 'S1' AND t1.status = 20
106
+ # restrict(join)
107
+ - alf: |-
108
+ restrict(join(suppliers, supplies), sid: 'S2', qty: 300)
109
+ sql:
110
+ SELECT t1.sid, t1.name, t1.status, t1.city, t2.pid, t2.qty
111
+ FROM suppliers AS t1
112
+ JOIN supplies AS t2 ON t1.sid = t2.sid
113
+ WHERE t1.sid = 'S2'
114
+ AND t2.qty = 300
@@ -0,0 +1,90 @@
1
+ # A base union case
2
+ - alf: |-
3
+ union(suppliers_in_london, suppliers_in_paris)
4
+ sql:
5
+ (SELECT t1.sid, t1.name, t1.status, t1.city
6
+ FROM suppliers AS t1
7
+ WHERE t1.city = 'London')
8
+ UNION
9
+ (SELECT t2.sid, t2.name, t2.status, t2.city
10
+ FROM suppliers AS t2
11
+ WHERE t2.city = 'Paris')
12
+ # union requiring a reordering
13
+ - alf: |-
14
+ union(project(suppliers, [:name, :city]), rename(cities, country: :name))
15
+ sql: |-
16
+ (SELECT t1.name, t1.city
17
+ FROM suppliers AS t1)
18
+ UNION
19
+ (SELECT t2.country AS name, t2.city
20
+ FROM cities AS t2)
21
+ # union of union
22
+ - alf: |-
23
+ union(union(suppliers_in_london, suppliers_in_paris), suppliers)
24
+ sql:
25
+ ((SELECT t1.sid, t1.name, t1.status, t1.city
26
+ FROM suppliers AS t1
27
+ WHERE t1.city = 'London')
28
+ UNION
29
+ (SELECT t2.sid, t2.name, t2.status, t2.city
30
+ FROM suppliers AS t2
31
+ WHERE t2.city = 'Paris'))
32
+ UNION
33
+ (SELECT t3.sid, t3.name, t3.status, t3.city
34
+ FROM suppliers AS t3)
35
+ # union with a with_exp at left
36
+ - alf: |-
37
+ union(sort(sort(suppliers_in_london, [:sid, :asc]), [:sid, :desc]), suppliers_in_paris)
38
+ sql:
39
+ WITH t2 AS (
40
+ SELECT t1.sid, t1.name, t1.status, t1.city
41
+ FROM suppliers AS t1
42
+ WHERE t1.city = 'London'
43
+ ORDER BY t1.sid ASC
44
+ )
45
+ (SELECT t2.sid, t2.name, t2.status, t2.city
46
+ FROM t2 AS t2
47
+ ORDER BY t2.sid DESC)
48
+ UNION
49
+ (SELECT t3.sid, t3.name, t3.status, t3.city
50
+ FROM suppliers AS t3
51
+ WHERE t3.city = 'Paris')
52
+ # union with a with_exp at right
53
+ - alf: |-
54
+ union(suppliers_in_london, sort(sort(suppliers_in_paris, [:sid, :asc]), [:sid, :desc]))
55
+ sql:
56
+ WITH t3 AS (
57
+ SELECT t2.sid, t2.name, t2.status, t2.city
58
+ FROM suppliers AS t2
59
+ WHERE t2.city = 'Paris'
60
+ ORDER BY t2.sid ASC
61
+ )
62
+ (SELECT t1.sid, t1.name, t1.status, t1.city
63
+ FROM suppliers AS t1
64
+ WHERE t1.city = 'London')
65
+ UNION
66
+ (SELECT t3.sid, t3.name, t3.status, t3.city
67
+ FROM t3 AS t3
68
+ ORDER BY t3.sid DESC)
69
+ # union of two with_exps
70
+ - alf: |-
71
+ union(sort(sort(suppliers_in_london, [:sid, :asc]), [:sid, :desc]),
72
+ sort(sort(suppliers_in_paris, [:sid, :asc]), [:sid, :desc]))
73
+ sql:
74
+ WITH t2 AS (
75
+ SELECT t1.sid, t1.name, t1.status, t1.city
76
+ FROM suppliers AS t1
77
+ WHERE t1.city = 'London'
78
+ ORDER BY t1.sid ASC),
79
+ t4 AS (
80
+ SELECT t3.sid, t3.name, t3.status, t3.city
81
+ FROM suppliers AS t3
82
+ WHERE t3.city = 'Paris'
83
+ ORDER BY t3.sid ASC)
84
+ (SELECT t2.sid, t2.name, t2.status, t2.city
85
+ FROM t2 AS t2
86
+ ORDER BY t2.sid DESC)
87
+ UNION
88
+ (SELECT t4.sid, t4.name, t4.status, t4.city
89
+ FROM t4 AS t4
90
+ ORDER BY t4.sid DESC)