Repository: reata/sqllineage

Issue:
Inconsistent order of lineage tuples
Hi, first of all thanks for this amazing library!

I came across an edge cases I wanted to highlight. The below example inconsistently fails or passes because the column lineages are ordered differently.

**To Reproduce**
```python
import pytest

from sqllineage.core.metadata_provider import MetaDataProvider
from sqllineage.utils.entities import ColumnQualifierTuple
from ...helpers import assert_column_lineage_equal, generate_metadata_providers


providers = generate_metadata_providers(
    {
        "database_a.table_a": ["col_a", "col_b", "col_c"],
    }
)


@pytest.mark.parametrize("provider", providers)
def test_ouput_consistency(provider: MetaDataProvider):
    sql = """CREATE TABLE database_b.table_c
    AS (
      SELECT
        *,
        1 AS event_time
      FROM (
        SELECT
          table_b.col_b AS col_a
        FROM database_b.table_b AS table_b
        JOIN database_a.table_a AS table_d
      ) AS base
    )
    """
    assert_column_lineage_equal(
        sql,
        [
            (
                ColumnQualifierTuple("col_b", "database_a.table_a"),
                ColumnQualifierTuple("col_b", "database_b.table_c"),
            ),
            (
                ColumnQualifierTuple("col_c", "database_a.table_a"),
                ColumnQualifierTuple("col_c", "database_b.table_c"),
            ),
            (
                ColumnQualifierTuple("col_b", "database_b.table_b"),
                ColumnQualifierTuple("col_a", "database_b.table_c"),
            ),
        ],
        dialect="athena",
        test_sqlparse=False,
        test_sqlfluff=True,
        metadata_provider=provider,
    )
```

Sometimes the pytest fails with below:
```
E       	Expected Lineage: {(Column: database_b.table_b.col_b, Column: database_b.table_c.col_a), (Column: database_a.table_a.col_b, Column: database_b.table_c.col_b), (Column: database_a.table_a.col_c, Column: database_b.table_c.col_c)}
E       	Actual Lineage: {(Column: database_a.table_a.col_a, Column: database_b.table_c.col_a), (Column: database_a.table_a.col_b, Column: database_b.table_c.col_b), (Column: database_a.table_a.col_c, Column: database_b.table_c.col_c)}
```
Sometimes with this:
```
E       	Expected Lineage: {(Column: database_a.table_a.col_c, Column: database_b.table_c.col_c), (Column: database_b.table_b.col_b, Column: database_b.table_c.col_a), (Column: database_a.table_a.col_b, Column: database_b.table_c.col_b)}
E       	Actual Lineage: {(Column: database_a.table_a.col_a, Column: database_b.table_c.col_a), (Column: database_a.table_a.col_c, Column: database_b.table_c.col_c), (Column: database_a.table_a.col_b, Column: database_b.table_c.col_b)}
```
And sometimes it actually succeeds.


**Expected behavior**
I would expect the column lineages to be consistent in the results. 

If I understand the codebase right, it's because the results are only ordered based on first and last lineage element, not the whole lineage: https://github.com/reata/sqllineage/blob/6189d312b3f53d4302bb951a3297a06321a53a2d/sqllineage/runner.py#L154-L167

Something like the below would take the whole lineage into account for ordering:
```python
key=lambda x: "".join([str(i) for i in reversed(x)])
```


Discussion:

Patch:
diff --git a/sqllineage/core/parser/sqlfluff/utils.py b/sqllineage/core/parser/sqlfluff/utils.py
index 6d841c4c..62decf30 100644
--- a/sqllineage/core/parser/sqlfluff/utils.py
+++ b/sqllineage/core/parser/sqlfluff/utils.py
@@ -87,6 +87,18 @@ def list_join_clause(segment: BaseSegment) -> List[BaseSegment]:
     traverse from_clause, recursively goes into bracket by default
     """
     if segment.type in ["from_clause", "update_statement"]:
+        # for select from subquery, do not recursively go into subquery
+        if from_expression := segment.get_child("from_expression"):
+            join_clause = from_expression.get_child("join_clause")
+            if not join_clause:
+                try:
+                    next(from_expression.recursive_crawl("select_clause"))
+                except StopIteration:
+                    pass
+                else:
+                    # no join at top level, and there is select statement in from_clause
+                    return []
+        # otherwise, recursively find join_clause
         return list(segment.recursive_crawl("join_clause"))
     return []
 


Test patch:
diff --git a/tests/sql/column/test_metadata_wildcard.py b/tests/sql/column/test_metadata_wildcard.py
index 2d6c71ad..81fa8573 100644
--- a/tests/sql/column/test_metadata_wildcard.py
+++ b/tests/sql/column/test_metadata_wildcard.py
@@ -336,3 +336,21 @@ def test_wildcard_reference_from_previous_statements(provider: MetaDataProvider)
         ],
         metadata_provider=provider,
     )
+
+
+def test_output_consistency():
+    sql = """INSERT INTO tab_c
+SELECT *,
+       1 AS event_time
+FROM (SELECT tab_b.col_b AS col_a
+      FROM tab_b
+               JOIN tab_a) AS base"""
+    assert_column_lineage_equal(
+        sql,
+        [
+            (
+                ColumnQualifierTuple("col_b", "tab_b"),
+                ColumnQualifierTuple("col_a", "tab_c"),
+            ),
+        ],
+    )