• 【翻译】Flink Table Api & SQL — SQL


    本文翻译自官网:SQL https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/table/sql.html

    Flink Table Api & SQL 翻译目录

    这是Flink 支持的 数据定义语言(DDL) 和数据操纵语言的完整列表。

    查询

    SQL查询使用TableEnvironment 的 sqlQuery() 方法指定。这个方法返回一个表作为SQL查询的结果。这个表可以在后续的 SQL 和 Table API 中查询,可以转换为 DataSet 和 DataStream ,或写到 TableSink 中。SQL和Table API查询可以无缝混合,可以进行整体优化并将其转换为单个程序。

    为了在 SQL 查询中使用一个表,它必须在 TableEnvironment 中注册。表可以通过  TableSourceTableCREATE TABLE statementDataStream, or DataSet 注册。或者,用户还可以在TableEnvironment中注册外部目录以指定数据源的位置。

    为方便起见,Table.toString()自动在其TableEnvironment中以唯一名称注册该表并返回该名称。 因此,可以将Table对象直接内联到SQL查询中(通过字符串连接),如下面的示例所示。

    注意:Flink的SQL支持尚未完成。 包含不受支持的SQL功能的查询会导致TableException。 以下各节列出了批处理表和流表上SQL的受支持功能。

    指定查询

     以下示例显示如何在已注册和内联表上指定SQL查询。

    val env = StreamExecutionEnvironment.getExecutionEnvironment
    val tableEnv = StreamTableEnvironment.create(env)
    
    // read a DataStream from an external source
    val ds: DataStream[(Long, String, Integer)] = env.addSource(...)
    
    // SQL query with an inlined (unregistered) table
    val table = ds.toTable(tableEnv, 'user, 'product, 'amount)
    val result = tableEnv.sqlQuery(
      s"SELECT SUM(amount) FROM $table WHERE product LIKE '%Rubber%'")
    
    // SQL query with a registered table
    // register the DataStream under the name "Orders"
    tableEnv.registerDataStream("Orders", ds, 'user, 'product, 'amount)
    // run a SQL query on the Table and retrieve the result as a new Table
    val result2 = tableEnv.sqlQuery(
      "SELECT product, amount FROM Orders WHERE product LIKE '%Rubber%'")
    
    // SQL update with a registered table
    // create and register a TableSink
    val csvSink: CsvTableSink = new CsvTableSink("/path/to/file", ...)
    val fieldNames: Array[String] = Array("product", "amount")
    val fieldTypes: Array[TypeInformation[_]] = Array(Types.STRING, Types.INT)
    tableEnv.registerTableSink("RubberOrders", fieldNames, fieldTypes, csvSink)
    // run a SQL update query on the Table and emit the result to the TableSink
    tableEnv.sqlUpdate(
      "INSERT INTO RubberOrders SELECT product, amount FROM Orders WHERE product LIKE '%Rubber%'")

    Supported Syntax

     Flink使用支持标准ANSI SQL的Apache Calcite解析SQL。 Flink不支持DDL语句。

    以下BNF语法描述了批处理和流查询中支持的SQL功能的超集。 “操作”部分显示了受支持功能的示例,并指示仅批处理或流查询支持哪些功能。

    insert:
      INSERT INTO tableReference
      query
      
    query:
      values
      | {
          select
          | selectWithoutFrom
          | query UNION [ ALL ] query
          | query EXCEPT query
          | query INTERSECT query
        }
        [ ORDER BY orderItem [, orderItem ]* ]
        [ LIMIT { count | ALL } ]
        [ OFFSET start { ROW | ROWS } ]
        [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY]
    
    orderItem:
      expression [ ASC | DESC ]
    
    select:
      SELECT [ ALL | DISTINCT ]
      { * | projectItem [, projectItem ]* }
      FROM tableExpression
      [ WHERE booleanExpression ]
      [ GROUP BY { groupItem [, groupItem ]* } ]
      [ HAVING booleanExpression ]
      [ WINDOW windowName AS windowSpec [, windowName AS windowSpec ]* ]
      
    selectWithoutFrom:
      SELECT [ ALL | DISTINCT ]
      { * | projectItem [, projectItem ]* }
    
    projectItem:
      expression [ [ AS ] columnAlias ]
      | tableAlias . *
    
    tableExpression:
      tableReference [, tableReference ]*
      | tableExpression [ NATURAL ] [ LEFT | RIGHT | FULL ] JOIN tableExpression [ joinCondition ]
    
    joinCondition:
      ON booleanExpression
      | USING '(' column [, column ]* ')'
    
    tableReference:
      tablePrimary
      [ matchRecognize ]
      [ [ AS ] alias [ '(' columnAlias [, columnAlias ]* ')' ] ]
    
    tablePrimary:
      [ TABLE ] [ [ catalogName . ] schemaName . ] tableName
      | LATERAL TABLE '(' functionName '(' expression [, expression ]* ')' ')'
      | UNNEST '(' expression ')'
    
    values:
      VALUES expression [, expression ]*
    
    groupItem:
      expression
      | '(' ')'
      | '(' expression [, expression ]* ')'
      | CUBE '(' expression [, expression ]* ')'
      | ROLLUP '(' expression [, expression ]* ')'
      | GROUPING SETS '(' groupItem [, groupItem ]* ')'
    
    windowRef:
        windowName
      | windowSpec
    
    windowSpec:
        [ windowName ]
        '('
        [ ORDER BY orderItem [, orderItem ]* ]
        [ PARTITION BY expression [, expression ]* ]
        [
            RANGE numericOrIntervalExpression {PRECEDING}
          | ROWS numericExpression {PRECEDING}
        ]
        ')'
    
    matchRecognize:
          MATCH_RECOGNIZE '('
          [ PARTITION BY expression [, expression ]* ]
          [ ORDER BY orderItem [, orderItem ]* ]
          [ MEASURES measureColumn [, measureColumn ]* ]
          [ ONE ROW PER MATCH ]
          [ AFTER MATCH
                ( SKIP TO NEXT ROW
                | SKIP PAST LAST ROW
                | SKIP TO FIRST variable
                | SKIP TO LAST variable
                | SKIP TO variable )
          ]
          PATTERN '(' pattern ')'
          [ WITHIN intervalLiteral ]
          DEFINE variable AS condition [, variable AS condition ]*
          ')'
    
    measureColumn:
          expression AS alias
    
    pattern:
          patternTerm [ '|' patternTerm ]*
    
    patternTerm:
          patternFactor [ patternFactor ]*
    
    patternFactor:
          variable [ patternQuantifier ]
    
    patternQuantifier:
          '*'
      |   '*?'
      |   '+'
      |   '+?'
      |   '?'
      |   '??'
      |   '{' { [ minRepeat ], [ maxRepeat ] } '}' ['?']
      |   '{' repeat '}'

    Flink SQL对类似于Java的标识符(表,属性,函数名称)使用词法策略:

    • 不管是否引用标识符,都保留标识符的大小写。
    • 之后,标识符区分大小写。
    • 与Java不同,反引号允许标识符包含非字母数字字符(例如"SELECT a AS `my field` FROM t")。

    字符串文字必须用单引号引起来(例如SELECT 'Hello World')。复制单引号以进行转义(例如SELECT 'It''s me.')。字符串文字中支持Unicode字符。如果需要明确的unicode代码点,请使用以下语法:

    • 使用反斜杠()作为转义字符(默认):SELECT U&'263A'
    • 使用自定义转义字符: SELECT U&'#263A' UESCAPE '#'

    Operations

    Show and Use

    OperationDescription
    Show
    Batch Streaming

    Show all catalogs

    SHOW CATALOGS;

    Show all databases in the current catalog

    SHOW DATABASES;

    Show all tables in the current database in the current catalog

    SHOW TABLES;
    Use
    Batch Streaming

    Set current catalog for the session

    USE CATALOG mycatalog;

    Set current database of the current catalog for the session

    USE mydatabase;

    Scan, Projection, and Filter

    OperationDescription
    Scan / Select / As
    Batch Streaming
    SELECT * FROM Orders
    
    SELECT a, c AS d FROM Orders
    Where / Filter
    Batch Streaming
    SELECT * FROM Orders WHERE b = 'red'
    
    SELECT * FROM Orders WHERE a % 2 = 0
    User-defined Scalar Functions (Scalar UDF)
    Batch Streaming

    UDFs  必须在TableEnvironment 中注册了. See the UDF documentation  有关如何指定和注册标量UDF的详细信息.

    SELECT PRETTY_PRINT(user) FROM Orders

    Aggregations

    OperationDescription
    GroupBy Aggregation
    Batch Streaming
    Result Updating

    Note: 流表上的GroupBy产生更新结果. See the Dynamic Tables Streaming Concepts page for details.

    SELECT a, SUM(b) as d
    FROM Orders
    GROUP BY a
    GroupBy Window Aggregation
    Batch Streaming

    使用分组窗口可为每个组计算一个结果行。 有关更多详细信息,请参见Group Windows 部分。

    SELECT user, SUM(amount)
    FROM Orders
    GROUP BY TUMBLE(rowtime, INTERVAL '1' DAY), user
    Over Window aggregation
    Streaming

    Note: 必须在同一窗口(即相同的分区,排序和范围)上定义所有聚合。 当前,仅支持PRECEDING(无边界和有界)到CURRENT ROW范围的窗口。

    目前尚不支持带有FOLLOWING的范围。 必须在单个时间属性上指定ORDER BY

    SELECT COUNT(amount) OVER (
      PARTITION BY user
      ORDER BY proctime
      ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
    FROM Orders
    
    SELECT COUNT(amount) OVER w, SUM(amount) OVER w
    FROM Orders 
    WINDOW w AS (
      PARTITION BY user
      ORDER BY proctime
      ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)  
    Distinct
    Batch Streaming 
    Result Updating
    SELECT DISTINCT users FROM Orders

    Note: 对于流查询,根据不同字段的数量,计算查询结果所需的状态可能会无限增长。

    请提供具有有效保留间隔的查询配置,以防止出现过多的状态。 有关详细信息,请参见查询配置。.

    Grouping sets, Rollup, Cube
    Batch
    SELECT SUM(amount)
    FROM Orders
    GROUP BY GROUPING SETS ((user), (product))
    Having
    Batch Streaming
    SELECT SUM(amount)
    FROM Orders
    GROUP BY users
    HAVING SUM(amount) > 50
    User-defined Aggregate Functions (UDAGG)
    Batch Streaming

    UDAGG必须在TableEnvironment中注册。 有关如何指定和注册UDAGG的详细信息,请参见UDF文档。

    SELECT MyAggregate(amount)
    FROM Orders
    GROUP BY users

    Joins

    OperationDescription
    Inner Equi-join
    Batch Streaming

    当前,仅支持等值连接,即具有至少一个具有相等谓词的联合条件的连接。 不支持任意交叉或 theta 连接 (自连接).

    Note: 连接顺序未优化。 表按照在FROM子句中指定的顺序进行连接。 确保以不产生交叉联接(笛卡尔乘积)的顺序指定表,该顺序不被支持并会导致查询失败.

    SELECT *
    FROM Orders INNER JOIN Product ON Orders.productId = Product.id

    Note: 对于流查询,根据不同输入行的数量,计算查询结果所需的状态可能会无限增长。 请提供具有有效保留间隔的查询配置,以防止出现过多的状态。 有关详细信息,请参见查询配置。

    Outer Equi-join
    Batch StreamingResult Updating

    当前,仅支持等值连接,即具有至少一个具有相等谓词的联合条件的连接。 不支持任意交叉或 theta 连接 (自连接).

    Note: 连接顺序未优化。 表按照在FROM子句中指定的顺序进行连接。 确保以不产生交叉联接(笛卡尔乘积)的顺序指定表,该顺序不被支持并会导致查询失败.

    SELECT *
    FROM Orders LEFT JOIN Product ON Orders.productId = Product.id
    
    SELECT *
    FROM Orders RIGHT JOIN Product ON Orders.productId = Product.id
    
    SELECT *
    FROM Orders FULL OUTER JOIN Product ON Orders.productId = Product.id

    Note: 对于流查询,根据不同输入行的数量,计算查询结果所需的状态可能会无限增长。 请提供具有有效保留间隔的查询配置,以防止出现过多的状态。 有关详细信息,请参见查询配置。

    Time-windowed Join
    Batch Streaming

    Note: 时间窗口连接是常规连接的子集,可以以流方式处理.

    时间窗连接需要至少一个等联接谓词和在两侧限制时间的连接条件。两个输入表可以通过两个适当的范围谓词(<,<=,> =,>),BETWEEN谓词或比较相同类型的时间属性

    (即处理时间或事件时间)的单个相等谓词来定义这样的条件 .

    例如,以下谓词是有效的窗口连接条件:

    • ltime = rtime
    • ltime >= rtime AND ltime < rtime + INTERVAL '10' MINUTE
    • ltime BETWEEN rtime - INTERVAL '10' SECOND AND rtime + INTERVAL '5' SECOND
    SELECT *
    FROM Orders o, Shipments s
    WHERE o.id = s.orderId AND
          o.ordertime BETWEEN s.shiptime - INTERVAL '4' HOUR AND s.shiptime
    如果订单在收到订单后四个小时内发货,则上面的示例会将所有订单与其相应的发货合并在一起.
    Expanding arrays into a relation
    Batch Streaming

    目前尚不支持使用ORDINALITY取消嵌套.

    SELECT users, tag
    FROM Orders CROSS JOIN UNNEST(tags) AS t (tag)
    Join with Table Function (UDTF)
    Batch Streaming

    用表函数的结果连接表。 左(外)表的每一行都与表函数的相应调用产生的所有行连接在一起.

    必须先注册用户定义的表函数(UDTF)。 有关如何指定和注册UDTF的详细信息,请参见UDF文档。

    Inner Join

    如果左表(外部)的表函数调用返回空结果,则会删除该表的左行.

    SELECT users, tag
    FROM Orders, LATERAL TABLE(unnest_udtf(tags)) t AS tag

    Left Outer Join

    如果表函数调用返回空结果,则保留对应的外部行,并用空值填充结果.

    SELECT users, tag
    FROM Orders LEFT JOIN LATERAL TABLE(unnest_udtf(tags)) t AS tag ON TRUE

    Note: 当前,仅支持将文字TRUE作为针对横向表的左外部连接的谓词。

    Join with Temporal Table Function
    Streaming

    时态表是跟踪随时间变化的表.

    时态表功能提供对特定时间点时态表状态的访问。 使用时态表函数联接表的语法与使用表函数联接的语法相同.

    Note: 当前仅支持带有时态表的内部联接.

    假设Rates是一个时态表函数,则联接可以用SQL表示如下:

    SELECT
      o_amount, r_rate
    FROM
      Orders,
      LATERAL TABLE (Rates(o_proctime))
    WHERE
      r_currency = o_currency

    有关更多信息,请检查更详细的时态表概念描述.

    Join with Temporal Table
    Batch Streaming

    时态表是跟踪随时间变化的表。 临时表提供对特定时间点的时态表版本的访问.

    仅支持带有处理时间时态表的内部联接和左联接.

    下面的示例假定LatestRates是一个以最新速率物化的时态表.

    SELECT
      o.amout, o.currency, r.rate, o.amount * r.rate
    FROM
      Orders AS o
      JOIN LatestRates FOR SYSTEM_TIME AS OF o.proctime AS r
      ON r.currency = o.currency

    有关更多信息,请检查更详细的时态表概念描述.

    只有Blink planner 支持.

    Set Operations

    OperationDescription
    Union
    Batch
    SELECT *
    FROM (
        (SELECT user FROM Orders WHERE a % 2 = 0)
      UNION
        (SELECT user FROM Orders WHERE b = 0)
    )
    UnionAll
    Batch Streaming
    SELECT *
    FROM (
        (SELECT user FROM Orders WHERE a % 2 = 0)
      UNION ALL
        (SELECT user FROM Orders WHERE b = 0)
    )
    Intersect / Except
    Batch
    SELECT *
    FROM (
        (SELECT user FROM Orders WHERE a % 2 = 0)
      INTERSECT
        (SELECT user FROM Orders WHERE b = 0)
    )
    SELECT *
    FROM (
        (SELECT user FROM Orders WHERE a % 2 = 0)
      EXCEPT
        (SELECT user FROM Orders WHERE b = 0)
    )
    In
    Batch Streaming

    如果给定表子查询中存在表达式,则返回true。 子查询表必须由一列组成。 此列的数据类型必须与表达式相同.

    SELECT user, amount
    FROM Orders
    WHERE product IN (
        SELECT product FROM NewProducts
    )

    Note: 对于流查询,该操作将被重写为join and group操作。 根据不同输入行的数量,计算查询结果所需的状态可能会无限增长。

    请提供具有有效保留间隔的查询配置,以防止出现过多的状态。 有关详细信息,请参见查询配置。.

    Exists
    Batch Streaming

    如果子查询返回至少一行,则返回true。 仅在可以在联接和组操作中重写操作时才受支持.

    SELECT user, amount
    FROM Orders
    WHERE product EXISTS (
        SELECT product FROM NewProducts
    )

    Note: 对于流查询,该操作将被重写为join and group操作。 根据不同输入行的数量,计算查询结果所需的状态可能会无限增长。

    请提供具有有效保留间隔的查询配置,以防止出现过多的状态。 有关详细信息,请参见查询配置。.

    OrderBy & Limit

    OperationDescription
    Order By
    Batch Streaming
    Note: 流查询的结果必须主要按升序时间属性排序。 支持其他排序属性.
    SELECT *
    FROM Orders
    ORDER BY orderTime
    Limit
    Batch
    Note: LIMIT子句需要ORDER BY子句.
    SELECT *
    FROM Orders
    ORDER BY orderTime
    LIMIT 3

    Top-N

     注意:仅Blink planner 仅支持Top-N。

    Top-N 查询要求按列排序的N个最小值或最大值。 最小和最大值集都被认为是Top-N查询。 在需要只显示批处理/流表中的N个最底层记录或N个最顶层记录的情况下,Top-N查询很有用。 此结果集可用于进一步分析。

    Flink使用OVER窗口子句和过滤条件的组合来表示Top-N查询。 借助OVER window PARTITION BY子句的强大功能,Flink还支持每组Top-N。 例如,每个类别中实时销量最高的前五种产品。 批处理表和流表上的SQL支持Top-N查询。

    下面显示了TOP-N语句的语法:

    SELECT [column_list]
    FROM (
       SELECT [column_list],
         ROW_NUMBER() OVER ([PARTITION BY col1[, col2...]]
           ORDER BY col1 [asc|desc][, col2 [asc|desc]...]) AS rownum
       FROM table_name)
    WHERE rownum <= N [AND conditions]

    参数含义:

    • ROW_NUMBER(): 根据分区中各行的顺序,为每一行分配一个唯一的顺序号(从1开始)。 目前,我们仅支持ROW_NUMBER作为窗口函数。 将来,我们将支持RANK()和DENSE_RANK().
    • PARTITION BY col1[, col2...]: 指定分区列。 每个分区都有一个Top-N结果.
    • ORDER BY col1 [asc|desc][, col2 [asc|desc]...]: 指定排序列。 不同列上的排序方向可以不同.
    • WHERE rownum <= N: Flink将rownum <= N识别为该查询是Top-N查询。 N代表将保留N个最小或最大记录.
    • [AND conditions]: 可以在where子句中添加其他条件,但是其他条件只能与AND结合使用rownum <= N.

     流模式下的注意:TopN查询会更新结果。 Flink SQL将根据顺序键对输入数据流进行排序,因此,如果前N条记录已更改,则更改后的记录将作为撤消/更新记录发送到下游。 建议使用支持更新的存储作为Top-N查询的接收器。 此外,如果需要将前N条记录存储在外部存储中,则结果表应具有与前N条查询相同的唯一键。

    Top-N查询的唯一键是分区列和rownum列的组合。 Top-N查询还可以导出上游的唯一键。 以下面的工作为例,假设product_id是ShopSales的唯一键,那么Top-N查询的唯一键是[category,rownum]和[product_id]。

    以下示例显示如何在流表上使用Top-N指定SQL查询。 这是我们上面提到的“每个类别中实时销量最高的前五种产品”的示例。

    val env = StreamExecutionEnvironment.getExecutionEnvironment
    val tableEnv = TableEnvironment.getTableEnvironment(env)
    
    // read a DataStream from an external source
    val ds: DataStream[(String, String, String, Long)] = env.addSource(...)
    // register the DataStream under the name "ShopSales"
    tableEnv.registerDataStream("ShopSales", ds, 'product_id, 'category, 'product_name, 'sales)
    
    
    // select top-5 products per category which have the maximum sales.
    val result1 = tableEnv.sqlQuery(
        """
          |SELECT *
          |FROM (
          |   SELECT *,
          |       ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) as row_num
          |   FROM ShopSales)
          |WHERE row_num <= 5
        """.stripMargin)

    没有排名输出优化

    如上所述,rownum字段将作为唯一键的一个字段写入结果表,这可能导致许多记录被写入结果表。 例如,当更新排名9的记录(例如product-1001)并将其排名升级到1时,排名1到9的所有记录将作为更新消息输出到结果表。 如果结果表接收到太多数据,它会成为SQL作业的瓶颈。

    优化方法是在Top-N查询的外部SELECT子句中省略rownum字段。 这是合理的,因为前N条记录的数量通常不大,因此消费者可以自己对记录进行快速排序。 如果没有rownum字段,则在上面的示例中,仅需要将已更改的记录(product-1001)发送到下游,这可以减少结果表的大量IO。

    下面的示例显示如何以这种方式优化上面的Top-N示例:

    val env = StreamExecutionEnvironment.getExecutionEnvironment
    val tableEnv = TableEnvironment.getTableEnvironment(env)
    
    // read a DataStream from an external source
    val ds: DataStream[(String, String, String, Long)] = env.addSource(...)
    // register the DataStream under the name "ShopSales"
    tableEnv.registerDataStream("ShopSales", ds, 'product_id, 'category, 'product_name, 'sales)
    
    
    // select top-5 products per category which have the maximum sales.
    val result1 = tableEnv.sqlQuery(
        """
          |SELECT product_id, category, product_name, sales  -- omit row_num field in the output
          |FROM (
          |   SELECT *,
          |       ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) as row_num
          |   FROM ShopSales)
          |WHERE row_num <= 5
        """.stripMargin)

    流传输模式中的注意事项:为了将以上查询输出到外部存储并获得正确的结果,外部存储必须具有与Top-N查询相同的唯一键。 在上面的示例查询中,如果product_id是查询的唯一键,则外部表也应将product_id作为唯一键。

    重复数据删除

     注意:重复数据删除仅在Blink planner 中受支持。

    重复数据删除是指删除在一组列上重复的行,仅保留第一个或最后一个。 在某些情况下,上游ETL作业不是一次精确的端到端,这可能导致在故障转移的情况下,接收器中有重复的记录。 但是,重复的记录将影响下游分析作业的正确性(例如SUM,COUNT)。 因此,在进一步分析之前需要进行重复数据删除。

    Flink使用ROW_NUMBER()删除重复项,就像Top-N查询一样。 从理论上讲,重复数据删除是Top-N的一种特殊情况,其中N为1,并按处理时间或事件时间排序。

    下面显示了重复数据删除语句的语法:

    SELECT [column_list]
    FROM (
       SELECT [column_list],
         ROW_NUMBER() OVER ([PARTITION BY col1[, col2...]]
           ORDER BY time_attr [asc|desc]) AS rownum
       FROM table_name)
    WHERE rownum = 1

    参数含义: 

    • ROW_NUMBER(): 从每一行开始,为每一行分配一个唯一的顺序号.
    • PARTITION BY col1[, col2...]: 指定分区列,即重复数据删除键.
    • ORDER BY time_attr [asc|desc]: 指定排序列,它必须是时间属性。 当前仅支持proctime属性。 将来将支持行时间属性。 通过ASC排序意味着保留第一行,通过DESC排序意味着保留最后一行.
    • WHERE rownum = 1: Flink要求rownum = 1才能识别此查询是重复数据删除.

    以下示例说明如何在流表上指定带有重复数据删除功能的SQL查询。

    val env = StreamExecutionEnvironment.getExecutionEnvironment
    val tableEnv = TableEnvironment.getTableEnvironment(env)
    
    // read a DataStream from an external source
    val ds: DataStream[(String, String, String, Int)] = env.addSource(...)
    // register the DataStream under the name "Orders"
    tableEnv.registerDataStream("Orders", ds, 'order_id, 'user, 'product, 'number, 'proctime.proctime)
    
    // remove duplicate rows on order_id and keep the first occurrence row,
    // because there shouldn't be two orders with the same order_id.
    val result1 = tableEnv.sqlQuery(
        """
          |SELECT order_id, user, product, number
          |FROM (
          |   SELECT *,
          |       ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY proctime DESC) as row_num
          |   FROM Orders)
          |WHERE row_num = 1
        """.stripMargin)

    Insert

    OperationDescription
    Insert Into
    Batch Streaming

    输出表必须在TableEnvironment中注册(请参阅注册TableSink)。 此外,已注册表的结构必须与查询的结构匹配.

    INSERT INTO OutputTable
    SELECT users, tag
    FROM Orders

    Group Windows

     分组窗口在SQL查询的GROUP BY子句中定义。 就像带有常规GROUP BY子句的查询一样,带有GROUP BY子句(包括分组窗口函数)的查询每个组只计算一个结果行。 批处理表和流表上的SQL支持以下分组窗口功能。

    Group Window FunctionDescription
    TUMBLE(time_attr, interval)

    定义滚动时间窗口。 滚动时间窗口将行分配给具有固定持续时间(间隔)的非重叠连续窗口。 例如,5分钟的滚动窗口以5分钟为间隔对行进行分组。

    可以在事件时间(流+批处理)或处理时间(流)上定义滚动窗口。

    HOP(time_attr, interval, interval)

    定义一个跳跃时间窗口(在Table API中称为滑动窗口)。 跳跃时间窗口具有固定的持续时间(第二个间隔参数),并按指定的跳跃间隔(第一个间隔参数)跳跃。

    如果跳跃间隔小于窗口大小,则跳跃窗口重叠。 因此,可以将行分配给多个窗口。 例如,一个15分钟大小和5分钟跳跃间隔的跳窗将每行分配给3个15分钟大小的不同窗口,

    它们以5分钟的间隔进行评估。 可以在事件时间(流+批处理)或处理时间(流)上定义跳跃窗口。

    SESSION(time_attr, interval)

    定义会话时间窗口。 会话时间窗口没有固定的持续时间,但其边界由不活动的时间间隔定义,即,如果在定义的间隔时间段内未出现任何事件,则关闭会话窗口。

    例如,间隔30分钟的会话窗口在30分钟不活动后观察到一行时开始(否则该行将被添加到现有窗口),如果在30分钟内未添加任何行,则关闭该窗口。

    会话窗口可以在事件时间(流+批处理)或处理时间(流)上工作。

    时间属性

    对于流表上的SQL查询,分组窗口函数的time_attr参数必须引用一个有效的时间属性,该属性指定行的处理时间或事件时间。 请参阅时间属性文档以了解如何定义时间属性。

    对于批处理表上的SQL,分组窗口函数的time_attr参数必须是TIMESTAMP类型的属性。

     选择分组窗口开始和结束时间戳

    可以使用以下辅助功能选择组窗口的开始和结束时间戳以及时间属性:

    Auxiliary FunctionDescription
    TUMBLE_START(time_attr, interval)
    HOP_START(time_attr, interval, interval)
    SESSION_START(time_attr, interval)

    返回相应的滚动,跳动或会话窗口的包含下限的时间戳.

    TUMBLE_END(time_attr, interval)
    HOP_END(time_attr, interval, interval)
    SESSION_END(time_attr, interval)

    返回相应的滚动,跳跃或会话窗口的排他上限的时间戳.

    Note: 排他上限时间戳不能在随后的基于时间的操作(例如带时间窗扣的连接和分组窗口或窗口聚合中)中用作行时间属性。.

    TUMBLE_ROWTIME(time_attr, interval)
    HOP_ROWTIME(time_attr, interval, interval)
    SESSION_ROWTIME(time_attr, interval)

    返回相应的滚动,跳跃或会话窗口的包含上限的时间戳.

    结果属性是一个行时间属性,可以在随后的基于时间的操作(例如带时间窗口的连接和分组窗口或整个窗口聚合)中使用.

    TUMBLE_PROCTIME(time_attr, interval)
    HOP_PROCTIME(time_attr, interval, interval)
    SESSION_PROCTIME(time_attr, interval)

    返回一个proctime属性,该属性可以在随后的基于时间的操作(例如带时间窗口的连接和分组窗口或窗口聚合中)中使用.

     注意:必须使用与GROUP BY子句中的分组窗口函数完全相同的参数来调用辅助函数。

    以下示例说明如何在流表上使用分组窗口指定SQL查询。

    val env = StreamExecutionEnvironment.getExecutionEnvironment
    val tableEnv = StreamTableEnvironment.create(env)
    
    // read a DataStream from an external source
    val ds: DataStream[(Long, String, Int)] = env.addSource(...)
    // register the DataStream under the name "Orders"
    tableEnv.registerDataStream("Orders", ds, 'user, 'product, 'amount, 'proctime.proctime, 'rowtime.rowtime)
    
    // compute SUM(amount) per day (in event-time)
    val result1 = tableEnv.sqlQuery(
        """
          |SELECT
          |  user,
          |  TUMBLE_START(rowtime, INTERVAL '1' DAY) as wStart,
          |  SUM(amount)
          | FROM Orders
          | GROUP BY TUMBLE(rowtime, INTERVAL '1' DAY), user
        """.stripMargin)
    
    // compute SUM(amount) per day (in processing-time)
    val result2 = tableEnv.sqlQuery(
      "SELECT user, SUM(amount) FROM Orders GROUP BY TUMBLE(proctime, INTERVAL '1' DAY), user")
    
    // compute every hour the SUM(amount) of the last 24 hours in event-time
    val result3 = tableEnv.sqlQuery(
      "SELECT product, SUM(amount) FROM Orders GROUP BY HOP(rowtime, INTERVAL '1' HOUR, INTERVAL '1' DAY), product")
    
    // compute SUM(amount) per session with 12 hour inactivity gap (in event-time)
    val result4 = tableEnv.sqlQuery(
        """
          |SELECT
          |  user,
          |  SESSION_START(rowtime, INTERVAL '12' HOUR) AS sStart,
          |  SESSION_END(rowtime, INTERVAL '12' HOUR) AS sEnd,
          |  SUM(amount)
          | FROM Orders
          | GROUP BY SESSION(rowtime(), INTERVAL '12' HOUR), user
        """.stripMargin)

    Pattern Recognition

    OperationDescription
    MATCH_RECOGNIZE
    Streaming

    根据MATCH_RECOGNIZE ISO标准在流表中搜索给定的模式。 这样就可以在SQL查询中表达复杂的事件处理(CEP)逻辑.

    有关更详细的描述,请参见用于检测表中模式的专用页面.

    SELECT T.aid, T.bid, T.cid
    FROM MyTable
    MATCH_RECOGNIZE (
      PARTITION BY userid
      ORDER BY proctime
      MEASURES
        A.id AS aid,
        B.id AS bid,
        C.id AS cid
      PATTERN (A B C)
      DEFINE
        A AS name = 'a',
        B AS name = 'b',
        C AS name = 'c'
    ) AS T

    DDL

    DDL是通过TableEnvironment的sqlUpdate()方法指定的。 对于成功创建表,该方法不返回任何内容。 可以使用CREATE TABLE语句将表注册到目录中,然后可以在TableEnvironment的方法sqlQuery()中的SQL查询中引用表。

    注意:Flink的DDL支持尚未完成。 包含不受支持的SQL功能的查询会导致TableException。 以下各节列出了批处理表和流表上SQL DDL的受支持功能。

    指定DDL

    以下示例显示如何指定SQL DDL。

    val env = StreamExecutionEnvironment.getExecutionEnvironment
    val tableEnv = StreamTableEnvironment.create(env)
    
    // SQL query with a registered table
    // register a table named "Orders"
    tableEnv.sqlUpdate("CREATE TABLE Orders (`user` BIGINT, product VARCHAR, amount INT) WITH (...)");
    // run a SQL query on the Table and retrieve the result as a new Table
    val result = tableEnv.sqlQuery(
      "SELECT product, amount FROM Orders WHERE product LIKE '%Rubber%'");
    
    // SQL update with a registered table
    // register a TableSink
    tableEnv.sqlUpdate("CREATE TABLE RubberOrders(product VARCHAR, amount INT) WITH ('connector.path'='/path/to/file' ...)");
    // run a SQL update query on the Table and emit the result to the TableSink
    tableEnv.sqlUpdate(
      "INSERT INTO RubberOrders SELECT product, amount FROM Orders WHERE product LIKE '%Rubber%'")

    Create Table

    CREATE TABLE [catalog_name.][db_name.]table_name
      [(col_name1 col_type1 [COMMENT col_comment1], ...)]
      [COMMENT table_comment]
      [PARTITIONED BY (col_name1, col_name2, ...)]
      WITH (key1=val1, key2=val2, ...)

    创建具有给定表属性的表。 如果数据库中已经存在具有相同名称的表,则会引发异常。

    PARTITIONED BY

     按指定的列对创建的表进行分区。 如果将此表用作文件系统接收器,则会为每个分区创建一个目录。

    WITH OPTIONS

     用于创建表源/接收器的表属性。 这些属性通常用于查找和创建基础连接器。

    表达式key1 = val1的键和值都应为字符串文字。 有关不同连接器的所有受支持表属性,请参阅“连接到外部系统”中的详细信息。

    注意:表名可以采用三种格式:1. catalog_name.db_name.table_name 2. db_name.table_name 3. table_name。 对于catalog_name.db_name.table_name,该表将被注册到 catalog 名为“ catalog_name”和数据库名为“ db_name”的元存储中; 对于db_name.table_name,该表将被注册到执行表环境和名为“ db_name”的数据库的当前 catalog 中; 对于table_name,该表将被注册到执行表环境的当前 catalog 和数据库中。

    注意:用CREATE TABLE语句注册的表既可以用作表源,也可以用作表接收器,在DML中引用它之前,我们无法确定是将其用作源还是接收器。

    Drop Table 

    DROP TABLE [IF EXISTS] [catalog_name.][db_name.]table_name

    删除具有给定表名的表。 如果要删除的表不存在,则会引发异常。

    IF EXISTS

     如果该表不存在,则什么也不会发生。

    Data Types

     请参阅有关数据类型的专用页面。

    通用类型和(嵌套的)复合类型(例如POJO,元组,行,Scala案例类)也可以是一行的字段。

    可以使用值访问功能访问具有任意嵌套的复合类型的字段。

    泛型类型被视为黑盒,可以通过用户定义的函数传递或处理。

    对于DDL,我们支持在“数据类型”页面中定义的完整数据类型。

    注意:sql查询中不支持某些数据类型(强制转换表达式或文字)。 例如。 STRING,BYTES,不带时区的TIME(p),带本地时区的TIME(p),不带时区的TIMESTAMP(p),带本地时区的TIMESTAMP(p),数组,多集,行。

    保留关键字

    尽管尚未实现所有SQL功能,但某些字符串组合已作为关键字保留,以备将来使用。 如果您想使用以下字符串之一作为字段名称,请确保将其用反引号引起来(例如,“ value”,“ count”)。

    A, ABS, ABSOLUTE, ACTION, ADA, ADD, ADMIN, AFTER, ALL, ALLOCATE, ALLOW, ALTER, ALWAYS, AND, ANY, ARE, ARRAY, AS, ASC, ASENSITIVE, ASSERTION, ASSIGNMENT, ASYMMETRIC, AT, ATOMIC, ATTRIBUTE, ATTRIBUTES, AUTHORIZATION, AVG, BEFORE, BEGIN, BERNOULLI, BETWEEN, BIGINT, BINARY, BIT, BLOB, BOOLEAN, BOTH, BREADTH, BY, BYTES, C, CALL, CALLED, CARDINALITY, CASCADE, CASCADED, CASE, CAST, CATALOG, CATALOG_NAME, CEIL, CEILING, CENTURY, CHAIN, CHAR, CHARACTER, CHARACTERISTICS, CHARACTERS, CHARACTER_LENGTH, CHARACTER_SET_CATALOG, CHARACTER_SET_NAME, CHARACTER_SET_SCHEMA, CHAR_LENGTH, CHECK, CLASS_ORIGIN, CLOB, CLOSE, COALESCE, COBOL, COLLATE, COLLATION, COLLATION_CATALOG, COLLATION_NAME, COLLATION_SCHEMA, COLLECT, COLUMN, COLUMN_NAME, COMMAND_FUNCTION, COMMAND_FUNCTION_CODE, COMMIT, COMMITTED, CONDITION, CONDITION_NUMBER, CONNECT, CONNECTION, CONNECTION_NAME, CONSTRAINT, CONSTRAINTS, CONSTRAINT_CATALOG, CONSTRAINT_NAME, CONSTRAINT_SCHEMA, CONSTRUCTOR, CONTAINS, CONTINUE, CONVERT, CORR, CORRESPONDING, COUNT, COVAR_POP, COVAR_SAMP, CREATE, CROSS, CUBE, CUME_DIST, CURRENT, CURRENT_CATALOG, CURRENT_DATE, CURRENT_DEFAULT_TRANSFORM_GROUP, CURRENT_PATH, CURRENT_ROLE, CURRENT_SCHEMA, CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_TRANSFORM_GROUP_FOR_TYPE, CURRENT_USER, CURSOR, CURSOR_NAME, CYCLE, DATA, DATABASE, DATE, DATETIME_INTERVAL_CODE, DATETIME_INTERVAL_PRECISION, DAY, DEALLOCATE, DEC, DECADE, DECIMAL, DECLARE, DEFAULT, DEFAULTS, DEFERRABLE, DEFERRED, DEFINED, DEFINER, DEGREE, DELETE, DENSE_RANK, DEPTH, DEREF, DERIVED, DESC, DESCRIBE, DESCRIPTION, DESCRIPTOR, DETERMINISTIC, DIAGNOSTICS, DISALLOW, DISCONNECT, DISPATCH, DISTINCT, DOMAIN, DOUBLE, DOW, DOY, DROP, DYNAMIC, DYNAMIC_FUNCTION, DYNAMIC_FUNCTION_CODE, EACH, ELEMENT, ELSE, END, END-EXEC, EPOCH, EQUALS, ESCAPE, EVERY, EXCEPT, EXCEPTION, EXCLUDE, EXCLUDING, EXEC, EXECUTE, EXISTS, EXP, EXPLAIN, EXTEND, EXTERNAL, EXTRACT, FALSE, FETCH, FILTER, FINAL, FIRST, FIRST_VALUE, FLOAT, FLOOR, FOLLOWING, FOR, FOREIGN, FORTRAN, FOUND, FRAC_SECOND, FREE, FROM, FULL, FUNCTION, FUSION, G, GENERAL, GENERATED, GET, GLOBAL, GO, GOTO, GRANT, GRANTED, GROUP, GROUPING, HAVING, HIERARCHY, HOLD, HOUR, IDENTITY, IMMEDIATE, IMPLEMENTATION, IMPORT, IN, INCLUDING, INCREMENT, INDICATOR, INITIALLY, INNER, INOUT, INPUT, INSENSITIVE, INSERT, INSTANCE, INSTANTIABLE, INT, INTEGER, INTERSECT, INTERSECTION, INTERVAL, INTO, INVOKER, IS, ISOLATION, JAVA, JOIN, K, KEY, KEY_MEMBER, KEY_TYPE, LABEL, LANGUAGE, LARGE, LAST, LAST_VALUE, LATERAL, LEADING, LEFT, LENGTH, LEVEL, LIBRARY, LIKE, LIMIT, LN, LOCAL, LOCALTIME, LOCALTIMESTAMP, LOCATOR, LOWER, M, MAP, MATCH, MATCHED, MAX, MAXVALUE, MEMBER, MERGE, MESSAGE_LENGTH, MESSAGE_OCTET_LENGTH, MESSAGE_TEXT, METHOD, MICROSECOND, MILLENNIUM, MIN, MINUTE, MINVALUE, MOD, MODIFIES, MODULE, MONTH, MORE, MULTISET, MUMPS, NAME, NAMES, NATIONAL, NATURAL, NCHAR, NCLOB, NESTING, NEW, NEXT, NO, NONE, NORMALIZE, NORMALIZED, NOT, NULL, NULLABLE, NULLIF, NULLS, NUMBER, NUMERIC, OBJECT, OCTETS, OCTET_LENGTH, OF, OFFSET, OLD, ON, ONLY, OPEN, OPTION, OPTIONS, OR, ORDER, ORDERING, ORDINALITY, OTHERS, OUT, OUTER, OUTPUT, OVER, OVERLAPS, OVERLAY, OVERRIDING, PAD, PARAMETER, PARAMETER_MODE, PARAMETER_NAME, PARAMETER_ORDINAL_POSITION, PARAMETER_SPECIFIC_CATALOG, PARAMETER_SPECIFIC_NAME, PARAMETER_SPECIFIC_SCHEMA, PARTIAL, PARTITION, PASCAL, PASSTHROUGH, PATH, PERCENTILE_CONT, PERCENTILE_DISC, PERCENT_RANK, PLACING, PLAN, PLI, POSITION, POWER, PRECEDING, PRECISION, PREPARE, PRESERVE, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE, PUBLIC, QUARTER, RANGE, RANK, READ, READS, REAL, RECURSIVE, REF, REFERENCES, REFERENCING, REGR_AVGX, REGR_AVGY, REGR_COUNT, REGR_INTERCEPT, REGR_R2, REGR_SLOPE, REGR_SXX, REGR_SXY, REGR_SYY, RELATIVE, RELEASE, REPEATABLE, RESET, RESTART, RESTRICT, RESULT, RETURN, RETURNED_CARDINALITY, RETURNED_LENGTH, RETURNED_OCTET_LENGTH, RETURNED_SQLSTATE, RETURNS, REVOKE, RIGHT, ROLE, ROLLBACK, ROLLUP, ROUTINE, ROUTINE_CATALOG, ROUTINE_NAME, ROUTINE_SCHEMA, ROW, ROWS, ROW_COUNT, ROW_NUMBER, SAVEPOINT, SCALE, SCHEMA, SCHEMA_NAME, SCOPE, SCOPE_CATALOGS, SCOPE_NAME, SCOPE_SCHEMA, SCROLL, SEARCH, SECOND, SECTION, SECURITY, SELECT, SELF, SENSITIVE, SEQUENCE, SERIALIZABLE, SERVER, SERVER_NAME, SESSION, SESSION_USER, SET, SETS, SIMILAR, SIMPLE, SIZE, SMALLINT, SOME, SOURCE, SPACE, SPECIFIC, SPECIFICTYPE, SPECIFIC_NAME, SQL, SQLEXCEPTION, SQLSTATE, SQLWARNING, SQL_TSI_DAY, SQL_TSI_FRAC_SECOND, SQL_TSI_HOUR, SQL_TSI_MICROSECOND, SQL_TSI_MINUTE, SQL_TSI_MONTH, SQL_TSI_QUARTER, SQL_TSI_SECOND, SQL_TSI_WEEK, SQL_TSI_YEAR, SQRT, START, STATE, STATEMENT, STATIC, STDDEV_POP, STDDEV_SAMP, STREAM, STRING, STRUCTURE, STYLE, SUBCLASS_ORIGIN, SUBMULTISET, SUBSTITUTE, SUBSTRING, SUM, SYMMETRIC, SYSTEM, SYSTEM_USER, TABLE, TABLESAMPLE, TABLE_NAME, TEMPORARY, THEN, TIES, TIME, TIMESTAMP, TIMESTAMPADD, TIMESTAMPDIFF, TIMEZONE_HOUR, TIMEZONE_MINUTE, TINYINT, TO, TOP_LEVEL_COUNT, TRAILING, TRANSACTION, TRANSACTIONS_ACTIVE, TRANSACTIONS_COMMITTED, TRANSACTIONS_ROLLED_BACK, TRANSFORM, TRANSFORMS, TRANSLATE, TRANSLATION, TREAT, TRIGGER, TRIGGER_CATALOG, TRIGGER_NAME, TRIGGER_SCHEMA, TRIM, TRUE, TYPE, UESCAPE, UNBOUNDED, UNCOMMITTED, UNDER, UNION, UNIQUE, UNKNOWN, UNNAMED, UNNEST, UPDATE, UPPER, UPSERT, USAGE, USER, USER_DEFINED_TYPE_CATALOG, USER_DEFINED_TYPE_CODE, USER_DEFINED_TYPE_NAME, USER_DEFINED_TYPE_SCHEMA, USING, VALUE, VALUES, VARBINARY, VARCHAR, VARYING, VAR_POP, VAR_SAMP, VERSION, VIEW, WEEK, WHEN, WHENEVER, WHERE, WIDTH_BUCKET, WINDOW, WITH, WITHIN, WITHOUT, WORK, WRAPPER, WRITE, XML, YEAR, ZONE

    欢迎关注Flink菜鸟公众号,会不定期更新Flink(开发技术)相关的推文

  • 相关阅读:
    leetcode131分割回文串
    leetcode315 计算右侧小于当前元素的个数
    Tensorflow写代码流程&反向传播
    vue脚手架的搭建
    Vue 脱坑记
    简历中的工作经历要怎么写?
    如何制作高水平简历?
    window.location.hash的知识点
    前端面试题小集
    前端面试题
  • 原文地址:https://www.cnblogs.com/Springmoon-venn/p/11888724.html
Copyright © 2020-2023  润新知