Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagesql
 SELECT 
			CAST(FILE_ID, AS 11),
			CAST(FILE_NAME, AS 22),
			CAST(FILE_TYPE, AS 33),
            CAST(FILE_SIZE, AS 44),
			CAST(COUNT(PART_ID), AS 55),
			AGG_EXPAND(STAGE, AS 66),
			AGG_EXPAND(AGE, AS 77),
			CAST(GROUP_CONCAT(DISTINCT PART_ID), AS 88)
				FROM MATERIAL
				WHERE FILE_ID IS NOT NULL GROUP BY FILE_ID, FILE_NAME, FILE_TYPE, FILE_SIZE

...

Next, at line:2 we have CAST(FILE_ID , AS 11), which defines the first column of the perspective. This line is simply casting the FILE_ID as column ID: 11. In other words, line 2 tells Synapse to treat the first column of the resulting table as type INTEGER with the name FILE_ID (see: ID 11). Note: Since FILE_ID is part of the group by, we are not required apply an aggregation function to it. Any column that is not part of the group by must have some type of aggregation functions.

...

At line:7 we have a new function: AGG_EXPAND(STAGE , AS 66) called AGG_EXPAND. This function call is syntactic sugar that tells Synapse to do the following:

...

At line:8 we have AGG_EXPAND(AGE , AS 77) which will do a similar expansion to the previous case. This expansion will create a column for each aggregate function defined in column ID=77.

Finally, at line:9 we have CAST(GROUP_CONCAT(DISTINCT PART_ID) , AS 88). The group concat function will create a comma separated list of all of the PART_IDs that match each file. The results are then cast to column ID=88 which is of type STRING_LIST. This means this column will behave similar to other string list columns in Synapse.

...

So how does that work exactly? Basically, when the user provides select * from syn123 at runtime, we run the following query on their behalf:

Code Block
WITH
	F2PAGG AS (
		SELECT 
			FILE_ID,
			FILE_NAME,
			FILE_TYPE,
            FILE_SIZE,
			COUNT(PART_ID) AS PART_COUNT,
			
            JSON_OBJECT('one', SUM(CASE STAGE WHEN 'one' THEN 1 ELSE 0 END), AS STAGE_ONE_COUNT,

						'two', SUM(CASE STAGE WHEN 'two' THEN 1 ELSE 0 END)) ASas PART_STAGE_TWO_COUNT,
            MAXJSON_OBJECT('min', MIN(AGE), AS MAX_AGE,
            MIN(AGE) AS MIN_AGE,
			GROUP_CONCAT(DISTINCT PART_ID) AS PART_IDS FROM MATERIAL
				WHERE FILE_ID IS NOT NULL GROUP BY FILE_ID, FILE_NAME, FILE_TYPE, FILE_SIZE
    ),
    AGG AS (
		SELECT FILE_ID, FILE_NAME, FILE_TYPE, FILE_SIZE, PART_COUNT,
			JSON_OBJECT('one', STAGE_ONE_COUNT, 'two', STAGE_TWO_COUNT) as PART_STAGE,
            JSON_OBJECT('min', MIN_AGE, 'max', MAX_AGE) as PART_AGE,
            PART_IDS
				FROM F2P
    'max', MAX(AGE)) as PART_AGE,
			GROUP_CONCAT(DISTINCT PART_ID) AS PART_IDS FROM MATERIAL
				WHERE FILE_ID IS NOT NULL GROUP BY FILE_ID, FILE_NAME, FILE_TYPE, FILE_SIZE
	)
SELECT * FROM AGG;

The above SQL is actually a combination of the syn123’s defining SQL and the runtime query (select * from syn123). Specifically, two the inner queries query of the common table expression (CTE) (lines:23-2214) are an expansion of the defining SQL. While the runtime query is transformed into the outer query of the CTE (line:2315). In essence, the user is querying what appears to be a simple table.

...

A real runtime query transformation would be more complex but basic principals would still apply. For example, since our MATERIAL table includes files, the transformation process would include adding a row-level-filter to hide rows where the user lacks the read permission. This type of query manipulation is already common for existing Synapse tables/views.

In the finalnext section, section we will show how runtime filtering and sorting would be applied using a few examples.

...

Code Block
select * from syn123 where PART_STAGE.one > 2

For this query the first 22 14 lines of the above query would remain the same, while the last line (line:3215) would become:

Code Block
select * from AGG where JSON_EXTRACT(PART_STAGE, '$.one') > 2;

...

Here we have defined a new function called pre_agg() which is syntactic sugar that means apply this filter before aggregation. So rather than apply the filter at the end of the CTE (line:2315) add it is added to the first inner layer of the CTE (line:1413).

The key to this entire design is that there is always a one-to-one translation for anything in the both the provide defining SQL and runtime queries.

...