class_docstr: Visits the SQL query plan to simplify sub-queries. On each visit, return a simplfied node.
class_docstr_tok: ["Visits","the","SQL","query","plan","to","simplify","sub-queries",".","On","each","visit",",","return","a","simplfied","node","."]
docstr: Returns true if the given node can be reduced with the parent node.
  
  Reducing this node means eliminating the SELECT of this node and merging it with the parent SELECT. This
  checks for obvious cases where reducing can't happen, but there are cases where reducing is possible, but this
  returns false for ease of reasoning.
docstr_tok: ["Returns","true","if","the","given","node","can","be","reduced","with","the","parent","node",".","Reducing","this","node","means","eliminating","the","SELECT","of","this","node","and","merging","it","with","the","parent","SELECT",".","This","checks","for","obvious","cases","where","reducing","ca","n't","happen",",","but","there","are","cases","where","reducing","is","possible",",","but","this","returns","false","for","ease","of","reasoning","."]
code: def _reduce_is_possible(
      self, node: SqlSelectStatementNode
  ) -> bool:  # noqa: D
      """Returns true if the given node can be reduced with the parent node.
  
      Reducing this node means eliminating the SELECT of this node and merging it with the parent SELECT. This
      checks for obvious cases where reducing can't happen, but there are cases where reducing is possible, but this
      returns false for ease of reasoning.
      """
      # If this node has multiple parents (i.e. a join), then this can't be collapsed.
      is_join = len(node.join_descs) > 0
      has_multiple_parent_nodes = len(node.parent_nodes) > 1
      if has_multiple_parent_nodes or is_join:
          return False
  
      assert len(node.parent_nodes) == 1
      parent_node = node.parent_nodes[0]
  
      # If the parent node is not a select statement, then this can't be collapsed. e.g. with a table as a parent like
      # SELECT foo FROM bar
      if not parent_node.as_select_node:
          return False
      parent_select_node = parent_node.as_select_node
  
      # More conditions where we don't want to collapse. It's not impossible with these cases, but not reducing in
      # these cases for simplicity.
  
      # Don't reduce distinct selects
      if parent_select_node.distinct:
          return False
  
      # Reducing a where is tricky as it requires the expressions to be re-written.
      if node.where:
          return False
  
      # Group bys are hard to reduce.
      if len(node.group_bys) > 0:
          return False
  
      # Similar with order bys.
      if (
          len(node.order_bys) > 0
          and len(parent_select_node.order_bys) > 0
      ):
          return False
  
      # Can't reduce if the sub-query selects more columns. This generally won't be hit as long as the column pruner
      # runs before this optimization.
      if len(parent_select_node.select_columns) > len(
          node.select_columns
      ):
          return False
  
      # For now, simplify only in cases where the select expressions directly reference columns in the parent query
      # and the alias is the same as the column reference. This means that the column references don't have to be
      # re-written when this is collapsed into the parent subquery.
      for select_column in node.select_columns:
          if not select_column.expr.as_column_reference_expression:
              return False
          column_reference_expression = (
              select_column.expr.as_column_reference_expression
          )
          assert column_reference_expression
          if (
              column_reference_expression.col_ref.column_name
              != select_column.column_alias
          ):
              return False
  
      # Same thing with order by
      for order_by in node.order_bys:
          if not order_by.expr.as_column_reference_expression:
              return False
  
      return True
  
file_path: metricflow/metricflow/sql/optimizer/sub_query_reducer.py
imports: from __future__ import annotations
  import logging
  from typing import List, Optional
  from metricflow.sql.optimizer.sql_query_plan_optimizer import SqlQueryPlanOptimizer
  from metricflow.sql.sql_exprs import SqlColumnReference, SqlColumnReferenceExpression
  from metricflow.sql.sql_plan import SqlJoinDescription, SqlOrderByDescription, SqlQueryPlanNode, SqlQueryPlanNodeVisitor, SqlSelectQueryFromClauseNode, SqlSelectStatementNode, SqlTableFromClauseNode
label_desc: Use image node_id 2 for calling the SqlSubQueryReducerVisitor obj's underlying member method code with example usage: obj._reduce_is_possible(node) and returns: True, False, False, False, False, False, False, False, False, False, False