sql-blocks 1.20250715__tar.gz → 1.20250719__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-1.20250715/sql_blocks.egg-info → sql_blocks-1.20250719}/PKG-INFO +24 -13
- {sql_blocks-1.20250715 → sql_blocks-1.20250719}/README.md +23 -12
- {sql_blocks-1.20250715 → sql_blocks-1.20250719}/pyproject.toml +1 -1
- {sql_blocks-1.20250715 → sql_blocks-1.20250719}/setup.py +1 -1
- {sql_blocks-1.20250715 → sql_blocks-1.20250719}/sql_blocks/sql_blocks.py +82 -71
- {sql_blocks-1.20250715 → sql_blocks-1.20250719/sql_blocks.egg-info}/PKG-INFO +24 -13
- {sql_blocks-1.20250715 → sql_blocks-1.20250719}/LICENSE +0 -0
- {sql_blocks-1.20250715 → sql_blocks-1.20250719}/setup.cfg +0 -0
- {sql_blocks-1.20250715 → sql_blocks-1.20250719}/sql_blocks/__init__.py +0 -0
- {sql_blocks-1.20250715 → sql_blocks-1.20250719}/sql_blocks.egg-info/SOURCES.txt +0 -0
- {sql_blocks-1.20250715 → sql_blocks-1.20250719}/sql_blocks.egg-info/dependency_links.txt +0 -0
- {sql_blocks-1.20250715 → sql_blocks-1.20250719}/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: 1.
|
3
|
+
Version: 1.20250719
|
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
|
@@ -573,16 +573,20 @@ ORDER BY
|
|
573
573
|
mov.title
|
574
574
|
```
|
575
575
|
---
|
576
|
-
|
576
|
+
|
577
|
+
#### Separators and meaning:
|
578
|
+
<a id="cypher_separators"></a>
|
579
|
+
|
577
580
|
* `( )` Delimits a table and its fields
|
578
581
|
* `,` Separate fields
|
579
582
|
* `?` For simple conditions (> < = <>)
|
580
583
|
* `<-` connects to the table on the left
|
581
584
|
* `->` connects to the table on the right
|
582
585
|
* `^` Put the field in the ORDER BY clause
|
583
|
-
* `@` Immediately after the table name, it indicates the grouping field.
|
586
|
+
* `@` Immediately after the table/field name, it indicates the grouping field.
|
584
587
|
* `$` For SQL functions like **avg**$_field_, **sum**$_field_, **count**$_field_...
|
585
588
|
* `*` Sets the primary key field.
|
589
|
+
* `:` Allows you to assign an alias to the field or expression.
|
586
590
|
|
587
591
|
|
588
592
|
---
|
@@ -869,6 +873,7 @@ UNION ALL
|
|
869
873
|
```
|
870
874
|
|
871
875
|
* **17.2.1 - The `create` method** ... parameters :
|
876
|
+
<a id="cte_create_method"></a>
|
872
877
|
- name: The name of the CTE
|
873
878
|
- pattern: A cypher script that defines the tables used
|
874
879
|
- formula: The format for `Where.formula` method _(*)_
|
@@ -881,6 +886,7 @@ UNION ALL
|
|
881
886
|
'[2] = R.[1]', 'JFK', format='.csv'
|
882
887
|
) # ^^^--- Flyghts from JFK airport
|
883
888
|
```
|
889
|
+
|
884
890
|
_...Creates a recursive CTE called Route, using Flyght table, where the recursivity condition is Flyght.arrival equals to Route.departure_
|
885
891
|
>> (*) -- Note that [1] and [2] refers to first field and second field. 😉
|
886
892
|
|
@@ -995,31 +1001,36 @@ results...
|
|
995
1001
|
|
996
1002
|
#### 17.3.1 - You can also pass a Cypher script like in the example below:
|
997
1003
|
|
998
|
-
cte = CTEFactory(
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
+
cte = CTEFactory("""
|
1005
|
+
Annual_Sales_per_Vendor[
|
1006
|
+
Sales(
|
1007
|
+
year$ref_date:ref_year@, sum$quantity:qty_sold,
|
1008
|
+
vendor) <- Vendor(id, name:vendors_name@)
|
1009
|
+
]
|
1004
1010
|
|
1005
|
-
|
1011
|
+
[-1](**, ref_year) -> Goal(year, target)
|
1012
|
+
""")
|
1013
|
+
print(cte)
|
1006
1014
|
|
1007
1015
|
results...
|
1008
1016
|
```
|
1009
1017
|
WITH Annual_Sales_per_Vendor AS (
|
1010
|
-
SELECT ven.name as vendors_name
|
1011
|
-
,
|
1018
|
+
SELECT ven.name as vendors_name
|
1019
|
+
, Year(sal.ref_date) as ref_year
|
1020
|
+
, Sum(sal.quantity) as qty_sold
|
1021
|
+
FROM Vendor ven LEFT JOIN Sales sal ON (ven.id = sal.vendor
|
1012
1022
|
GROUP BY ven.name, ref_year
|
1013
1023
|
)
|
1014
1024
|
SELECT
|
1025
|
+
aspv.vendors_name,
|
1015
1026
|
aspv.ref_year,
|
1016
1027
|
aspv.qty_sold,
|
1017
|
-
aspv.vendors_name,
|
1018
1028
|
goa.target
|
1019
1029
|
FROM
|
1020
1030
|
Annual_Sales_per_Vendor aspv
|
1021
1031
|
RIGHT JOIN Goal goa ON (aspv.ref_year = goa.year)
|
1022
1032
|
```
|
1033
|
+
For more details, see the [Cypher syntax](#cypher_separators) or [CTE create method](#cte_create_method)!
|
1023
1034
|
|
1024
1035
|
|
1025
1036
|
---
|
@@ -558,16 +558,20 @@ ORDER BY
|
|
558
558
|
mov.title
|
559
559
|
```
|
560
560
|
---
|
561
|
-
|
561
|
+
|
562
|
+
#### Separators and meaning:
|
563
|
+
<a id="cypher_separators"></a>
|
564
|
+
|
562
565
|
* `( )` Delimits a table and its fields
|
563
566
|
* `,` Separate fields
|
564
567
|
* `?` For simple conditions (> < = <>)
|
565
568
|
* `<-` connects to the table on the left
|
566
569
|
* `->` connects to the table on the right
|
567
570
|
* `^` Put the field in the ORDER BY clause
|
568
|
-
* `@` Immediately after the table name, it indicates the grouping field.
|
571
|
+
* `@` Immediately after the table/field name, it indicates the grouping field.
|
569
572
|
* `$` For SQL functions like **avg**$_field_, **sum**$_field_, **count**$_field_...
|
570
573
|
* `*` Sets the primary key field.
|
574
|
+
* `:` Allows you to assign an alias to the field or expression.
|
571
575
|
|
572
576
|
|
573
577
|
---
|
@@ -854,6 +858,7 @@ UNION ALL
|
|
854
858
|
```
|
855
859
|
|
856
860
|
* **17.2.1 - The `create` method** ... parameters :
|
861
|
+
<a id="cte_create_method"></a>
|
857
862
|
- name: The name of the CTE
|
858
863
|
- pattern: A cypher script that defines the tables used
|
859
864
|
- formula: The format for `Where.formula` method _(*)_
|
@@ -866,6 +871,7 @@ UNION ALL
|
|
866
871
|
'[2] = R.[1]', 'JFK', format='.csv'
|
867
872
|
) # ^^^--- Flyghts from JFK airport
|
868
873
|
```
|
874
|
+
|
869
875
|
_...Creates a recursive CTE called Route, using Flyght table, where the recursivity condition is Flyght.arrival equals to Route.departure_
|
870
876
|
>> (*) -- Note that [1] and [2] refers to first field and second field. 😉
|
871
877
|
|
@@ -980,31 +986,36 @@ results...
|
|
980
986
|
|
981
987
|
#### 17.3.1 - You can also pass a Cypher script like in the example below:
|
982
988
|
|
983
|
-
cte = CTEFactory(
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
+
cte = CTEFactory("""
|
990
|
+
Annual_Sales_per_Vendor[
|
991
|
+
Sales(
|
992
|
+
year$ref_date:ref_year@, sum$quantity:qty_sold,
|
993
|
+
vendor) <- Vendor(id, name:vendors_name@)
|
994
|
+
]
|
989
995
|
|
990
|
-
|
996
|
+
[-1](**, ref_year) -> Goal(year, target)
|
997
|
+
""")
|
998
|
+
print(cte)
|
991
999
|
|
992
1000
|
results...
|
993
1001
|
```
|
994
1002
|
WITH Annual_Sales_per_Vendor AS (
|
995
|
-
SELECT ven.name as vendors_name
|
996
|
-
,
|
1003
|
+
SELECT ven.name as vendors_name
|
1004
|
+
, Year(sal.ref_date) as ref_year
|
1005
|
+
, Sum(sal.quantity) as qty_sold
|
1006
|
+
FROM Vendor ven LEFT JOIN Sales sal ON (ven.id = sal.vendor
|
997
1007
|
GROUP BY ven.name, ref_year
|
998
1008
|
)
|
999
1009
|
SELECT
|
1010
|
+
aspv.vendors_name,
|
1000
1011
|
aspv.ref_year,
|
1001
1012
|
aspv.qty_sold,
|
1002
|
-
aspv.vendors_name,
|
1003
1013
|
goa.target
|
1004
1014
|
FROM
|
1005
1015
|
Annual_Sales_per_Vendor aspv
|
1006
1016
|
RIGHT JOIN Goal goa ON (aspv.ref_year = goa.year)
|
1007
1017
|
```
|
1018
|
+
For more details, see the [Cypher syntax](#cypher_separators) or [CTE create method](#cte_create_method)!
|
1008
1019
|
|
1009
1020
|
|
1010
1021
|
---
|
@@ -1994,7 +1994,7 @@ class Select(SQLObject):
|
|
1994
1994
|
from copy import deepcopy
|
1995
1995
|
return deepcopy(self)
|
1996
1996
|
|
1997
|
-
def
|
1997
|
+
def relation_error(self, other: SQLObject):
|
1998
1998
|
raise ValueError(f'No relationship found between {self.table_name} and {other.table_name}.')
|
1999
1999
|
|
2000
2000
|
def __add__(self, other: SQLObject):
|
@@ -2011,7 +2011,7 @@ class Select(SQLObject):
|
|
2011
2011
|
PrimaryKey.add(primary_key, query)
|
2012
2012
|
query.add(foreign_field, other)
|
2013
2013
|
return other
|
2014
|
-
self.
|
2014
|
+
self.relation_error(other) # === raise ERROR ... ===
|
2015
2015
|
elif primary_key:
|
2016
2016
|
PrimaryKey.add(primary_key, other)
|
2017
2017
|
other.add(foreign_field, query)
|
@@ -2040,7 +2040,7 @@ class Select(SQLObject):
|
|
2040
2040
|
else:
|
2041
2041
|
fk_field, primary_k = ForeignKey.find(other, self)
|
2042
2042
|
if not fk_field:
|
2043
|
-
self.
|
2043
|
+
self.relation_error(other) # === raise ERROR ... ===
|
2044
2044
|
query = other.copy()
|
2045
2045
|
other = self.copy()
|
2046
2046
|
query.__class__ = NotSelectIN
|
@@ -2127,8 +2127,8 @@ class CTE(Select):
|
|
2127
2127
|
query.break_lines = False
|
2128
2128
|
result, line = [], ''
|
2129
2129
|
keywords = '|'.join(KEYWORD)
|
2130
|
-
for word in re.split(fr'({keywords}|AND|OR|,)', str(query)):
|
2131
|
-
if len(line) >=
|
2130
|
+
for word in re.split(fr'({keywords}|AND|OR|JOIN|,)', str(query)):
|
2131
|
+
if len(line) >= 30:
|
2132
2132
|
result.append(line)
|
2133
2133
|
line = ''
|
2134
2134
|
line += word
|
@@ -2197,7 +2197,8 @@ class Recursive(CTE):
|
|
2197
2197
|
MAIN_TAG = '__main__'
|
2198
2198
|
|
2199
2199
|
class CTEFactory:
|
2200
|
-
|
2200
|
+
TEMPLATE_FIELD_FUNC = lambda t: t.lower()[:3] + '_id'
|
2201
|
+
|
2201
2202
|
def __init__(self, txt: str, template: str = ''):
|
2202
2203
|
"""
|
2203
2204
|
SQL syntax:
|
@@ -2208,35 +2209,61 @@ class CTEFactory:
|
|
2208
2209
|
|
2209
2210
|
Cypher syntax:
|
2210
2211
|
---
|
2211
|
-
|
2212
|
-
|
2212
|
+
`cte_name`[
|
2213
|
+
Table1(field, `function$`field`:alias`, `group@`) <- Table2(field)
|
2214
|
+
]
|
2213
2215
|
"""
|
2216
|
+
def put_parentheses():
|
2217
|
+
result = txt
|
2218
|
+
for found in re.findall(r'\[\d+\][^(]', result):
|
2219
|
+
item = found.strip()[:3]
|
2220
|
+
result = result.replace(item, f'{item}()')
|
2221
|
+
return result
|
2222
|
+
txt, *negative = re.split(r'(\[-\d+\])', txt)
|
2223
|
+
txt = put_parentheses()
|
2224
|
+
txt, *suffix = re.split(r'(\[\d+\])', txt, maxsplit=1)
|
2214
2225
|
if template:
|
2215
2226
|
for table in re.findall(r'[#](\w+)', txt):
|
2216
|
-
txt = txt.replace(f'#{table}', template.format(
|
2217
|
-
|
2218
|
-
|
2219
|
-
|
2220
|
-
|
2221
|
-
|
2222
|
-
|
2223
|
-
)
|
2224
|
-
|
2225
|
-
|
2226
|
-
|
2227
|
+
txt = txt.replace( f'#{table}', template.format(
|
2228
|
+
t=table, f=CTEFactory.TEMPLATE_FIELD_FUNC(table)
|
2229
|
+
) )
|
2230
|
+
self.cte_list = []
|
2231
|
+
self.main = None
|
2232
|
+
for script in txt.split(']'):
|
2233
|
+
if '(' not in script:
|
2234
|
+
script += self.replace_wildcards(''.join(suffix))
|
2235
|
+
suffix = []
|
2236
|
+
self.build_ctes(script)
|
2237
|
+
if not self.cte_list:
|
2238
|
+
return
|
2239
|
+
if not suffix and negative:
|
2240
|
+
suffix = negative
|
2241
|
+
if suffix:
|
2242
|
+
self.main = detect( self.replace_wildcards(''.join(suffix)) )
|
2243
|
+
elif not self.main:
|
2244
|
+
self.main = Select(self.cte_list[0].table_name)
|
2245
|
+
self.main.break_lines = False
|
2246
|
+
|
2247
|
+
def build_ctes(self, script: str):
|
2248
|
+
alias, *body = script.split('[')
|
2249
|
+
if body:
|
2250
|
+
script = ''.join(body)
|
2251
|
+
if not re.sub( r'\s+', '', script):
|
2252
|
+
return
|
2253
|
+
if parser_class(script) == CypherParser:
|
2254
|
+
query_list = Select.parse(script, CypherParser)
|
2255
|
+
if not body:
|
2227
2256
|
alias = '_'.join(query.table_name for query in query_list)
|
2228
|
-
self.main = Select(alias)
|
2229
|
-
self.main.break_lines = False
|
2230
2257
|
related_tables = any([
|
2231
2258
|
query.join_type.value for query in query_list
|
2232
2259
|
])
|
2233
2260
|
if related_tables:
|
2234
2261
|
query_list = [ join_queries(query_list) ]
|
2235
|
-
self.cte_list
|
2262
|
+
self.cte_list += [CTE(alias, query_list)]
|
2236
2263
|
return
|
2237
|
-
summary = self.extract_subqueries(
|
2264
|
+
summary = self.extract_subqueries(script)
|
2238
2265
|
self.main = detect( summary.pop(MAIN_TAG) )
|
2239
|
-
self.cte_list
|
2266
|
+
self.cte_list += [
|
2240
2267
|
CTE(alias, [
|
2241
2268
|
Select.parse(query)[0]
|
2242
2269
|
for query in elements
|
@@ -2245,24 +2272,43 @@ class CTEFactory:
|
|
2245
2272
|
]
|
2246
2273
|
|
2247
2274
|
def __str__(self):
|
2275
|
+
if not self.main:
|
2276
|
+
return ''
|
2248
2277
|
CTE.show_query = False
|
2249
2278
|
lines = [str(cte) for cte in self.cte_list]
|
2250
2279
|
result = ',\n'.join(lines) + '\n' + str(self.main)
|
2251
2280
|
CTE.show_query = True
|
2252
2281
|
return result
|
2253
2282
|
|
2254
|
-
|
2255
|
-
|
2256
|
-
|
2257
|
-
|
2258
|
-
|
2259
|
-
|
2260
|
-
|
2261
|
-
|
2262
|
-
|
2263
|
-
|
2264
|
-
|
2265
|
-
|
2283
|
+
def replace_wildcards(self, txt: str) -> str:
|
2284
|
+
ALL_FIELDS_WILDCARD = '**'
|
2285
|
+
result = ''
|
2286
|
+
names = []
|
2287
|
+
query_list = []
|
2288
|
+
cte: CTE
|
2289
|
+
for cte in self.cte_list:
|
2290
|
+
names.append(cte.table_name)
|
2291
|
+
query_list += cte.query_list
|
2292
|
+
last = 0
|
2293
|
+
for found in re.finditer(r'\[[-]*\d+\]', txt):
|
2294
|
+
pos = int(re.sub(r'\[|\]', '', found.group()))
|
2295
|
+
if pos > 0:
|
2296
|
+
pos -= 1
|
2297
|
+
start = found.start()
|
2298
|
+
result += txt[last:start] + names[pos]
|
2299
|
+
last = found.end()
|
2300
|
+
txt = result + txt[last:]
|
2301
|
+
if ALL_FIELDS_WILDCARD in txt:
|
2302
|
+
field_list = []
|
2303
|
+
for query in query_list:
|
2304
|
+
for field in query.values.get(SELECT, []):
|
2305
|
+
new_item = re.split(
|
2306
|
+
r'\bas\b|\bAS\b|[.]', field
|
2307
|
+
)[-1].strip()
|
2308
|
+
if new_item not in field_list:
|
2309
|
+
field_list.append(new_item)
|
2310
|
+
return txt.replace(ALL_FIELDS_WILDCARD, '{}'.format(
|
2311
|
+
','.join(field_list)
|
2266
2312
|
))
|
2267
2313
|
return txt
|
2268
2314
|
|
@@ -2458,38 +2504,3 @@ def detect(text: str, join_method = join_queries, format: str='') -> Select | li
|
|
2458
2504
|
# ===========================================================================================//
|
2459
2505
|
|
2460
2506
|
|
2461
|
-
if __name__ == "__main__":
|
2462
|
-
OrderBy.sort = SortType.DESC
|
2463
|
-
cte = CTEFactory(
|
2464
|
-
# "#Customer#Employee#Supplier...People_by_Type(*)",
|
2465
|
-
# template = '{t}("{t[0]}":ptype, nome:person_name)'
|
2466
|
-
"""
|
2467
|
-
SELECT u001.name, agg_sales.total
|
2468
|
-
FROM (
|
2469
|
-
SELECT * FROM Users u
|
2470
|
-
WHERE u.status = 'active'
|
2471
|
-
) AS u001
|
2472
|
-
JOIN (
|
2473
|
-
SELECT s.user_id, Sum(s.value) as total
|
2474
|
-
FROM Sales s
|
2475
|
-
GROUP BY s.user_id
|
2476
|
-
)
|
2477
|
-
As agg_sales
|
2478
|
-
ON u001.id = agg_sales.user_id
|
2479
|
-
ORDER BY u001.name
|
2480
|
-
"""
|
2481
|
-
# "Sales(year$ref_date:ref_year@, sum$quantity:qty_sold, vendor) <- Vendor(id, name:vendors_name@)"
|
2482
|
-
# ^^^ ^^^ ^^^
|
2483
|
-
# | | | ^^^ ^^^
|
2484
|
-
# | | | | |
|
2485
|
-
# | | | Relate Sales to Vendor --------+ |
|
2486
|
-
# | | | |
|
2487
|
-
# | | +---- Call it `ref_year` and group it |
|
2488
|
-
# | | |
|
2489
|
-
# | +-- Extracts the year from the `ref_date` field |
|
2490
|
-
# | |
|
2491
|
-
# +--- The Sales table |
|
2492
|
-
# Also groups by vendor´s name ------------------+
|
2493
|
-
# "...Annual_Sales_per_Vendor(*) -> Goal(^year, target)"
|
2494
|
-
)
|
2495
|
-
print(cte)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sql_blocks
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.20250719
|
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
|
@@ -573,16 +573,20 @@ ORDER BY
|
|
573
573
|
mov.title
|
574
574
|
```
|
575
575
|
---
|
576
|
-
|
576
|
+
|
577
|
+
#### Separators and meaning:
|
578
|
+
<a id="cypher_separators"></a>
|
579
|
+
|
577
580
|
* `( )` Delimits a table and its fields
|
578
581
|
* `,` Separate fields
|
579
582
|
* `?` For simple conditions (> < = <>)
|
580
583
|
* `<-` connects to the table on the left
|
581
584
|
* `->` connects to the table on the right
|
582
585
|
* `^` Put the field in the ORDER BY clause
|
583
|
-
* `@` Immediately after the table name, it indicates the grouping field.
|
586
|
+
* `@` Immediately after the table/field name, it indicates the grouping field.
|
584
587
|
* `$` For SQL functions like **avg**$_field_, **sum**$_field_, **count**$_field_...
|
585
588
|
* `*` Sets the primary key field.
|
589
|
+
* `:` Allows you to assign an alias to the field or expression.
|
586
590
|
|
587
591
|
|
588
592
|
---
|
@@ -869,6 +873,7 @@ UNION ALL
|
|
869
873
|
```
|
870
874
|
|
871
875
|
* **17.2.1 - The `create` method** ... parameters :
|
876
|
+
<a id="cte_create_method"></a>
|
872
877
|
- name: The name of the CTE
|
873
878
|
- pattern: A cypher script that defines the tables used
|
874
879
|
- formula: The format for `Where.formula` method _(*)_
|
@@ -881,6 +886,7 @@ UNION ALL
|
|
881
886
|
'[2] = R.[1]', 'JFK', format='.csv'
|
882
887
|
) # ^^^--- Flyghts from JFK airport
|
883
888
|
```
|
889
|
+
|
884
890
|
_...Creates a recursive CTE called Route, using Flyght table, where the recursivity condition is Flyght.arrival equals to Route.departure_
|
885
891
|
>> (*) -- Note that [1] and [2] refers to first field and second field. 😉
|
886
892
|
|
@@ -995,31 +1001,36 @@ results...
|
|
995
1001
|
|
996
1002
|
#### 17.3.1 - You can also pass a Cypher script like in the example below:
|
997
1003
|
|
998
|
-
cte = CTEFactory(
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
+
cte = CTEFactory("""
|
1005
|
+
Annual_Sales_per_Vendor[
|
1006
|
+
Sales(
|
1007
|
+
year$ref_date:ref_year@, sum$quantity:qty_sold,
|
1008
|
+
vendor) <- Vendor(id, name:vendors_name@)
|
1009
|
+
]
|
1004
1010
|
|
1005
|
-
|
1011
|
+
[-1](**, ref_year) -> Goal(year, target)
|
1012
|
+
""")
|
1013
|
+
print(cte)
|
1006
1014
|
|
1007
1015
|
results...
|
1008
1016
|
```
|
1009
1017
|
WITH Annual_Sales_per_Vendor AS (
|
1010
|
-
SELECT ven.name as vendors_name
|
1011
|
-
,
|
1018
|
+
SELECT ven.name as vendors_name
|
1019
|
+
, Year(sal.ref_date) as ref_year
|
1020
|
+
, Sum(sal.quantity) as qty_sold
|
1021
|
+
FROM Vendor ven LEFT JOIN Sales sal ON (ven.id = sal.vendor
|
1012
1022
|
GROUP BY ven.name, ref_year
|
1013
1023
|
)
|
1014
1024
|
SELECT
|
1025
|
+
aspv.vendors_name,
|
1015
1026
|
aspv.ref_year,
|
1016
1027
|
aspv.qty_sold,
|
1017
|
-
aspv.vendors_name,
|
1018
1028
|
goa.target
|
1019
1029
|
FROM
|
1020
1030
|
Annual_Sales_per_Vendor aspv
|
1021
1031
|
RIGHT JOIN Goal goa ON (aspv.ref_year = goa.year)
|
1022
1032
|
```
|
1033
|
+
For more details, see the [Cypher syntax](#cypher_separators) or [CTE create method](#cte_create_method)!
|
1023
1034
|
|
1024
1035
|
|
1025
1036
|
---
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|