sql-blocks 0.0.5__tar.gz → 0.0.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sql_blocks-0.0.5/sql_blocks.egg-info → sql_blocks-0.0.7}/PKG-INFO +34 -1
- {sql_blocks-0.0.5 → sql_blocks-0.0.7}/README.md +33 -0
- {sql_blocks-0.0.5 → sql_blocks-0.0.7}/pyproject.toml +1 -1
- {sql_blocks-0.0.5 → sql_blocks-0.0.7}/setup.py +1 -1
- {sql_blocks-0.0.5 → sql_blocks-0.0.7}/sql_blocks/sql_blocks.py +122 -50
- {sql_blocks-0.0.5 → sql_blocks-0.0.7/sql_blocks.egg-info}/PKG-INFO +34 -1
- {sql_blocks-0.0.5 → sql_blocks-0.0.7}/sql_blocks.egg-info/SOURCES.txt +1 -2
- sql_blocks-0.0.5/tests/tests.py +0 -99
- {sql_blocks-0.0.5 → sql_blocks-0.0.7}/LICENSE +0 -0
- {sql_blocks-0.0.5 → sql_blocks-0.0.7}/setup.cfg +0 -0
- {sql_blocks-0.0.5 → sql_blocks-0.0.7}/sql_blocks/__init__.py +0 -0
- {sql_blocks-0.0.5 → sql_blocks-0.0.7}/sql_blocks.egg-info/dependency_links.txt +0 -0
- {sql_blocks-0.0.5 → sql_blocks-0.0.7}/sql_blocks.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sql_blocks
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.7
|
4
4
|
Summary: Allows you to create objects for parts of SQL query commands. Also to combine these objects by joining them, adding or removing parts...
|
5
5
|
Home-page: https://github.com/julio-cascalles/sql_blocks
|
6
6
|
Author: Júlio Cascalles
|
@@ -313,3 +313,36 @@ m2 = Select(
|
|
313
313
|
'normal'
|
314
314
|
)
|
315
315
|
)
|
316
|
+
|
317
|
+
---
|
318
|
+
|
319
|
+
### 11 - optimize method
|
320
|
+
p1 = Select.parse("""
|
321
|
+
SELECT * FROM Product p
|
322
|
+
WHERE (p.category = 'Gizmo'
|
323
|
+
OR p.category = 'Gadget'
|
324
|
+
OR p.category = 'Doohickey')
|
325
|
+
AND NOT price <= 387.64
|
326
|
+
AND YEAR(last_sale) = 2024
|
327
|
+
ORDER BY
|
328
|
+
category
|
329
|
+
""")[0]
|
330
|
+
p1.optimize() # <<===============
|
331
|
+
p2 = Select.parse("""
|
332
|
+
SELECT category FROM Product p
|
333
|
+
WHERE category IN ('Gizmo','Gadget','Doohickey')
|
334
|
+
and p.price > 387.64
|
335
|
+
and p.last_sale >= '2024-01-01'
|
336
|
+
and p.last_sale <= '2024-12-31'
|
337
|
+
ORDER BY p.category LIMIT 100
|
338
|
+
""")[0]
|
339
|
+
p1 == p2 # --- True!
|
340
|
+
|
341
|
+
This will...
|
342
|
+
* Replace `OR` conditions to `SELECT IN ...`
|
343
|
+
* Put `LIMIT` if no fields or conditions defined;
|
344
|
+
* Normalizes inverted conditions;
|
345
|
+
* Auto includes fields present in `ORDER/GROUP BY`;
|
346
|
+
* Replace `YEAR` function with date range comparison.
|
347
|
+
|
348
|
+
> The method allows you to select which rules you want to apply in the optimization...Or define your own rules!
|
@@ -298,3 +298,36 @@ m2 = Select(
|
|
298
298
|
'normal'
|
299
299
|
)
|
300
300
|
)
|
301
|
+
|
302
|
+
---
|
303
|
+
|
304
|
+
### 11 - optimize method
|
305
|
+
p1 = Select.parse("""
|
306
|
+
SELECT * FROM Product p
|
307
|
+
WHERE (p.category = 'Gizmo'
|
308
|
+
OR p.category = 'Gadget'
|
309
|
+
OR p.category = 'Doohickey')
|
310
|
+
AND NOT price <= 387.64
|
311
|
+
AND YEAR(last_sale) = 2024
|
312
|
+
ORDER BY
|
313
|
+
category
|
314
|
+
""")[0]
|
315
|
+
p1.optimize() # <<===============
|
316
|
+
p2 = Select.parse("""
|
317
|
+
SELECT category FROM Product p
|
318
|
+
WHERE category IN ('Gizmo','Gadget','Doohickey')
|
319
|
+
and p.price > 387.64
|
320
|
+
and p.last_sale >= '2024-01-01'
|
321
|
+
and p.last_sale <= '2024-12-31'
|
322
|
+
ORDER BY p.category LIMIT 100
|
323
|
+
""")[0]
|
324
|
+
p1 == p2 # --- True!
|
325
|
+
|
326
|
+
This will...
|
327
|
+
* Replace `OR` conditions to `SELECT IN ...`
|
328
|
+
* Put `LIMIT` if no fields or conditions defined;
|
329
|
+
* Normalizes inverted conditions;
|
330
|
+
* Auto includes fields present in `ORDER/GROUP BY`;
|
331
|
+
* Replace `YEAR` function with date range comparison.
|
332
|
+
|
333
|
+
> The method allows you to select which rules you want to apply in the optimization...Or define your own rules!
|
@@ -10,26 +10,32 @@ DISTINCT_SF_PR = f'(DISTINCT|distinct)|{SUFFIX_AND_PRE}'
|
|
10
10
|
KEYWORD = {
|
11
11
|
'SELECT': (',{}', 'SELECT *', DISTINCT_SF_PR),
|
12
12
|
'FROM': ('{}', '', PATTERN_SUFFIX),
|
13
|
-
'WHERE': ('{}AND ', '', PATTERN_PREFIX),
|
13
|
+
'WHERE': ('{}AND ', '', f'{PATTERN_PREFIX}| '),
|
14
14
|
'GROUP BY': (',{}', '', SUFFIX_AND_PRE),
|
15
15
|
'ORDER BY': (',{}', '', SUFFIX_AND_PRE),
|
16
16
|
'LIMIT': (' ', '', ''),
|
17
17
|
}
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
18
|
+
# ^ ^ ^
|
19
|
+
# | | |
|
20
|
+
# | | +----- pattern to compare fields
|
21
|
+
# | |
|
22
|
+
# | +----- default when empty (SELECT * ...)
|
23
|
+
# |
|
24
|
+
# +-------- separator
|
25
25
|
|
26
26
|
SELECT, FROM, WHERE, GROUP_BY, ORDER_BY, LIMIT = KEYWORD.keys()
|
27
|
-
USUAL_KEYS = [SELECT, WHERE, GROUP_BY, ORDER_BY]
|
27
|
+
USUAL_KEYS = [SELECT, WHERE, GROUP_BY, ORDER_BY, LIMIT]
|
28
28
|
|
29
29
|
|
30
30
|
class SQLObject:
|
31
|
+
ALIAS_FUNC = lambda t: t.lower()[:3]
|
32
|
+
""" ^^^^^^^^^^^^^^^^^^^^^^^^
|
33
|
+
You can change the behavior by assigning
|
34
|
+
a user function to SQLObject.ALIAS_FUNC
|
35
|
+
"""
|
36
|
+
|
31
37
|
def __init__(self, table_name: str=''):
|
32
|
-
self.
|
38
|
+
self.__alias = ''
|
33
39
|
self.values = {}
|
34
40
|
self.key_field = ''
|
35
41
|
self.set_table(table_name)
|
@@ -37,20 +43,26 @@ class SQLObject:
|
|
37
43
|
def set_table(self, table_name: str):
|
38
44
|
if not table_name:
|
39
45
|
return
|
40
|
-
if ' ' in table_name:
|
41
|
-
table_name, self.
|
46
|
+
if ' ' in table_name.strip():
|
47
|
+
table_name, self.__alias = table_name.split()
|
42
48
|
elif '_' in table_name:
|
43
|
-
self.
|
49
|
+
self.__alias = ''.join(
|
44
50
|
word[0].lower()
|
45
51
|
for word in table_name.split('_')
|
46
52
|
)
|
47
53
|
else:
|
48
|
-
self.
|
54
|
+
self.__alias = SQLObject.ALIAS_FUNC(table_name)
|
49
55
|
self.values.setdefault(FROM, []).append(f'{table_name} {self.alias}')
|
50
56
|
|
51
57
|
@property
|
52
58
|
def table_name(self) -> str:
|
53
59
|
return self.values[FROM][0].split()[0]
|
60
|
+
|
61
|
+
@property
|
62
|
+
def alias(self) -> str:
|
63
|
+
if self.__alias:
|
64
|
+
return self.__alias
|
65
|
+
return self.table_name
|
54
66
|
|
55
67
|
@staticmethod
|
56
68
|
def get_separator(key: str) -> str:
|
@@ -90,9 +102,9 @@ class Field:
|
|
90
102
|
@classmethod
|
91
103
|
def format(cls, name: str, main: SQLObject) -> str:
|
92
104
|
name = name.strip()
|
93
|
-
if name
|
105
|
+
if name in ('_', '*'):
|
94
106
|
name = '*'
|
95
|
-
elif '.'
|
107
|
+
elif not re.findall('[.()0-9]', name):
|
96
108
|
name = f'{main.alias}.{name}'
|
97
109
|
if Function in cls.__bases__:
|
98
110
|
name = f'{cls.__name__}({name})'
|
@@ -185,7 +197,7 @@ class Where:
|
|
185
197
|
prefix = ''
|
186
198
|
|
187
199
|
def __init__(self, expr: str):
|
188
|
-
self.expr =
|
200
|
+
self.expr = expr
|
189
201
|
|
190
202
|
@classmethod
|
191
203
|
def __constructor(cls, operator: str, value):
|
@@ -226,8 +238,8 @@ class Where:
|
|
226
238
|
return cls(f'IN ({values})')
|
227
239
|
|
228
240
|
def add(self, name: str, main: SQLObject):
|
229
|
-
main.values.setdefault(WHERE, []).append('{} {}'.format(
|
230
|
-
Field.format(name, main), self.expr
|
241
|
+
main.values.setdefault(WHERE, []).append('{}{} {}'.format(
|
242
|
+
self.prefix, Field.format(name, main), self.expr
|
231
243
|
))
|
232
244
|
|
233
245
|
|
@@ -347,6 +359,12 @@ class Having:
|
|
347
359
|
return cls(Count, condition)
|
348
360
|
|
349
361
|
|
362
|
+
class Rule:
|
363
|
+
@classmethod
|
364
|
+
def apply(cls, target: 'Select'):
|
365
|
+
...
|
366
|
+
|
367
|
+
|
350
368
|
class JoinType(Enum):
|
351
369
|
INNER = ''
|
352
370
|
LEFT = 'LEFT '
|
@@ -424,13 +442,16 @@ class Select(SQLObject):
|
|
424
442
|
return False
|
425
443
|
return True
|
426
444
|
|
427
|
-
def limit(self, row_count: int, offset: int=0):
|
445
|
+
def limit(self, row_count: int=100, offset: int=0):
|
428
446
|
result = [str(row_count)]
|
429
447
|
if offset > 0:
|
430
448
|
result.append(f'OFFSET {offset}')
|
431
449
|
self.values.setdefault(LIMIT, result)
|
432
450
|
return self
|
433
451
|
|
452
|
+
def match(self, expr: str) -> bool:
|
453
|
+
return re.findall(f'\b*{self.alias}[.]', expr) != []
|
454
|
+
|
434
455
|
@classmethod
|
435
456
|
def parse(cls, txt: str) -> list[SQLObject]:
|
436
457
|
def find_last_word(pos: int) -> int:
|
@@ -452,7 +473,7 @@ class Select(SQLObject):
|
|
452
473
|
if not cls.REGEX:
|
453
474
|
keywords = '|'.join(k + r'\b' for k in KEYWORD)
|
454
475
|
flags = re.IGNORECASE + re.MULTILINE
|
455
|
-
cls.REGEX['keywords'] = re.compile(f'({keywords})', flags)
|
476
|
+
cls.REGEX['keywords'] = re.compile(f'({keywords}|[*])', flags)
|
456
477
|
cls.REGEX['subquery'] = re.compile(r'(\w\.)*\w+ +in +\(SELECT.*?\)', flags)
|
457
478
|
result = {}
|
458
479
|
found = cls.REGEX['subquery'].search(txt)
|
@@ -476,7 +497,7 @@ class Select(SQLObject):
|
|
476
497
|
result[obj.alias] = obj
|
477
498
|
txt = txt[:start-1] + txt[end+1:]
|
478
499
|
found = cls.REGEX['subquery'].search(txt)
|
479
|
-
tokens = [t.strip() for t in cls.REGEX['keywords'].split(txt) if
|
500
|
+
tokens = [t.strip() for t in cls.REGEX['keywords'].split(txt) if t.strip()]
|
480
501
|
values = {k.upper(): v for k, v in zip(tokens[::2], tokens[1::2])}
|
481
502
|
tables = [t.strip() for t in re.split('JOIN|LEFT|RIGHT|ON', values[FROM]) if t.strip()]
|
482
503
|
for item in tables:
|
@@ -495,11 +516,18 @@ class Select(SQLObject):
|
|
495
516
|
obj.values[key] = [
|
496
517
|
Field.format(fld, obj)
|
497
518
|
for fld in re.split(separator, values[key])
|
498
|
-
if len(tables) == 1 or
|
519
|
+
if (fld != '*' and len(tables) == 1) or obj.match(fld)
|
499
520
|
]
|
500
521
|
result[obj.alias] = obj
|
501
522
|
return list( result.values() )
|
502
523
|
|
524
|
+
def optimize(self, rules: list[Rule]=None):
|
525
|
+
if not rules:
|
526
|
+
rules = Rule.__subclasses__()
|
527
|
+
for rule in rules:
|
528
|
+
rule.apply(self)
|
529
|
+
|
530
|
+
|
503
531
|
class SelectIN(Select):
|
504
532
|
condition_class = Where
|
505
533
|
|
@@ -513,30 +541,74 @@ class NotSelectIN(SelectIN):
|
|
513
541
|
condition_class = Not
|
514
542
|
|
515
543
|
|
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
|
-
|
544
|
+
class RulePutLimit(Rule):
|
545
|
+
@classmethod
|
546
|
+
def apply(cls, target: Select):
|
547
|
+
need_limit = any(not target.values.get(key) for key in (WHERE, SELECT))
|
548
|
+
if need_limit:
|
549
|
+
target.limit()
|
550
|
+
|
551
|
+
class RuleSelectIN(Rule):
|
552
|
+
@classmethod
|
553
|
+
def apply(cls, target: Select):
|
554
|
+
for i, condition in enumerate(target.values[WHERE]):
|
555
|
+
tokens = re.split(' or | OR ', re.sub('\n|\t|[()]', ' ', condition))
|
556
|
+
if len(tokens) < 2:
|
557
|
+
continue
|
558
|
+
fields = [t.split('=')[0].split('.')[-1].lower().strip() for t in tokens]
|
559
|
+
if len(set(fields)) == 1:
|
560
|
+
target.values[WHERE][i] = '{} IN ({})'.format(
|
561
|
+
Field.format(fields[0], target),
|
562
|
+
','.join(t.split('=')[-1].strip() for t in tokens)
|
563
|
+
)
|
564
|
+
|
565
|
+
class RuleAutoField(Rule):
|
566
|
+
@classmethod
|
567
|
+
def apply(cls, target: Select):
|
568
|
+
if target.values.get(GROUP_BY):
|
569
|
+
target.values[SELECT] = target.values[GROUP_BY]
|
570
|
+
target.values[ORDER_BY] = []
|
571
|
+
elif target.values.get(ORDER_BY):
|
572
|
+
s1 = set(target.values.get(SELECT, []))
|
573
|
+
s2 = set(target.values[ORDER_BY])
|
574
|
+
target.values.setdefault(SELECT, []).extend( list(s2-s1) )
|
575
|
+
|
576
|
+
class RuleLogicalOp(Rule):
|
577
|
+
REVERSE = {
|
578
|
+
">=": "<",
|
579
|
+
"<=": ">",
|
580
|
+
"<>": "=",
|
581
|
+
"=": "<>"
|
582
|
+
}
|
583
|
+
@classmethod
|
584
|
+
def apply(cls, target: Select):
|
585
|
+
REGEX = re.compile('({})'.format(
|
586
|
+
'|'.join(cls.REVERSE)
|
587
|
+
))
|
588
|
+
for i, condition in enumerate(target.values.get(WHERE, [])):
|
589
|
+
expr = re.sub('\n|\t', ' ', condition)
|
590
|
+
tokens = [t for t in re.split(r'(NOT\b|not\b)',expr) if t.strip()]
|
591
|
+
if len(tokens) < 2 or not REGEX.findall(tokens[-1]):
|
592
|
+
continue
|
593
|
+
tokens = REGEX.split(tokens[-1])
|
594
|
+
tokens[1] = cls.REVERSE[tokens[1]]
|
595
|
+
target.values[WHERE][i] = ' '.join(tokens)
|
596
|
+
|
597
|
+
class RuleDateFuncReplace(Rule):
|
598
|
+
"""
|
599
|
+
SQL algorithm by Ralff Matias
|
600
|
+
"""
|
601
|
+
REGEX = re.compile(r'(\bYEAR[(]|\byear[(]|=|[)])')
|
602
|
+
|
603
|
+
@classmethod
|
604
|
+
def apply(cls, target: Select):
|
605
|
+
for i, condition in enumerate(target.values.get(WHERE, [])):
|
606
|
+
tokens = [
|
607
|
+
t.strip() for t in cls.REGEX.split(condition) if t.strip()
|
608
|
+
]
|
609
|
+
if len(tokens) < 3:
|
610
|
+
continue
|
611
|
+
func, field, *rest, year = tokens
|
612
|
+
temp = Select(f'{target.table_name} {target.alias}')
|
613
|
+
Between(f'{year}-01-01', f'{year}-12-31').add(field, temp)
|
614
|
+
target.values[WHERE][i] = ' AND '.join(temp.values[WHERE])
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sql_blocks
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.7
|
4
4
|
Summary: Allows you to create objects for parts of SQL query commands. Also to combine these objects by joining them, adding or removing parts...
|
5
5
|
Home-page: https://github.com/julio-cascalles/sql_blocks
|
6
6
|
Author: Júlio Cascalles
|
@@ -313,3 +313,36 @@ m2 = Select(
|
|
313
313
|
'normal'
|
314
314
|
)
|
315
315
|
)
|
316
|
+
|
317
|
+
---
|
318
|
+
|
319
|
+
### 11 - optimize method
|
320
|
+
p1 = Select.parse("""
|
321
|
+
SELECT * FROM Product p
|
322
|
+
WHERE (p.category = 'Gizmo'
|
323
|
+
OR p.category = 'Gadget'
|
324
|
+
OR p.category = 'Doohickey')
|
325
|
+
AND NOT price <= 387.64
|
326
|
+
AND YEAR(last_sale) = 2024
|
327
|
+
ORDER BY
|
328
|
+
category
|
329
|
+
""")[0]
|
330
|
+
p1.optimize() # <<===============
|
331
|
+
p2 = Select.parse("""
|
332
|
+
SELECT category FROM Product p
|
333
|
+
WHERE category IN ('Gizmo','Gadget','Doohickey')
|
334
|
+
and p.price > 387.64
|
335
|
+
and p.last_sale >= '2024-01-01'
|
336
|
+
and p.last_sale <= '2024-12-31'
|
337
|
+
ORDER BY p.category LIMIT 100
|
338
|
+
""")[0]
|
339
|
+
p1 == p2 # --- True!
|
340
|
+
|
341
|
+
This will...
|
342
|
+
* Replace `OR` conditions to `SELECT IN ...`
|
343
|
+
* Put `LIMIT` if no fields or conditions defined;
|
344
|
+
* Normalizes inverted conditions;
|
345
|
+
* Auto includes fields present in `ORDER/GROUP BY`;
|
346
|
+
* Replace `YEAR` function with date range comparison.
|
347
|
+
|
348
|
+
> The method allows you to select which rules you want to apply in the optimization...Or define your own rules!
|
sql_blocks-0.0.5/tests/tests.py
DELETED
@@ -1,99 +0,0 @@
|
|
1
|
-
from sql_blocks.sql_blocks import *
|
2
|
-
|
3
|
-
|
4
|
-
Select.join_type = JoinType.LEFT
|
5
|
-
OrderBy.sort = SortType.DESC
|
6
|
-
|
7
|
-
def best_movies() -> SubSelect:
|
8
|
-
return SubSelect(
|
9
|
-
'Review r', movie=[GroupBy, Distinct], rate=Having.avg(Where.gt(4.5))
|
10
|
-
)
|
11
|
-
|
12
|
-
def detached_objects() -> tuple:
|
13
|
-
def select_actor() -> Select:
|
14
|
-
return Select('Actor a', cast=ForeignKey('Cast'),
|
15
|
-
name=NamedField('actors_name'), age=Between(45, 69)
|
16
|
-
)
|
17
|
-
def select_cast() -> Select:
|
18
|
-
return Select(
|
19
|
-
Cast=Table('role'), id=PrimaryKey, movie=ForeignKey('Movie'),
|
20
|
-
)
|
21
|
-
def select_movie() -> Select:
|
22
|
-
return Select('Movie m', title=Field,
|
23
|
-
release_date=[OrderBy, Field], id=PrimaryKey,
|
24
|
-
OR=Options(
|
25
|
-
genre=Where.eq('Sci-Fi'), awards=Where.like('Oscar')
|
26
|
-
), director=[Where.like('Coppola'), Field, OrderBy]
|
27
|
-
)
|
28
|
-
return select_actor(), select_cast(), select_movie()
|
29
|
-
|
30
|
-
def query_reference() -> Select:
|
31
|
-
return Select('Actor a', age=Between(45, 69),
|
32
|
-
cast=Select(
|
33
|
-
Cast=Table('role'), id=PrimaryKey,
|
34
|
-
movie=Select(
|
35
|
-
'Movie m', title=Field,
|
36
|
-
release_date=[OrderBy, Field],
|
37
|
-
id=[
|
38
|
-
SubSelect(
|
39
|
-
'Review r', movie=[GroupBy, Distinct],
|
40
|
-
rate=Having.avg(Where.gt(4.5))
|
41
|
-
),
|
42
|
-
PrimaryKey
|
43
|
-
], OR=Options(
|
44
|
-
genre=Where.eq('Sci-Fi'), awards=Where.like('Oscar')
|
45
|
-
)
|
46
|
-
) # --- Movie
|
47
|
-
), # ------- Cast
|
48
|
-
name=NamedField('actors_name'),
|
49
|
-
) # ----------- Actor
|
50
|
-
|
51
|
-
def single_text_to_objects():
|
52
|
-
return Select.parse('''
|
53
|
-
SELECT
|
54
|
-
cas.role,
|
55
|
-
m.title,
|
56
|
-
m.release_date,
|
57
|
-
a.name as actors_name
|
58
|
-
FROM
|
59
|
-
Actor a
|
60
|
-
LEFT JOIN Cast cas ON (a.cast = cas.id)
|
61
|
-
LEFT JOIN Movie m ON (cas.movie = m.id)
|
62
|
-
WHERE
|
63
|
-
( m.genre = 'Sci-Fi' OR m.awards LIKE '%Oscar%' )
|
64
|
-
AND a.age <= 69 AND a.age >= 45
|
65
|
-
ORDER BY
|
66
|
-
m.release_date DESC
|
67
|
-
''')
|
68
|
-
|
69
|
-
def many_texts_to_objects():
|
70
|
-
ForeignKey.references = {
|
71
|
-
('Actor', 'Cast'): ('cast', 'id'),
|
72
|
-
('Cast', 'Movie'): ('movie', 'id'),
|
73
|
-
}
|
74
|
-
actor = Select.parse('''
|
75
|
-
SELECT name as actors_name FROM Actor a
|
76
|
-
WHERE a.age >= 45 AND a.age <= 69
|
77
|
-
''')[0]
|
78
|
-
cast = Select.parse('SELECT role FROM Cast')[0]
|
79
|
-
movie = Select.parse("""
|
80
|
-
SELECT title, release_date FROM Movie m ORDER BY release_date DESC
|
81
|
-
WHERE ( m.genre = 'Sci-Fi' OR m.awards LIKE '%Oscar%' ) GROUP BY director
|
82
|
-
""")[0]
|
83
|
-
return actor, cast, movie
|
84
|
-
|
85
|
-
def two_queries_same_table() -> Select:
|
86
|
-
txt1 = """SELECT p.name, p.category
|
87
|
-
,p.price,p.promotional FROM product p
|
88
|
-
where p.category in (6,14,29,35,78)
|
89
|
-
AND p.Status = p.last_st ORDER BY p.EAN"""
|
90
|
-
txt2 = """select stock_amount, EAN,Name ,expiration_date
|
91
|
-
from PRODUCT where price < 357.46 and status = Last_ST order by ean"""
|
92
|
-
return Select.parse(txt1)[0] + Select.parse(txt2)[0]
|
93
|
-
|
94
|
-
def select_product() -> Select:
|
95
|
-
return Select(
|
96
|
-
Product=Table('name,promotional,stock_amount,expiration_date'),
|
97
|
-
category=[Where.list([6,14,29,35,78]),Field], EAN=[Field, OrderBy],
|
98
|
-
price=[Where.lt(357.46),Field], status=Where('= Last_st')
|
99
|
-
)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|