You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by ch...@apache.org on 2024/10/18 10:32:48 UTC

(shardingsphere) branch master updated: Use Multimap and CaseInsensitiveString to replace CaseInsensitiveMap for supporting mysql multi table join with same table alias (#33303)

This is an automated email from the ASF dual-hosted git repository.

chengzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 044e049054b Use Multimap and CaseInsensitiveString to replace CaseInsensitiveMap for supporting mysql multi table join with same table alias (#33303)
044e049054b is described below

commit 044e049054b35d1292155c13f1a07cccc788a4a4
Author: Zhengqiang Duan <du...@apache.org>
AuthorDate: Fri Oct 18 18:32:41 2024 +0800

    Use Multimap and CaseInsensitiveString to replace CaseInsensitiveMap for supporting mysql multi table join with same table alias (#33303)
    
    * Use Multimap and CaseInsensitiveString to replace CaseInsensitiveMap for supporting mysql multi table join with same table alias
    
    * remove toLowerCase call
    
    * Add more unit test for ColumnSegmentBinderTest
    
    * Update release note
---
 RELEASE-NOTES.md                                   |  1 +
 .../segment/assign/AssignmentSegmentBinder.java    | 10 ++--
 .../segment/column/InsertColumnsSegmentBinder.java | 10 ++--
 .../expression/ExpressionSegmentBinder.java        | 11 ++--
 .../type/BinaryOperationExpressionBinder.java      |  7 ++-
 .../expression/type/ColumnSegmentBinder.java       | 53 +++++++++--------
 .../type/ExistsSubqueryExpressionBinder.java       |  6 +-
 .../type/FunctionExpressionSegmentBinder.java      |  6 +-
 .../expression/type/InExpressionBinder.java        |  7 ++-
 .../expression/type/NotExpressionBinder.java       | 10 ++--
 .../expression/type/SubquerySegmentBinder.java     |  7 ++-
 .../engine/segment/from/TableSegmentBinder.java    | 14 +++--
 .../from/type/DeleteMultiTableSegmentBinder.java   | 10 ++--
 .../segment/from/type/JoinTableSegmentBinder.java  | 51 +++++++++--------
 .../from/type/SimpleTableSegmentBinder.java        | 12 ++--
 .../from/type/SubqueryTableSegmentBinder.java      | 11 ++--
 .../engine/segment/lock/LockSegmentBinder.java     |  6 +-
 .../projection/ProjectionsSegmentBinder.java       | 17 +++---
 .../type/ColumnProjectionSegmentBinder.java        | 10 ++--
 .../type/ShorthandProjectionSegmentBinder.java     | 14 +++--
 .../type/SubqueryProjectionSegmentBinder.java      |  6 +-
 .../engine/segment/where/WhereSegmentBinder.java   |  7 ++-
 .../statement/SQLStatementBinderContext.java       | 15 ++---
 .../statement/dml/DeleteStatementBinder.java       | 13 ++---
 .../statement/dml/InsertStatementBinder.java       |  7 ++-
 .../statement/dml/SelectStatementBinder.java       | 12 ++--
 .../statement/dml/UpdateStatementBinder.java       | 17 +++---
 .../assign/AssignmentSegmentBinderTest.java        | 10 ++--
 .../type/BinaryOperationExpressionBinderTest.java  |  7 +--
 .../expression/type/ColumnSegmentBinderTest.java   | 66 ++++++++++++++++++----
 .../type/ExistsSubqueryExpressionBinderTest.java   |  3 +-
 .../type/FunctionExpressionSegmentBinderTest.java  |  3 +-
 .../expression/type/InExpressionBinderTest.java    |  5 +-
 .../expression/type/NotExpressionBinderTest.java   |  5 +-
 .../expression/type/SubquerySegmentBinderTest.java | 10 ++--
 .../from/type/JoinTableSegmentBinderTest.java      | 47 +++++++--------
 .../from/type/SimpleTableSegmentBinderTest.java    |  7 ++-
 .../from/type/SubqueryTableSegmentBinderTest.java  | 27 ++++-----
 .../type/ShorthandProjectionSegmentBinderTest.java | 22 +++++---
 .../segment/where/WhereSegmentBinderTest.java      | 10 ++--
 40 files changed, 331 insertions(+), 241 deletions(-)

diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index f92f04a7c65..028b2d01e87 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -11,6 +11,7 @@
 ### Bug Fix
 
 1. Mode: Fixes `JDBCRepository` improper handling of H2database in memory mode - [#33281](https://github.com/apache/shardingsphere/issues/33281)
+1. SQL Binder: Use Multimap and CaseInsensitiveString to replace CaseInsensitiveMap for supporting mysql multi table join with same table alias - [#33303](https://github.com/apache/shardingsphere/pull/33303)
 
 ### Change Log
 1. [MILESTONE](https://github.com/apache/shardingsphere/milestone/30)
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/assign/AssignmentSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/assign/AssignmentSegmentBinder.java
index 26b129bb909..2d47f9c66be 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/assign/AssignmentSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/assign/AssignmentSegmentBinder.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.assign;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
@@ -30,7 +32,6 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.Co
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
 
 import java.util.List;
-import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -49,14 +50,15 @@ public final class AssignmentSegmentBinder {
      * @return bound assignment segment
      */
     public static SetAssignmentSegment bind(final SetAssignmentSegment segment, final SQLStatementBinderContext binderContext,
-                                            final Map<String, TableSegmentBinderContext> tableBinderContexts, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                            final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                            final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         return new SetAssignmentSegment(segment.getStartIndex(), segment.getStopIndex(), segment.getAssignments().stream()
                 .map(each -> bindColumnAssignmentSegment(each, binderContext, tableBinderContexts, outerTableBinderContexts)).collect(Collectors.toList()));
     }
     
     private static ColumnAssignmentSegment bindColumnAssignmentSegment(final ColumnAssignmentSegment columnAssignmentSegment, final SQLStatementBinderContext binderContext,
-                                                                       final Map<String, TableSegmentBinderContext> tableBinderContexts,
-                                                                       final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                                                       final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                                                       final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         List<ColumnSegment> boundColumns = columnAssignmentSegment.getColumns().stream()
                 .map(each -> ColumnSegmentBinder.bind(each, SegmentType.SET_ASSIGNMENT, binderContext, tableBinderContexts, outerTableBinderContexts)).collect(Collectors.toList());
         ExpressionSegment boundValue = ExpressionSegmentBinder.bind(columnAssignmentSegment.getValue(), SegmentType.SET_ASSIGNMENT, binderContext, tableBinderContexts, outerTableBinderContexts);
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/column/InsertColumnsSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/column/InsertColumnsSegmentBinder.java
index 1ac6aff5219..5f02778d073 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/column/InsertColumnsSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/column/InsertColumnsSegmentBinder.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.column;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
@@ -27,8 +30,6 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.Co
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.InsertColumnsSegment;
 
 import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -45,9 +46,10 @@ public final class InsertColumnsSegmentBinder {
      * @param tableBinderContexts table binder contexts
      * @return bound insert columns segment
      */
-    public static InsertColumnsSegment bind(final InsertColumnsSegment segment, final SQLStatementBinderContext binderContext, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+    public static InsertColumnsSegment bind(final InsertColumnsSegment segment, final SQLStatementBinderContext binderContext,
+                                            final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
         Collection<ColumnSegment> boundColumns = segment.getColumns().stream()
-                .map(each -> ColumnSegmentBinder.bind(each, SegmentType.INSERT_COLUMNS, binderContext, tableBinderContexts, Collections.emptyMap())).collect(Collectors.toList());
+                .map(each -> ColumnSegmentBinder.bind(each, SegmentType.INSERT_COLUMNS, binderContext, tableBinderContexts, LinkedHashMultimap.create())).collect(Collectors.toList());
         return new InsertColumnsSegment(segment.getStartIndex(), segment.getStopIndex(), boundColumns);
     }
 }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/ExpressionSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/ExpressionSegmentBinder.java
index 0cb80277d7d..5adaf40ff5d 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/ExpressionSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/ExpressionSegmentBinder.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
@@ -38,9 +41,6 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.InEx
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.NotExpression;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubqueryExpressionSegment;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
-
 /**
  * Expression segment binder.
  */
@@ -58,7 +58,8 @@ public final class ExpressionSegmentBinder {
      * @return bound expression segment
      */
     public static ExpressionSegment bind(final ExpressionSegment segment, final SegmentType parentSegmentType, final SQLStatementBinderContext binderContext,
-                                         final Map<String, TableSegmentBinderContext> tableBinderContexts, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                         final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                         final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         if (segment instanceof BinaryOperationExpression) {
             return BinaryOperationExpressionBinder.bind((BinaryOperationExpression) segment, parentSegmentType, binderContext, tableBinderContexts, outerTableBinderContexts);
         }
@@ -66,7 +67,7 @@ public final class ExpressionSegmentBinder {
             return ExistsSubqueryExpressionBinder.bind((ExistsSubqueryExpression) segment, binderContext, tableBinderContexts);
         }
         if (segment instanceof SubqueryExpressionSegment) {
-            Map<String, TableSegmentBinderContext> newOuterTableBinderContexts = new LinkedHashMap<>();
+            Multimap<CaseInsensitiveString, TableSegmentBinderContext> newOuterTableBinderContexts = LinkedHashMultimap.create();
             newOuterTableBinderContexts.putAll(outerTableBinderContexts);
             newOuterTableBinderContexts.putAll(tableBinderContexts);
             return new SubqueryExpressionSegment(SubquerySegmentBinder.bind(((SubqueryExpressionSegment) segment).getSubquery(), binderContext, newOuterTableBinderContexts));
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/BinaryOperationExpressionBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/BinaryOperationExpressionBinder.java
index 3add920b694..43cb19973c0 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/BinaryOperationExpressionBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/BinaryOperationExpressionBinder.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
@@ -26,8 +28,6 @@ import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinde
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
 
-import java.util.Map;
-
 /**
  * Binary operation expression binder.
  */
@@ -45,7 +45,8 @@ public final class BinaryOperationExpressionBinder {
      * @return bound binary operation expression segment
      */
     public static BinaryOperationExpression bind(final BinaryOperationExpression segment, final SegmentType parentSegmentType, final SQLStatementBinderContext binderContext,
-                                                 final Map<String, TableSegmentBinderContext> tableBinderContexts, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                                 final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                                 final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         ExpressionSegment boundLeft = ExpressionSegmentBinder.bind(segment.getLeft(), parentSegmentType, binderContext, tableBinderContexts, outerTableBinderContexts);
         ExpressionSegment boundRight = ExpressionSegmentBinder.bind(segment.getRight(), parentSegmentType, binderContext, tableBinderContexts, outerTableBinderContexts);
         return new BinaryOperationExpression(segment.getStartIndex(), segment.getStopIndex(), boundLeft, boundRight, segment.getOperator(), segment.getText());
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinder.java
index 527957067bf..ca8f52b8572 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinder.java
@@ -17,7 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
 import com.google.common.base.Strings;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.groovy.util.Maps;
@@ -71,7 +73,8 @@ public final class ColumnSegmentBinder {
      * @return bound column segment
      */
     public static ColumnSegment bind(final ColumnSegment segment, final SegmentType parentSegmentType, final SQLStatementBinderContext binderContext,
-                                     final Map<String, TableSegmentBinderContext> tableBinderContexts, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                     final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                     final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         if (EXCLUDE_BIND_COLUMNS.contains(segment.getIdentifier().getValue().toUpperCase())) {
             return segment;
         }
@@ -93,12 +96,11 @@ public final class ColumnSegmentBinder {
     
     private static Collection<TableSegmentBinderContext> getTableSegmentBinderContexts(final ColumnSegment segment, final SegmentType parentSegmentType,
                                                                                        final SQLStatementBinderContext binderContext,
-                                                                                       final Map<String, TableSegmentBinderContext> tableBinderContexts,
-                                                                                       final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                                                                       final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                                                                       final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         if (segment.getOwner().isPresent()) {
-            String owner = segment.getOwner().get().getIdentifier().getValue().toLowerCase();
-            return findTableBinderContextByOwner(owner, tableBinderContexts, outerTableBinderContexts, binderContext.getExternalTableBinderContexts())
-                    .map(Collections::singletonList).orElse(Collections.emptyList());
+            String owner = segment.getOwner().get().getIdentifier().getValue();
+            return getTableBinderContextByOwner(owner, tableBinderContexts, outerTableBinderContexts, binderContext.getExternalTableBinderContexts());
         }
         if (!binderContext.getJoinTableProjectionSegments().isEmpty() && isNeedUseJoinTableProjectionBind(segment, parentSegmentType, binderContext)) {
             return Collections.singleton(new SimpleTableSegmentBinderContext(binderContext.getJoinTableProjectionSegments()));
@@ -106,28 +108,30 @@ public final class ColumnSegmentBinder {
         return tableBinderContexts.values();
     }
     
-    private static Optional<TableSegmentBinderContext> findTableBinderContextByOwner(final String owner, final Map<String, TableSegmentBinderContext> tableBinderContexts,
-                                                                                     final Map<String, TableSegmentBinderContext> outerTableBinderContexts,
-                                                                                     final Map<String, TableSegmentBinderContext> externalTableBinderContexts) {
-        if (tableBinderContexts.containsKey(owner)) {
-            return Optional.of(tableBinderContexts.get(owner));
+    private static Collection<TableSegmentBinderContext> getTableBinderContextByOwner(final String owner, final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                                                                      final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts,
+                                                                                      final Multimap<CaseInsensitiveString, TableSegmentBinderContext> externalTableBinderContexts) {
+        CaseInsensitiveString caseInsensitiveOwner = new CaseInsensitiveString(owner);
+        if (tableBinderContexts.containsKey(caseInsensitiveOwner)) {
+            return tableBinderContexts.get(caseInsensitiveOwner);
         }
-        if (outerTableBinderContexts.containsKey(owner)) {
-            return Optional.of(outerTableBinderContexts.get(owner));
+        if (outerTableBinderContexts.containsKey(caseInsensitiveOwner)) {
+            return outerTableBinderContexts.get(caseInsensitiveOwner);
         }
-        if (externalTableBinderContexts.containsKey(owner)) {
-            return Optional.of(externalTableBinderContexts.get(owner));
+        if (externalTableBinderContexts.containsKey(caseInsensitiveOwner)) {
+            return externalTableBinderContexts.get(caseInsensitiveOwner);
         }
-        return Optional.empty();
+        return Collections.emptyList();
     }
     
     private static boolean isNeedUseJoinTableProjectionBind(final ColumnSegment segment, final SegmentType parentSegmentType, final SQLStatementBinderContext binderContext) {
         return SegmentType.PROJECTION == parentSegmentType
-                || SegmentType.PREDICATE == parentSegmentType && binderContext.getUsingColumnNames().contains(segment.getIdentifier().getValue().toLowerCase());
+                || SegmentType.PREDICATE == parentSegmentType && binderContext.getUsingColumnNames().contains(segment.getIdentifier().getValue());
     }
     
     private static Optional<ColumnSegment> findInputColumnSegment(final ColumnSegment segment, final SegmentType parentSegmentType, final Collection<TableSegmentBinderContext> tableBinderContexts,
-                                                                  final Map<String, TableSegmentBinderContext> outerTableBinderContexts, final SQLStatementBinderContext binderContext) {
+                                                                  final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts,
+                                                                  final SQLStatementBinderContext binderContext) {
         ColumnSegment result = null;
         boolean isFindInputColumn = false;
         for (TableSegmentBinderContext each : tableBinderContexts) {
@@ -172,13 +176,14 @@ public final class ColumnSegmentBinder {
         if (pivotColumnNames.isEmpty()) {
             return Optional.empty();
         }
-        if (pivotColumnNames.contains(segment.getIdentifier().getValue().toLowerCase())) {
+        if (pivotColumnNames.contains(segment.getIdentifier().getValue())) {
             return Optional.of(new ColumnSegment(0, 0, segment.getIdentifier()));
         }
         return Optional.empty();
     }
     
-    private static Optional<ProjectionSegment> findInputColumnSegmentFromOuterTable(final ColumnSegment segment, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+    private static Optional<ProjectionSegment> findInputColumnSegmentFromOuterTable(final ColumnSegment segment,
+                                                                                    final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         ListIterator<TableSegmentBinderContext> listIterator = new ArrayList<>(outerTableBinderContexts.values()).listIterator(outerTableBinderContexts.size());
         while (listIterator.hasPrevious()) {
             TableSegmentBinderContext each = listIterator.previous();
@@ -190,7 +195,8 @@ public final class ColumnSegmentBinder {
         return Optional.empty();
     }
     
-    private static Optional<ProjectionSegment> findInputColumnSegmentFromExternalTables(final ColumnSegment segment, final Map<String, TableSegmentBinderContext> externalTableBinderContexts) {
+    private static Optional<ProjectionSegment> findInputColumnSegmentFromExternalTables(final ColumnSegment segment,
+                                                                                        final Multimap<CaseInsensitiveString, TableSegmentBinderContext> externalTableBinderContexts) {
         for (TableSegmentBinderContext each : externalTableBinderContexts.values()) {
             Optional<ProjectionSegment> result = each.findProjectionSegmentByColumnLabel(segment.getIdentifier().getValue());
             if (result.isPresent()) {
@@ -204,7 +210,7 @@ public final class ColumnSegmentBinder {
         if (variableNames.isEmpty()) {
             return Optional.empty();
         }
-        if (variableNames.contains(segment.getIdentifier().getValue().toLowerCase())) {
+        if (variableNames.contains(segment.getIdentifier().getValue())) {
             ColumnSegment result = new ColumnSegment(0, 0, segment.getIdentifier());
             result.setVariable(true);
             return Optional.of(result);
@@ -246,7 +252,8 @@ public final class ColumnSegmentBinder {
      * @param tableBinderContexts table binder contexts
      * @return bound using column segment
      */
-    public static ColumnSegment bindUsingColumn(final ColumnSegment segment, final SegmentType parentSegmentType, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+    public static ColumnSegment bindUsingColumn(final ColumnSegment segment, final SegmentType parentSegmentType,
+                                                final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
         ColumnSegment result = copy(segment);
         List<ColumnSegment> usingInputColumnSegments = findUsingInputColumnSegments(segment.getIdentifier().getValue(), tableBinderContexts.values());
         ShardingSpherePreconditions.checkState(usingInputColumnSegments.size() >= 2,
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ExistsSubqueryExpressionBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ExistsSubqueryExpressionBinder.java
index 9630e72e03c..70026051bcc 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ExistsSubqueryExpressionBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ExistsSubqueryExpressionBinder.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
@@ -24,8 +26,6 @@ import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinde
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExistsSubqueryExpression;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
 
-import java.util.Map;
-
 /**
  * Exists subquery expression binder.
  */
@@ -41,7 +41,7 @@ public final class ExistsSubqueryExpressionBinder {
      * @return bound exists subquery expression segment
      */
     public static ExistsSubqueryExpression bind(final ExistsSubqueryExpression segment, final SQLStatementBinderContext binderContext,
-                                                final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+                                                final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
         SubquerySegment boundSubquery = SubquerySegmentBinder.bind(segment.getSubquery(), binderContext, tableBinderContexts);
         ExistsSubqueryExpression result = new ExistsSubqueryExpression(segment.getStartIndex(), segment.getStopIndex(), boundSubquery);
         result.setNot(segment.isNot());
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/FunctionExpressionSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/FunctionExpressionSegmentBinder.java
index 3db6db5b4b6..a169c4b5e9e 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/FunctionExpressionSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/FunctionExpressionSegmentBinder.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
@@ -25,7 +27,6 @@ import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableS
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.FunctionSegment;
 
-import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -45,7 +46,8 @@ public final class FunctionExpressionSegmentBinder {
      * @return bound function segment
      */
     public static FunctionSegment bind(final FunctionSegment segment, final SegmentType parentSegmentType, final SQLStatementBinderContext binderContext,
-                                       final Map<String, TableSegmentBinderContext> tableBinderContexts, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                       final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                       final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         FunctionSegment result = new FunctionSegment(segment.getStartIndex(), segment.getStopIndex(), segment.getFunctionName(), segment.getText());
         result.setOwner(segment.getOwner());
         result.getParameters().addAll(segment.getParameters().stream()
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/InExpressionBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/InExpressionBinder.java
index f14e95a7437..8233c07b324 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/InExpressionBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/InExpressionBinder.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
@@ -26,8 +28,6 @@ import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinde
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.InExpression;
 
-import java.util.Map;
-
 /**
  * In expression binder.
  */
@@ -45,7 +45,8 @@ public final class InExpressionBinder {
      * @return bound in expression
      */
     public static InExpression bind(final InExpression segment, final SegmentType parentSegmentType, final SQLStatementBinderContext binderContext,
-                                    final Map<String, TableSegmentBinderContext> tableBinderContexts, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                    final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                    final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         ExpressionSegment boundLeft = ExpressionSegmentBinder.bind(segment.getLeft(), parentSegmentType, binderContext, tableBinderContexts, outerTableBinderContexts);
         ExpressionSegment boundRight = ExpressionSegmentBinder.bind(segment.getRight(), parentSegmentType, binderContext, tableBinderContexts, outerTableBinderContexts);
         return new InExpression(segment.getStartIndex(), segment.getStopIndex(), boundLeft, boundRight, segment.isNot());
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/NotExpressionBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/NotExpressionBinder.java
index cc7d608f091..b877238d870 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/NotExpressionBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/NotExpressionBinder.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
@@ -26,9 +29,6 @@ import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinde
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.NotExpression;
 
-import java.util.Collections;
-import java.util.Map;
-
 /**
  * Not expression binder.
  */
@@ -45,8 +45,8 @@ public final class NotExpressionBinder {
      * @return bound not expression
      */
     public static NotExpression bind(final NotExpression segment, final SegmentType parentSegmentType,
-                                     final SQLStatementBinderContext binderContext, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
-        ExpressionSegment boundExpression = ExpressionSegmentBinder.bind(segment.getExpression(), parentSegmentType, binderContext, tableBinderContexts, Collections.emptyMap());
+                                     final SQLStatementBinderContext binderContext, final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
+        ExpressionSegment boundExpression = ExpressionSegmentBinder.bind(segment.getExpression(), parentSegmentType, binderContext, tableBinderContexts, LinkedHashMultimap.create());
         return new NotExpression(segment.getStartIndex(), segment.getStopIndex(), boundExpression, segment.getNotSign());
     }
 }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/SubquerySegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/SubquerySegmentBinder.java
index e4723aea035..e986c0a0cfd 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/SubquerySegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/SubquerySegmentBinder.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
@@ -25,8 +27,6 @@ import org.apache.shardingsphere.infra.binder.engine.statement.dml.SelectStateme
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.dml.SelectStatement;
 
-import java.util.Map;
-
 /**
  * Subquery segment binder.
  */
@@ -41,7 +41,8 @@ public final class SubquerySegmentBinder {
      * @param outerTableBinderContexts outer table binder contexts
      * @return bound subquery segment
      */
-    public static SubquerySegment bind(final SubquerySegment segment, final SQLStatementBinderContext binderContext, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+    public static SubquerySegment bind(final SubquerySegment segment, final SQLStatementBinderContext binderContext,
+                                       final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         SQLStatementBinderContext selectBinderContext = new SQLStatementBinderContext(segment.getSelect(), binderContext.getMetaData(), binderContext.getCurrentDatabaseName());
         selectBinderContext.getExternalTableBinderContexts().putAll(binderContext.getExternalTableBinderContexts());
         SelectStatement boundSelectStatement = new SelectStatementBinder(outerTableBinderContexts).bind(segment.getSelect(), selectBinderContext);
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/TableSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/TableSegmentBinder.java
index f417d5bc396..a29186e97c3 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/TableSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/TableSegmentBinder.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.from;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
@@ -34,8 +36,6 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table
 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SubqueryTableSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableSegment;
 
-import java.util.Map;
-
 /**
  * Table segment binder.
  */
@@ -51,8 +51,8 @@ public final class TableSegmentBinder {
      * @param outerTableBinderContexts outer table binder contexts
      * @return bound table segment
      */
-    public static TableSegment bind(final TableSegment segment, final SQLStatementBinderContext binderContext, final Map<String, TableSegmentBinderContext> tableBinderContexts,
-                                    final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+    public static TableSegment bind(final TableSegment segment, final SQLStatementBinderContext binderContext, final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                    final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         if (segment instanceof SimpleTableSegment) {
             return SimpleTableSegmentBinder.bind((SimpleTableSegment) segment, binderContext, tableBinderContexts);
         }
@@ -66,11 +66,13 @@ public final class TableSegmentBinder {
             return DeleteMultiTableSegmentBinder.bind((DeleteMultiTableSegment) segment, binderContext, tableBinderContexts);
         }
         if (segment instanceof FunctionTableSegment) {
-            tableBinderContexts.put(segment.getAliasName().orElseGet(() -> ((FunctionTableSegment) segment).getTableFunction().getText()).toLowerCase(), new FunctionTableSegmentBinderContext());
+            tableBinderContexts.put(new CaseInsensitiveString(segment.getAliasName().orElseGet(() -> ((FunctionTableSegment) segment).getTableFunction().getText())),
+                    new FunctionTableSegmentBinderContext());
             return segment;
         }
         if (segment instanceof CollectionTableSegment) {
-            tableBinderContexts.put(segment.getAliasName().orElseGet(() -> ((CollectionTableSegment) segment).getExpressionSegment().getText()).toLowerCase(), new FunctionTableSegmentBinderContext());
+            tableBinderContexts.put(new CaseInsensitiveString(segment.getAliasName().orElseGet(() -> ((CollectionTableSegment) segment).getExpressionSegment().getText())),
+                    new FunctionTableSegmentBinderContext());
             return segment;
         }
         return segment;
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/DeleteMultiTableSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/DeleteMultiTableSegmentBinder.java
index aef146a00b6..c1b7e331f81 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/DeleteMultiTableSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/DeleteMultiTableSegmentBinder.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.from.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.TableSegmentBinder;
@@ -24,9 +27,6 @@ import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableS
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.DeleteMultiTableSegment;
 
-import java.util.Collections;
-import java.util.Map;
-
 /**
  * Delete multi table segment binder.
  */
@@ -42,12 +42,12 @@ public final class DeleteMultiTableSegmentBinder {
      * @return bound delete multi table segment
      */
     public static DeleteMultiTableSegment bind(final DeleteMultiTableSegment segment,
-                                               final SQLStatementBinderContext binderContext, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+                                               final SQLStatementBinderContext binderContext, final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
         DeleteMultiTableSegment result = new DeleteMultiTableSegment();
         result.setStartIndex(segment.getStartIndex());
         result.setStopIndex(segment.getStopIndex());
         result.getActualDeleteTables().addAll(segment.getActualDeleteTables());
-        result.setRelationTable(TableSegmentBinder.bind(segment.getRelationTable(), binderContext, tableBinderContexts, Collections.emptyMap()));
+        result.setRelationTable(TableSegmentBinder.bind(segment.getRelationTable(), binderContext, tableBinderContexts, LinkedHashMultimap.create()));
         return result;
     }
 }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/JoinTableSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/JoinTableSegmentBinder.java
index 9af254ca17c..d631ef67139 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/JoinTableSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/JoinTableSegmentBinder.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.from.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap;
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
 import com.google.common.collect.LinkedHashMultimap;
 import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
@@ -41,7 +43,6 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table
 
 import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -62,7 +63,8 @@ public final class JoinTableSegmentBinder {
      * @return bound join table segment
      */
     public static JoinTableSegment bind(final JoinTableSegment segment, final SQLStatementBinderContext binderContext,
-                                        final Map<String, TableSegmentBinderContext> tableBinderContexts, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                        final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                        final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         JoinTableSegment result = new JoinTableSegment();
         result.setStartIndex(segment.getStartIndex());
         result.setStopIndex(segment.getStopIndex());
@@ -71,15 +73,15 @@ public final class JoinTableSegmentBinder {
         result.setJoinType(segment.getJoinType());
         result.setLeft(TableSegmentBinder.bind(segment.getLeft(), binderContext, tableBinderContexts, outerTableBinderContexts));
         result.setRight(TableSegmentBinder.bind(segment.getRight(), binderContext, tableBinderContexts, outerTableBinderContexts));
-        result.setCondition(ExpressionSegmentBinder.bind(segment.getCondition(), SegmentType.JOIN_ON, binderContext, tableBinderContexts, Collections.emptyMap()));
+        result.setCondition(ExpressionSegmentBinder.bind(segment.getCondition(), SegmentType.JOIN_ON, binderContext, tableBinderContexts, LinkedHashMultimap.create()));
         result.setUsing(bindUsingColumns(segment.getUsing(), tableBinderContexts));
-        result.getUsing().forEach(each -> binderContext.getUsingColumnNames().add(each.getIdentifier().getValue().toLowerCase()));
+        result.getUsing().forEach(each -> binderContext.getUsingColumnNames().add(each.getIdentifier().getValue()));
         Map<String, ProjectionSegment> usingColumnsByNaturalJoin = Collections.emptyMap();
         if (result.isNatural()) {
             usingColumnsByNaturalJoin = getUsingColumnsByNaturalJoin(result, tableBinderContexts);
             Collection<ColumnSegment> derivedUsingColumns = getDerivedUsingColumns(usingColumnsByNaturalJoin);
             result.setDerivedUsing(bindUsingColumns(derivedUsingColumns, tableBinderContexts));
-            result.getDerivedUsing().forEach(each -> binderContext.getUsingColumnNames().add(each.getIdentifier().getValue().toLowerCase()));
+            result.getDerivedUsing().forEach(each -> binderContext.getUsingColumnNames().add(each.getIdentifier().getValue()));
         }
         result.getDerivedJoinTableProjectionSegments().addAll(getDerivedJoinTableProjectionSegments(result, binderContext.getDatabaseType(), usingColumnsByNaturalJoin, tableBinderContexts));
         binderContext.getJoinTableProjectionSegments().addAll(result.getDerivedJoinTableProjectionSegments());
@@ -97,7 +99,7 @@ public final class JoinTableSegmentBinder {
         return result;
     }
     
-    private static List<ColumnSegment> bindUsingColumns(final Collection<ColumnSegment> usingColumns, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+    private static List<ColumnSegment> bindUsingColumns(final Collection<ColumnSegment> usingColumns, final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
         List<ColumnSegment> result = new LinkedList<>();
         for (ColumnSegment each : usingColumns) {
             result.add(ColumnSegmentBinder.bindUsingColumn(each, SegmentType.JOIN_USING, tableBinderContexts));
@@ -107,7 +109,7 @@ public final class JoinTableSegmentBinder {
     
     private static Collection<ProjectionSegment> getDerivedJoinTableProjectionSegments(final JoinTableSegment segment, final DatabaseType databaseType,
                                                                                        final Map<String, ProjectionSegment> usingColumnsByNaturalJoin,
-                                                                                       final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+                                                                                       final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
         Collection<ProjectionSegment> projectionSegments = getProjectionSegments(segment, databaseType, tableBinderContexts);
         if (segment.getUsing().isEmpty() && !segment.isNatural()) {
             return projectionSegments;
@@ -122,7 +124,7 @@ public final class JoinTableSegmentBinder {
     }
     
     private static Collection<ProjectionSegment> getProjectionSegments(final JoinTableSegment segment, final DatabaseType databaseType,
-                                                                       final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+                                                                       final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
         Collection<ProjectionSegment> result = new LinkedList<>();
         if (databaseType instanceof MySQLDatabaseType && JoinType.RIGHT.name().equalsIgnoreCase(segment.getJoinType()) && (!segment.getUsing().isEmpty() || segment.isNatural())) {
             result.addAll(getProjectionSegments(segment.getRight(), tableBinderContexts));
@@ -134,7 +136,7 @@ public final class JoinTableSegmentBinder {
         return result;
     }
     
-    private static Collection<ProjectionSegment> getProjectionSegments(final TableSegment tableSegment, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+    private static Collection<ProjectionSegment> getProjectionSegments(final TableSegment tableSegment, final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
         Collection<ProjectionSegment> result = new LinkedList<>();
         if (tableSegment instanceof SimpleTableSegment) {
             String tableAliasOrName = tableSegment.getAliasName().orElseGet(() -> ((SimpleTableSegment) tableSegment).getTableName().getIdentifier().getValue());
@@ -147,19 +149,20 @@ public final class JoinTableSegmentBinder {
         return result;
     }
     
-    private static Collection<ProjectionSegment> getProjectionSegmentsByTableAliasOrName(final Map<String, TableSegmentBinderContext> tableBinderContexts, final String tableAliasOrName) {
-        ShardingSpherePreconditions.checkContainsKey(tableBinderContexts, tableAliasOrName.toLowerCase(),
+    private static Collection<ProjectionSegment> getProjectionSegmentsByTableAliasOrName(final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                                                                         final String tableAliasOrName) {
+        ShardingSpherePreconditions.checkContains(tableBinderContexts.keySet(), new CaseInsensitiveString(tableAliasOrName),
                 () -> new IllegalStateException(String.format("Can not find table binder context by table alias or name %s.", tableAliasOrName)));
-        return tableBinderContexts.get(tableAliasOrName.toLowerCase()).getProjectionSegments();
+        return tableBinderContexts.get(new CaseInsensitiveString(tableAliasOrName)).iterator().next().getProjectionSegments();
     }
     
-    private static Map<String, ProjectionSegment> getUsingColumnsByNaturalJoin(final JoinTableSegment segment, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
-        Map<String, ProjectionSegment> result = new LinkedHashMap<>();
+    private static Map<String, ProjectionSegment> getUsingColumnsByNaturalJoin(final JoinTableSegment segment, final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
+        Map<String, ProjectionSegment> result = new CaseInsensitiveMap<>();
         Collection<ProjectionSegment> leftProjections = getProjectionSegments(segment.getLeft(), tableBinderContexts);
-        Map<String, ProjectionSegment> rightProjections = new LinkedHashMap<>();
-        getProjectionSegments(segment.getRight(), tableBinderContexts).forEach(each -> rightProjections.put(each.getColumnLabel().toLowerCase(), each));
+        Map<String, ProjectionSegment> rightProjections = new CaseInsensitiveMap<>();
+        getProjectionSegments(segment.getRight(), tableBinderContexts).forEach(each -> rightProjections.put(each.getColumnLabel(), each));
         for (ProjectionSegment each : leftProjections) {
-            String columnLabel = each.getColumnLabel().toLowerCase();
+            String columnLabel = each.getColumnLabel();
             if (rightProjections.containsKey(columnLabel)) {
                 result.put(columnLabel, each);
             }
@@ -169,14 +172,14 @@ public final class JoinTableSegmentBinder {
     
     private static Map<String, ProjectionSegment> getUsingColumns(final Collection<ProjectionSegment> projectionSegments, final Collection<ColumnSegment> usingColumns, final String joinType) {
         Multimap<String, ProjectionSegment> columnLabelProjectionSegments = LinkedHashMultimap.create();
-        projectionSegments.forEach(each -> columnLabelProjectionSegments.put(each.getColumnLabel().toLowerCase(), each));
-        Map<String, ProjectionSegment> result = new LinkedHashMap<>();
+        projectionSegments.forEach(each -> columnLabelProjectionSegments.put(each.getColumnLabel(), each));
+        Map<String, ProjectionSegment> result = new CaseInsensitiveMap<>();
         for (ColumnSegment each : usingColumns) {
-            LinkedList<ProjectionSegment> groupProjectionSegments = new LinkedList<>(columnLabelProjectionSegments.get(each.getIdentifier().getValue().toLowerCase()));
+            LinkedList<ProjectionSegment> groupProjectionSegments = new LinkedList<>(columnLabelProjectionSegments.get(each.getIdentifier().getValue()));
             if (!groupProjectionSegments.isEmpty()) {
                 ProjectionSegment targetProjectionSegment =
                         JoinType.RIGHT.name().equalsIgnoreCase(joinType) ? groupProjectionSegments.descendingIterator().next() : groupProjectionSegments.iterator().next();
-                result.put(targetProjectionSegment.getColumnLabel().toLowerCase(), targetProjectionSegment);
+                result.put(targetProjectionSegment.getColumnLabel(), targetProjectionSegment);
             }
         }
         return result;
@@ -184,9 +187,9 @@ public final class JoinTableSegmentBinder {
     
     private static Collection<ProjectionSegment> getJoinUsingColumnsByProjectionOrder(final Collection<ProjectionSegment> projectionSegments,
                                                                                       final Map<String, ProjectionSegment> usingColumns) {
-        Map<String, ProjectionSegment> result = new LinkedHashMap<>(usingColumns.size(), 1F);
+        Map<String, ProjectionSegment> result = new CaseInsensitiveMap<>(usingColumns.size(), 1F);
         for (ProjectionSegment each : projectionSegments) {
-            String columnLabel = each.getColumnLabel().toLowerCase();
+            String columnLabel = each.getColumnLabel();
             if (!result.containsKey(columnLabel) && usingColumns.containsKey(columnLabel)) {
                 result.put(columnLabel, each);
             }
@@ -197,7 +200,7 @@ public final class JoinTableSegmentBinder {
     private static Collection<ProjectionSegment> getJoinRemainingColumns(final Collection<ProjectionSegment> projectionSegments, final Map<String, ProjectionSegment> usingColumns) {
         Collection<ProjectionSegment> result = new LinkedList<>();
         for (ProjectionSegment each : projectionSegments) {
-            if (!usingColumns.containsKey(each.getColumnLabel().toLowerCase())) {
+            if (!usingColumns.containsKey(each.getColumnLabel())) {
                 result.add(each);
             }
         }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SimpleTableSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SimpleTableSegmentBinder.java
index 0fccc867238..f02b27f33e5 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SimpleTableSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SimpleTableSegmentBinder.java
@@ -17,7 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.from.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
 import com.cedarsoftware.util.CaseInsensitiveSet;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
@@ -47,7 +49,6 @@ import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.Iden
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedList;
-import java.util.Map;
 import java.util.Optional;
 
 /**
@@ -75,7 +76,8 @@ public final class SimpleTableSegmentBinder {
      * @param tableBinderContexts table binder contexts
      * @return bound simple table segment
      */
-    public static SimpleTableSegment bind(final SimpleTableSegment segment, final SQLStatementBinderContext binderContext, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+    public static SimpleTableSegment bind(final SimpleTableSegment segment, final SQLStatementBinderContext binderContext,
+                                          final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
         fillPivotColumnNamesInBinderContext(segment, binderContext);
         IdentifierValue databaseName = getDatabaseName(segment, binderContext);
         ShardingSpherePreconditions.checkNotNull(databaseName.getValue(), NoDatabaseSelectedException::new);
@@ -83,8 +85,8 @@ public final class SimpleTableSegmentBinder {
         IdentifierValue tableName = segment.getTableName().getIdentifier();
         checkTableExists(binderContext, databaseName.getValue(), schemaName.getValue(), tableName.getValue());
         ShardingSphereSchema schema = binderContext.getMetaData().getDatabase(databaseName.getValue()).getSchema(schemaName.getValue());
-        tableBinderContexts.putIfAbsent(
-                (segment.getAliasName().orElseGet(tableName::getValue)).toLowerCase(), createSimpleTableBinderContext(segment, schema, databaseName, schemaName, binderContext));
+        tableBinderContexts.put(new CaseInsensitiveString(segment.getAliasName().orElseGet(tableName::getValue)),
+                createSimpleTableBinderContext(segment, schema, databaseName, schemaName, binderContext));
         TableNameSegment tableNameSegment = new TableNameSegment(segment.getTableName().getStartIndex(), segment.getTableName().getStopIndex(), tableName);
         SimpleTableSegment result = new SimpleTableSegment(tableNameSegment);
         segment.getOwner().ifPresent(result::setOwner);
@@ -93,7 +95,7 @@ public final class SimpleTableSegmentBinder {
     }
     
     private static void fillPivotColumnNamesInBinderContext(final SimpleTableSegment segment, final SQLStatementBinderContext binderContext) {
-        segment.getPivot().ifPresent(optional -> optional.getPivotColumns().forEach(each -> binderContext.getPivotColumnNames().add(each.getIdentifier().getValue().toLowerCase())));
+        segment.getPivot().ifPresent(optional -> optional.getPivotColumns().forEach(each -> binderContext.getPivotColumnNames().add(each.getIdentifier().getValue())));
     }
     
     private static IdentifierValue getDatabaseName(final SimpleTableSegment segment, final SQLStatementBinderContext binderContext) {
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SubqueryTableSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SubqueryTableSegmentBinder.java
index 225f6787e2f..e1f8e170402 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SubqueryTableSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SubqueryTableSegmentBinder.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.from.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
@@ -30,8 +32,6 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table
 import org.apache.shardingsphere.sql.parser.statement.core.statement.dml.SelectStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
 
-import java.util.Map;
-
 /**
  * Subquery table segment binder.
  */
@@ -48,7 +48,8 @@ public final class SubqueryTableSegmentBinder {
      * @return bound subquery table segment
      */
     public static SubqueryTableSegment bind(final SubqueryTableSegment segment, final SQLStatementBinderContext binderContext,
-                                            final Map<String, TableSegmentBinderContext> tableBinderContexts, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                            final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                            final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         fillPivotColumnNamesInBinderContext(segment, binderContext);
         SQLStatementBinderContext subqueryBinderContext = new SQLStatementBinderContext(segment.getSubquery().getSelect(), binderContext.getMetaData(), binderContext.getCurrentDatabaseName());
         subqueryBinderContext.getExternalTableBinderContexts().putAll(binderContext.getExternalTableBinderContexts());
@@ -58,12 +59,12 @@ public final class SubqueryTableSegmentBinder {
         IdentifierValue subqueryTableName = segment.getAliasSegment().map(AliasSegment::getIdentifier).orElseGet(() -> new IdentifierValue(""));
         SubqueryTableSegment result = new SubqueryTableSegment(segment.getStartIndex(), segment.getStopIndex(), boundSubquerySegment);
         segment.getAliasSegment().ifPresent(result::setAlias);
-        tableBinderContexts.put(subqueryTableName.getValue().toLowerCase(), new SimpleTableSegmentBinderContext(
+        tableBinderContexts.put(new CaseInsensitiveString(subqueryTableName.getValue()), new SimpleTableSegmentBinderContext(
                 SubqueryTableBindUtils.createSubqueryProjections(boundSubSelect.getProjections().getProjections(), subqueryTableName, binderContext.getDatabaseType())));
         return result;
     }
     
     private static void fillPivotColumnNamesInBinderContext(final SubqueryTableSegment segment, final SQLStatementBinderContext binderContext) {
-        segment.getPivot().ifPresent(optional -> optional.getPivotColumns().forEach(each -> binderContext.getPivotColumnNames().add(each.getIdentifier().getValue().toLowerCase())));
+        segment.getPivot().ifPresent(optional -> optional.getPivotColumns().forEach(each -> binderContext.getPivotColumnNames().add(each.getIdentifier().getValue())));
     }
 }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/lock/LockSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/lock/LockSegmentBinder.java
index 520251b876c..5ab1ae83f85 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/lock/LockSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/lock/LockSegmentBinder.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.lock;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
@@ -25,7 +27,6 @@ import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableS
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.LockSegment;
 
-import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -44,7 +45,8 @@ public final class LockSegmentBinder {
      * @return bound lock segment
      */
     public static LockSegment bind(final LockSegment segment, final SQLStatementBinderContext binderContext,
-                                   final Map<String, TableSegmentBinderContext> tableBinderContexts, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                   final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                   final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         LockSegment result = new LockSegment(segment.getStartIndex(), segment.getStopIndex());
         result.getTables().addAll(segment.getTables());
         result.getColumns().addAll(segment.getColumns().stream()
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/ProjectionsSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/ProjectionsSegmentBinder.java
index 9a65b2a029d..124fbbf15a6 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/ProjectionsSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/ProjectionsSegmentBinder.java
@@ -17,13 +17,16 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.projection;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
-import org.apache.shardingsphere.infra.binder.engine.segment.projection.type.ColumnProjectionSegmentBinder;
-import org.apache.shardingsphere.infra.binder.engine.segment.projection.type.ShorthandProjectionSegmentBinder;
 import org.apache.shardingsphere.infra.binder.engine.segment.expression.ExpressionSegmentBinder;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
+import org.apache.shardingsphere.infra.binder.engine.segment.projection.type.ColumnProjectionSegmentBinder;
+import org.apache.shardingsphere.infra.binder.engine.segment.projection.type.ShorthandProjectionSegmentBinder;
 import org.apache.shardingsphere.infra.binder.engine.segment.projection.type.SubqueryProjectionSegmentBinder;
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
@@ -35,8 +38,6 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.Shor
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.SubqueryProjectionSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableSegment;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -56,7 +57,8 @@ public final class ProjectionsSegmentBinder {
      * @return bound projections segment
      */
     public static ProjectionsSegment bind(final ProjectionsSegment segment, final SQLStatementBinderContext binderContext, final TableSegment boundTableSegment,
-                                          final Map<String, TableSegmentBinderContext> tableBinderContexts, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                          final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                          final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         ProjectionsSegment result = new ProjectionsSegment(segment.getStartIndex(), segment.getStopIndex());
         result.setDistinctRow(segment.isDistinctRow());
         result.getProjections().addAll(segment.getProjections().stream()
@@ -65,7 +67,8 @@ public final class ProjectionsSegmentBinder {
     }
     
     private static ProjectionSegment bind(final ProjectionSegment projectionSegment, final SQLStatementBinderContext binderContext, final TableSegment boundTableSegment,
-                                          final Map<String, TableSegmentBinderContext> tableBinderContexts, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                          final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                          final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         if (projectionSegment instanceof ColumnProjectionSegment) {
             return ColumnProjectionSegmentBinder.bind((ColumnProjectionSegment) projectionSegment, binderContext, tableBinderContexts);
         }
@@ -73,7 +76,7 @@ public final class ProjectionsSegmentBinder {
             return ShorthandProjectionSegmentBinder.bind((ShorthandProjectionSegment) projectionSegment, boundTableSegment, tableBinderContexts);
         }
         if (projectionSegment instanceof SubqueryProjectionSegment) {
-            Map<String, TableSegmentBinderContext> newOuterTableBinderContexts = new LinkedHashMap<>(outerTableBinderContexts.size() + tableBinderContexts.size(), 1F);
+            Multimap<CaseInsensitiveString, TableSegmentBinderContext> newOuterTableBinderContexts = LinkedHashMultimap.create();
             newOuterTableBinderContexts.putAll(outerTableBinderContexts);
             newOuterTableBinderContexts.putAll(tableBinderContexts);
             return SubqueryProjectionSegmentBinder.bind((SubqueryProjectionSegment) projectionSegment, binderContext, newOuterTableBinderContexts);
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/ColumnProjectionSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/ColumnProjectionSegmentBinder.java
index b7193465ed9..37110563853 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/ColumnProjectionSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/ColumnProjectionSegmentBinder.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.projection.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
@@ -26,9 +29,6 @@ import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinde
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ColumnProjectionSegment;
 
-import java.util.Collections;
-import java.util.Map;
-
 /**
  * Column projection segment binder.
  */
@@ -44,8 +44,8 @@ public final class ColumnProjectionSegmentBinder {
      * @return bound column projection segment
      */
     public static ColumnProjectionSegment bind(final ColumnProjectionSegment segment,
-                                               final SQLStatementBinderContext binderContext, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
-        ColumnSegment boundColumn = ColumnSegmentBinder.bind(segment.getColumn(), SegmentType.PROJECTION, binderContext, tableBinderContexts, Collections.emptyMap());
+                                               final SQLStatementBinderContext binderContext, final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
+        ColumnSegment boundColumn = ColumnSegmentBinder.bind(segment.getColumn(), SegmentType.PROJECTION, binderContext, tableBinderContexts, LinkedHashMultimap.create());
         ColumnProjectionSegment result = new ColumnProjectionSegment(boundColumn);
         segment.getAliasSegment().ifPresent(result::setAlias);
         result.setVisible(segment.isVisible());
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/ShorthandProjectionSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/ShorthandProjectionSegmentBinder.java
index bfb7bfd9c53..65394bf10e5 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/ShorthandProjectionSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/ShorthandProjectionSegmentBinder.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.projection.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
@@ -29,7 +31,6 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table
 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableSegment;
 
 import java.util.Collection;
-import java.util.Map;
 
 /**
  * Shorthand projection segment binder.
@@ -46,7 +47,7 @@ public final class ShorthandProjectionSegmentBinder {
      * @return bound shorthand projection segment
      */
     public static ShorthandProjectionSegment bind(final ShorthandProjectionSegment segment, final TableSegment boundTableSegment,
-                                                  final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+                                                  final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
         ShorthandProjectionSegment result = copy(segment);
         if (segment.getOwner().isPresent()) {
             expandVisibleColumns(getProjectionSegmentsByTableAliasOrName(tableBinderContexts, segment.getOwner().get().getIdentifier().getValue()), result);
@@ -63,10 +64,11 @@ public final class ShorthandProjectionSegmentBinder {
         return result;
     }
     
-    private static Collection<ProjectionSegment> getProjectionSegmentsByTableAliasOrName(final Map<String, TableSegmentBinderContext> tableBinderContexts, final String tableAliasOrName) {
-        ShardingSpherePreconditions.checkContainsKey(tableBinderContexts, tableAliasOrName.toLowerCase(),
+    private static Collection<ProjectionSegment> getProjectionSegmentsByTableAliasOrName(final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                                                                         final String tableAliasOrName) {
+        ShardingSpherePreconditions.checkContains(tableBinderContexts.keySet(), new CaseInsensitiveString(tableAliasOrName),
                 () -> new IllegalStateException(String.format("Can not find table binder context by table alias or name %s.", tableAliasOrName)));
-        return tableBinderContexts.get(tableAliasOrName.toLowerCase()).getProjectionSegments();
+        return tableBinderContexts.get(new CaseInsensitiveString(tableAliasOrName)).iterator().next().getProjectionSegments();
     }
     
     private static void expandVisibleColumns(final Collection<ProjectionSegment> projectionSegments, final ShorthandProjectionSegment segment) {
@@ -77,7 +79,7 @@ public final class ShorthandProjectionSegmentBinder {
         }
     }
     
-    private static void expandNoOwnerProjections(final TableSegment boundTableSegment, final Map<String, TableSegmentBinderContext> tableBinderContexts,
+    private static void expandNoOwnerProjections(final TableSegment boundTableSegment, final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
                                                  final ShorthandProjectionSegment segment) {
         if (boundTableSegment instanceof SimpleTableSegment) {
             String tableAliasOrName = boundTableSegment.getAliasName().orElseGet(() -> ((SimpleTableSegment) boundTableSegment).getTableName().getIdentifier().getValue());
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/SubqueryProjectionSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/SubqueryProjectionSegmentBinder.java
index 55219433df3..4feba0cb9b1 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/SubqueryProjectionSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/SubqueryProjectionSegmentBinder.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.projection.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.expression.type.SubquerySegmentBinder;
@@ -25,8 +27,6 @@ import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinde
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.SubqueryProjectionSegment;
 
-import java.util.Map;
-
 /**
  * Subquery projection segment binder.
  */
@@ -42,7 +42,7 @@ public final class SubqueryProjectionSegmentBinder {
      * @return bound subquery projection segment
      */
     public static SubqueryProjectionSegment bind(final SubqueryProjectionSegment segment,
-                                                 final SQLStatementBinderContext binderContext, final Map<String, TableSegmentBinderContext> tableBinderContexts) {
+                                                 final SQLStatementBinderContext binderContext, final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts) {
         SubquerySegment boundSubquerySegment = SubquerySegmentBinder.bind(segment.getSubquery(), binderContext, tableBinderContexts);
         SubqueryProjectionSegment result = new SubqueryProjectionSegment(boundSubquerySegment, segment.getText());
         segment.getAliasSegment().ifPresent(result::setAlias);
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinder.java
index 34776635fc0..8c96935e7e8 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinder.java
@@ -17,6 +17,8 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.where;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.Multimap;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
@@ -25,8 +27,6 @@ import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableS
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment;
 
-import java.util.Map;
-
 /**
  * Where segment binder.
  */
@@ -43,7 +43,8 @@ public final class WhereSegmentBinder {
      * @return bound where segment
      */
     public static WhereSegment bind(final WhereSegment segment, final SQLStatementBinderContext binderContext,
-                                    final Map<String, TableSegmentBinderContext> tableBinderContexts, final Map<String, TableSegmentBinderContext> outerTableBinderContexts) {
+                                    final Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts,
+                                    final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts) {
         return new WhereSegment(segment.getStartIndex(), segment.getStopIndex(),
                 ExpressionSegmentBinder.bind(segment.getExpr(), SegmentType.PREDICATE, binderContext, tableBinderContexts, outerTableBinderContexts));
     }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/SQLStatementBinderContext.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/SQLStatementBinderContext.java
index 1ac3e373c8e..10d28175fa8 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/SQLStatementBinderContext.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/SQLStatementBinderContext.java
@@ -17,7 +17,10 @@
 
 package org.apache.shardingsphere.infra.binder.engine.statement;
 
-import com.cedarsoftware.util.CaseInsensitiveMap;
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.cedarsoftware.util.CaseInsensitiveSet;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
@@ -27,9 +30,7 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.Proj
 import org.apache.shardingsphere.sql.parser.statement.core.statement.SQLStatement;
 
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.LinkedList;
-import java.util.Map;
 
 /**
  * SQL statement binder context.
@@ -46,18 +47,18 @@ public final class SQLStatementBinderContext {
     
     private final Collection<String> variableNames;
     
-    private final Collection<String> usingColumnNames = new HashSet<>();
+    private final Collection<String> usingColumnNames = new CaseInsensitiveSet<>();
     
     private final Collection<ProjectionSegment> joinTableProjectionSegments = new LinkedList<>();
     
-    private final Map<String, TableSegmentBinderContext> externalTableBinderContexts = new CaseInsensitiveMap<>();
+    private final Multimap<CaseInsensitiveString, TableSegmentBinderContext> externalTableBinderContexts = LinkedHashMultimap.create();
     
-    private final Collection<String> pivotColumnNames = new HashSet<>();
+    private final Collection<String> pivotColumnNames = new CaseInsensitiveSet<>();
     
     public SQLStatementBinderContext(final SQLStatement sqlStatement, final ShardingSphereMetaData metaData, final String currentDatabaseName) {
         this.metaData = metaData;
         this.currentDatabaseName = currentDatabaseName;
         databaseType = sqlStatement.getDatabaseType();
-        variableNames = sqlStatement.getVariableNames();
+        variableNames = new CaseInsensitiveSet<>(sqlStatement.getVariableNames());
     }
 }
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/DeleteStatementBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/DeleteStatementBinder.java
index 72c218a2d1b..663c8f5bb45 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/DeleteStatementBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/DeleteStatementBinder.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.statement.dml;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import lombok.SneakyThrows;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.TableSegmentBinder;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
@@ -25,10 +28,6 @@ import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinde
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.dml.DeleteStatement;
 
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
 /**
  * Delete statement binder.
  */
@@ -37,9 +36,9 @@ public final class DeleteStatementBinder implements SQLStatementBinder<DeleteSta
     @Override
     public DeleteStatement bind(final DeleteStatement sqlStatement, final SQLStatementBinderContext binderContext) {
         DeleteStatement result = copy(sqlStatement);
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
-        result.setTable(TableSegmentBinder.bind(sqlStatement.getTable(), binderContext, tableBinderContexts, Collections.emptyMap()));
-        sqlStatement.getWhere().ifPresent(optional -> result.setWhere(WhereSegmentBinder.bind(optional, binderContext, tableBinderContexts, Collections.emptyMap())));
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
+        result.setTable(TableSegmentBinder.bind(sqlStatement.getTable(), binderContext, tableBinderContexts, LinkedHashMultimap.create()));
+        sqlStatement.getWhere().ifPresent(optional -> result.setWhere(WhereSegmentBinder.bind(optional, binderContext, tableBinderContexts, LinkedHashMultimap.create())));
         return result;
     }
     
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/InsertStatementBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/InsertStatementBinder.java
index af5d970e61f..5d2ac4a1780 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/InsertStatementBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/InsertStatementBinder.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.statement.dml;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import lombok.SneakyThrows;
 import org.apache.shardingsphere.infra.binder.engine.segment.column.InsertColumnsSegmentBinder;
 import org.apache.shardingsphere.infra.binder.engine.segment.expression.type.SubquerySegmentBinder;
@@ -30,8 +33,6 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.Proj
 import org.apache.shardingsphere.sql.parser.statement.core.statement.dml.InsertStatement;
 
 import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -42,7 +43,7 @@ public final class InsertStatementBinder implements SQLStatementBinder<InsertSta
     @Override
     public InsertStatement bind(final InsertStatement sqlStatement, final SQLStatementBinderContext binderContext) {
         InsertStatement result = copy(sqlStatement);
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
         sqlStatement.getTable().ifPresent(optional -> result.setTable(SimpleTableSegmentBinder.bind(optional, binderContext, tableBinderContexts)));
         if (sqlStatement.getInsertColumns().isPresent() && !sqlStatement.getInsertColumns().get().getColumns().isEmpty()) {
             result.setInsertColumns(InsertColumnsSegmentBinder.bind(sqlStatement.getInsertColumns().get(), binderContext, tableBinderContexts));
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java
index b2cff322e1f..c0a5da62a6d 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/SelectStatementBinder.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.statement.dml;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import lombok.RequiredArgsConstructor;
 import lombok.SneakyThrows;
 import org.apache.shardingsphere.infra.binder.engine.segment.combine.CombineSegmentBinder;
@@ -30,9 +33,6 @@ import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinde
 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.dml.SelectStatement;
 
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
 import java.util.Optional;
 
 /**
@@ -41,16 +41,16 @@ import java.util.Optional;
 @RequiredArgsConstructor
 public final class SelectStatementBinder implements SQLStatementBinder<SelectStatement> {
     
-    private final Map<String, TableSegmentBinderContext> outerTableBinderContexts;
+    private final Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts;
     
     public SelectStatementBinder() {
-        outerTableBinderContexts = Collections.emptyMap();
+        outerTableBinderContexts = LinkedHashMultimap.create();
     }
     
     @Override
     public SelectStatement bind(final SelectStatement sqlStatement, final SQLStatementBinderContext binderContext) {
         SelectStatement result = copy(sqlStatement);
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
         Optional<TableSegment> boundTableSegment = sqlStatement.getFrom().map(optional -> TableSegmentBinder.bind(optional, binderContext, tableBinderContexts, outerTableBinderContexts));
         boundTableSegment.ifPresent(result::setFrom);
         result.setProjections(ProjectionsSegmentBinder.bind(sqlStatement.getProjections(), binderContext, boundTableSegment.orElse(null), tableBinderContexts, outerTableBinderContexts));
diff --git a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/UpdateStatementBinder.java b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/UpdateStatementBinder.java
index 29427181e26..2747106952d 100644
--- a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/UpdateStatementBinder.java
+++ b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dml/UpdateStatementBinder.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.statement.dml;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import lombok.SneakyThrows;
 import org.apache.shardingsphere.infra.binder.engine.segment.assign.AssignmentSegmentBinder;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.TableSegmentBinder;
@@ -26,10 +29,6 @@ import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinde
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.dml.UpdateStatement;
 
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
 /**
  * Update statement binder.
  */
@@ -38,11 +37,11 @@ public final class UpdateStatementBinder implements SQLStatementBinder<UpdateSta
     @Override
     public UpdateStatement bind(final UpdateStatement sqlStatement, final SQLStatementBinderContext binderContext) {
         UpdateStatement result = copy(sqlStatement);
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
-        result.setTable(TableSegmentBinder.bind(sqlStatement.getTable(), binderContext, tableBinderContexts, Collections.emptyMap()));
-        sqlStatement.getFrom().ifPresent(optional -> result.setFrom(TableSegmentBinder.bind(optional, binderContext, tableBinderContexts, Collections.emptyMap())));
-        sqlStatement.getAssignmentSegment().ifPresent(optional -> result.setSetAssignment(AssignmentSegmentBinder.bind(optional, binderContext, tableBinderContexts, Collections.emptyMap())));
-        sqlStatement.getWhere().ifPresent(optional -> result.setWhere(WhereSegmentBinder.bind(optional, binderContext, tableBinderContexts, Collections.emptyMap())));
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
+        result.setTable(TableSegmentBinder.bind(sqlStatement.getTable(), binderContext, tableBinderContexts, LinkedHashMultimap.create()));
+        sqlStatement.getFrom().ifPresent(optional -> result.setFrom(TableSegmentBinder.bind(optional, binderContext, tableBinderContexts, LinkedHashMultimap.create())));
+        sqlStatement.getAssignmentSegment().ifPresent(optional -> result.setSetAssignment(AssignmentSegmentBinder.bind(optional, binderContext, tableBinderContexts, LinkedHashMultimap.create())));
+        sqlStatement.getWhere().ifPresent(optional -> result.setWhere(WhereSegmentBinder.bind(optional, binderContext, tableBinderContexts, LinkedHashMultimap.create())));
         return result;
     }
     
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/assign/AssignmentSegmentBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/assign/AssignmentSegmentBinderTest.java
index fecf5ab3781..fa22c44ee1d 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/assign/AssignmentSegmentBinderTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/assign/AssignmentSegmentBinderTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.assign;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.type.SimpleTableSegmentBinderContext;
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
@@ -33,7 +36,6 @@ import org.junit.jupiter.api.Test;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedList;
-import java.util.Map;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
@@ -51,9 +53,9 @@ class AssignmentSegmentBinderTest {
         ColumnSegment columnSegment = new ColumnSegment(0, 0, new IdentifierValue("order_id"));
         assignments.add(new ColumnAssignmentSegment(0, 0, Collections.singletonList(columnSegment), new LiteralExpressionSegment(0, 0, 1)));
         SetAssignmentSegment setAssignmentSegment = new SetAssignmentSegment(0, 0, assignments);
-        Map<String, TableSegmentBinderContext> tableBinderContexts = Collections.singletonMap(
-                "t_order", new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundOrderIdColumn))));
-        SetAssignmentSegment actual = AssignmentSegmentBinder.bind(setAssignmentSegment, mock(SQLStatementBinderContext.class), tableBinderContexts, Collections.emptyMap());
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
+        tableBinderContexts.put(new CaseInsensitiveString("t_order"), new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundOrderIdColumn))));
+        SetAssignmentSegment actual = AssignmentSegmentBinder.bind(setAssignmentSegment, mock(SQLStatementBinderContext.class), tableBinderContexts, LinkedHashMultimap.create());
         assertThat(actual, not(setAssignmentSegment));
         assertThat(actual.getAssignments().iterator().next(), not(setAssignmentSegment.getAssignments().iterator().next()));
         assertThat(actual.getAssignments().iterator().next().getColumns().iterator().next().getColumnBoundInfo().getOriginalTable().getValue(), is("t_order"));
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/BinaryOperationExpressionBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/BinaryOperationExpressionBinderTest.java
index 10026b292b3..25a9d68ca57 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/BinaryOperationExpressionBinderTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/BinaryOperationExpressionBinderTest.java
@@ -17,14 +17,13 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.google.common.collect.LinkedHashMultimap;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
 import org.junit.jupiter.api.Test;
 
-import java.util.Collections;
-
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.mockito.Mockito.mock;
@@ -37,8 +36,8 @@ class BinaryOperationExpressionBinderTest {
                 new LiteralExpressionSegment(0, 0, "test"),
                 new LiteralExpressionSegment(0, 0, "test"), "=", "test");
         SQLStatementBinderContext binderContext = mock(SQLStatementBinderContext.class);
-        BinaryOperationExpression actual = BinaryOperationExpressionBinder.bind(binaryOperationExpression, SegmentType.PROJECTION,
-                binderContext, Collections.emptyMap(), Collections.emptyMap());
+        BinaryOperationExpression actual =
+                BinaryOperationExpressionBinder.bind(binaryOperationExpression, SegmentType.PROJECTION, binderContext, LinkedHashMultimap.create(), LinkedHashMultimap.create());
         assertThat(actual.getLeft().getText(), is("test"));
         assertThat(actual.getRight().getText(), is("test"));
         assertThat(actual.getOperator(), is("="));
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinderTest.java
index e8851bc18fe..753dd0b6559 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinderTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinderTest.java
@@ -17,47 +17,51 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.type.SimpleTableSegmentBinderContext;
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.infra.database.core.DefaultDatabase;
 import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.exception.kernel.syntax.AmbiguousColumnException;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ColumnProjectionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.ColumnSegmentBoundInfo;
 import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
 import org.junit.jupiter.api.Test;
 
 import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.mock;
 
 class ColumnSegmentBinderTest {
     
     @Test
     void assertBindWithMultiTablesJoinAndNoOwner() {
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>(2, 1F);
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
         ColumnSegment boundOrderIdColumn = new ColumnSegment(0, 0, new IdentifierValue("order_id"));
         boundOrderIdColumn.setColumnBoundInfo(new ColumnSegmentBoundInfo(new IdentifierValue(DefaultDatabase.LOGIC_NAME), new IdentifierValue(DefaultDatabase.LOGIC_NAME),
                 new IdentifierValue("t_order"), new IdentifierValue("order_id")));
-        tableBinderContexts.put("t_order", new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundOrderIdColumn))));
+        tableBinderContexts.put(new CaseInsensitiveString("t_order"), new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundOrderIdColumn))));
         ColumnSegment boundItemIdColumn = new ColumnSegment(0, 0, new IdentifierValue("item_id"));
         boundItemIdColumn.setColumnBoundInfo(new ColumnSegmentBoundInfo(new IdentifierValue(DefaultDatabase.LOGIC_NAME), new IdentifierValue(DefaultDatabase.LOGIC_NAME),
                 new IdentifierValue("t_order_item"), new IdentifierValue("item_id")));
-        tableBinderContexts.put("t_order_item", new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundItemIdColumn))));
+        tableBinderContexts.put(new CaseInsensitiveString("t_order_item"), new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundItemIdColumn))));
         ColumnSegment columnSegment = new ColumnSegment(0, 0, new IdentifierValue("order_id"));
         SQLStatementBinderContext binderContext =
                 new SQLStatementBinderContext(mock(ShardingSphereMetaData.class), DefaultDatabase.LOGIC_NAME, TypedSPILoader.getService(DatabaseType.class, "FIXTURE"), Collections.emptySet());
-        ColumnSegment actual = ColumnSegmentBinder.bind(columnSegment, SegmentType.JOIN_ON, binderContext, tableBinderContexts, Collections.emptyMap());
+        ColumnSegment actual = ColumnSegmentBinder.bind(columnSegment, SegmentType.JOIN_ON, binderContext, tableBinderContexts, LinkedHashMultimap.create());
         assertNotNull(actual.getColumnBoundInfo());
         assertNull(actual.getOtherUsingColumnBoundInfo());
         assertThat(actual.getColumnBoundInfo().getOriginalDatabase().getValue(), is(DefaultDatabase.LOGIC_NAME));
@@ -68,19 +72,61 @@ class ColumnSegmentBinderTest {
     
     @Test
     void assertBindFromOuterTable() {
-        Map<String, TableSegmentBinderContext> outerTableBinderContexts = new LinkedHashMap<>(2, 1F);
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts = LinkedHashMultimap.create();
         ColumnSegment boundOrderStatusColumn = new ColumnSegment(0, 0, new IdentifierValue("status"));
         boundOrderStatusColumn.setColumnBoundInfo(new ColumnSegmentBoundInfo(new IdentifierValue(DefaultDatabase.LOGIC_NAME), new IdentifierValue(DefaultDatabase.LOGIC_NAME),
                 new IdentifierValue("t_order"), new IdentifierValue("status")));
-        outerTableBinderContexts.put("t_order", new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundOrderStatusColumn))));
+        outerTableBinderContexts.put(new CaseInsensitiveString("t_order"), new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundOrderStatusColumn))));
         ColumnSegment boundOrderItemStatusColumn = new ColumnSegment(0, 0, new IdentifierValue("status"));
         boundOrderItemStatusColumn.setColumnBoundInfo(new ColumnSegmentBoundInfo(new IdentifierValue(DefaultDatabase.LOGIC_NAME), new IdentifierValue(DefaultDatabase.LOGIC_NAME),
                 new IdentifierValue("t_order_item"), new IdentifierValue("status")));
-        outerTableBinderContexts.put("t_order_item", new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundOrderItemStatusColumn))));
+        outerTableBinderContexts.put(new CaseInsensitiveString("t_order_item"), new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundOrderItemStatusColumn))));
         SQLStatementBinderContext binderContext =
                 new SQLStatementBinderContext(mock(ShardingSphereMetaData.class), DefaultDatabase.LOGIC_NAME, TypedSPILoader.getService(DatabaseType.class, "FIXTURE"), Collections.emptySet());
         ColumnSegment columnSegment = new ColumnSegment(0, 0, new IdentifierValue("status"));
-        ColumnSegment actual = ColumnSegmentBinder.bind(columnSegment, SegmentType.PROJECTION, binderContext, Collections.emptyMap(), outerTableBinderContexts);
+        ColumnSegment actual = ColumnSegmentBinder.bind(columnSegment, SegmentType.PROJECTION, binderContext, LinkedHashMultimap.create(), outerTableBinderContexts);
+        assertNotNull(actual.getColumnBoundInfo());
+        assertNull(actual.getOtherUsingColumnBoundInfo());
+        assertThat(actual.getColumnBoundInfo().getOriginalDatabase().getValue(), is(DefaultDatabase.LOGIC_NAME));
+        assertThat(actual.getColumnBoundInfo().getOriginalSchema().getValue(), is(DefaultDatabase.LOGIC_NAME));
+        assertThat(actual.getColumnBoundInfo().getOriginalTable().getValue(), is("t_order_item"));
+        assertThat(actual.getColumnBoundInfo().getOriginalColumn().getValue(), is("status"));
+    }
+    
+    @Test
+    void assertBindWithSameTableAliasAndSameProjection() {
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
+        ColumnSegment boundOrderColumn = new ColumnSegment(0, 0, new IdentifierValue("status"));
+        boundOrderColumn.setColumnBoundInfo(new ColumnSegmentBoundInfo(new IdentifierValue(DefaultDatabase.LOGIC_NAME), new IdentifierValue(DefaultDatabase.LOGIC_NAME),
+                new IdentifierValue("t_order"), new IdentifierValue("status")));
+        tableBinderContexts.put(new CaseInsensitiveString("temp"), new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundOrderColumn))));
+        ColumnSegment boundOrderItemColumn = new ColumnSegment(0, 0, new IdentifierValue("status"));
+        boundOrderItemColumn.setColumnBoundInfo(new ColumnSegmentBoundInfo(new IdentifierValue(DefaultDatabase.LOGIC_NAME), new IdentifierValue(DefaultDatabase.LOGIC_NAME),
+                new IdentifierValue("t_order_item"), new IdentifierValue("status")));
+        tableBinderContexts.put(new CaseInsensitiveString("temp"), new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundOrderItemColumn))));
+        SQLStatementBinderContext binderContext =
+                new SQLStatementBinderContext(mock(ShardingSphereMetaData.class), DefaultDatabase.LOGIC_NAME, TypedSPILoader.getService(DatabaseType.class, "FIXTURE"), Collections.emptySet());
+        ColumnSegment columnSegment = new ColumnSegment(0, 0, new IdentifierValue("status"));
+        columnSegment.setOwner(new OwnerSegment(0, 0, new IdentifierValue("temp")));
+        assertThrows(AmbiguousColumnException.class, () -> ColumnSegmentBinder.bind(columnSegment, SegmentType.PROJECTION, binderContext, tableBinderContexts, LinkedHashMultimap.create()));
+    }
+    
+    @Test
+    void assertBindWithSameTableAliasAndDifferentProjection() {
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
+        ColumnSegment boundOrderColumn = new ColumnSegment(0, 0, new IdentifierValue("order_id"));
+        boundOrderColumn.setColumnBoundInfo(new ColumnSegmentBoundInfo(new IdentifierValue(DefaultDatabase.LOGIC_NAME), new IdentifierValue(DefaultDatabase.LOGIC_NAME),
+                new IdentifierValue("t_order"), new IdentifierValue("order_id")));
+        tableBinderContexts.put(new CaseInsensitiveString("temp"), new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundOrderColumn))));
+        ColumnSegment boundOrderItemColumn = new ColumnSegment(0, 0, new IdentifierValue("status"));
+        boundOrderItemColumn.setColumnBoundInfo(new ColumnSegmentBoundInfo(new IdentifierValue(DefaultDatabase.LOGIC_NAME), new IdentifierValue(DefaultDatabase.LOGIC_NAME),
+                new IdentifierValue("t_order_item"), new IdentifierValue("status")));
+        tableBinderContexts.put(new CaseInsensitiveString("temp"), new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundOrderItemColumn))));
+        SQLStatementBinderContext binderContext =
+                new SQLStatementBinderContext(mock(ShardingSphereMetaData.class), DefaultDatabase.LOGIC_NAME, TypedSPILoader.getService(DatabaseType.class, "FIXTURE"), Collections.emptySet());
+        ColumnSegment columnSegment = new ColumnSegment(0, 0, new IdentifierValue("status"));
+        columnSegment.setOwner(new OwnerSegment(0, 0, new IdentifierValue("temp")));
+        ColumnSegment actual = ColumnSegmentBinder.bind(columnSegment, SegmentType.PROJECTION, binderContext, tableBinderContexts, LinkedHashMultimap.create());
         assertNotNull(actual.getColumnBoundInfo());
         assertNull(actual.getOtherUsingColumnBoundInfo());
         assertThat(actual.getColumnBoundInfo().getOriginalDatabase().getValue(), is(DefaultDatabase.LOGIC_NAME));
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ExistsSubqueryExpressionBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ExistsSubqueryExpressionBinderTest.java
index ef7e2c55fdd..69b32b38daa 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ExistsSubqueryExpressionBinderTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ExistsSubqueryExpressionBinderTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.google.common.collect.LinkedHashMultimap;
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.infra.database.core.DefaultDatabase;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
@@ -41,7 +42,7 @@ class ExistsSubqueryExpressionBinderTest {
         selectStatement.setProjections(new ProjectionsSegment(0, 0));
         ExistsSubqueryExpression existsSubqueryExpression = new ExistsSubqueryExpression(0, 0, new SubquerySegment(0, 0, selectStatement, "t_test"));
         SQLStatementBinderContext binderContext = new SQLStatementBinderContext(mock(ShardingSphereMetaData.class), DefaultDatabase.LOGIC_NAME, new MockedDatabaseType(), Collections.emptyList());
-        ExistsSubqueryExpression actual = ExistsSubqueryExpressionBinder.bind(existsSubqueryExpression, binderContext, Collections.emptyMap());
+        ExistsSubqueryExpression actual = ExistsSubqueryExpressionBinder.bind(existsSubqueryExpression, binderContext, LinkedHashMultimap.create());
         assertThat(actual.getStartIndex(), is(existsSubqueryExpression.getStartIndex()));
         assertThat(actual.getStopIndex(), is(existsSubqueryExpression.getStopIndex()));
         assertThat(actual.getText(), is("t_test"));
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/FunctionExpressionSegmentBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/FunctionExpressionSegmentBinderTest.java
index 3a45fb63ae4..885d7f8a9ce 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/FunctionExpressionSegmentBinderTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/FunctionExpressionSegmentBinderTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.google.common.collect.LinkedHashMultimap;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.infra.database.core.DefaultDatabase;
@@ -36,7 +37,7 @@ class FunctionExpressionSegmentBinderTest {
     void assertBindFunctionExpressionSegment() {
         FunctionSegment functionSegment = new FunctionSegment(0, 0, "CONCAT", "('%','abc','%')");
         SQLStatementBinderContext binderContext = new SQLStatementBinderContext(new ShardingSphereMetaData(), DefaultDatabase.LOGIC_NAME, new MockedDatabaseType(), Collections.emptyList());
-        FunctionSegment actual = FunctionExpressionSegmentBinder.bind(functionSegment, SegmentType.PROJECTION, binderContext, Collections.emptyMap(), Collections.emptyMap());
+        FunctionSegment actual = FunctionExpressionSegmentBinder.bind(functionSegment, SegmentType.PROJECTION, binderContext, LinkedHashMultimap.create(), LinkedHashMultimap.create());
         assertThat(actual.getStartIndex(), is(functionSegment.getStartIndex()));
         assertThat(actual.getStopIndex(), is(functionSegment.getStopIndex()));
         assertThat(actual.getFunctionName(), is("CONCAT"));
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/InExpressionBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/InExpressionBinderTest.java
index 32a00d0780e..b815a3e5a35 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/InExpressionBinderTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/InExpressionBinderTest.java
@@ -17,14 +17,13 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.google.common.collect.LinkedHashMultimap;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.InExpression;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
 import org.junit.jupiter.api.Test;
 
-import java.util.Collections;
-
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -38,7 +37,7 @@ class InExpressionBinderTest {
                 new LiteralExpressionSegment(0, 0, "left"),
                 new LiteralExpressionSegment(0, 0, "right"), true);
         SQLStatementBinderContext binderContext = mock(SQLStatementBinderContext.class);
-        InExpression actual = InExpressionBinder.bind(inExpression, SegmentType.PROJECTION, binderContext, Collections.emptyMap(), Collections.emptyMap());
+        InExpression actual = InExpressionBinder.bind(inExpression, SegmentType.PROJECTION, binderContext, LinkedHashMultimap.create(), LinkedHashMultimap.create());
         assertThat(actual.getText(), is("leftright"));
         assertTrue(actual.isNot());
     }
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/NotExpressionBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/NotExpressionBinderTest.java
index 17e9e48d38f..d54bc6b8470 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/NotExpressionBinderTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/NotExpressionBinderTest.java
@@ -17,14 +17,13 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.google.common.collect.LinkedHashMultimap;
 import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.NotExpression;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
 import org.junit.jupiter.api.Test;
 
-import java.util.Collections;
-
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.mockito.Mockito.mock;
@@ -35,7 +34,7 @@ class NotExpressionBinderTest {
     void assertBind() {
         NotExpression notExpression = new NotExpression(0, 10, new LiteralExpressionSegment(0, 0, "test"), true);
         SQLStatementBinderContext binderContext = mock(SQLStatementBinderContext.class);
-        NotExpression actual = NotExpressionBinder.bind(notExpression, SegmentType.PROJECTION, binderContext, Collections.emptyMap());
+        NotExpression actual = NotExpressionBinder.bind(notExpression, SegmentType.PROJECTION, binderContext, LinkedHashMultimap.create());
         assertThat(actual.getNotSign(), is(notExpression.getNotSign()));
         assertThat(actual.getStartIndex(), is(notExpression.getStartIndex()));
         assertThat(actual.getStopIndex(), is(notExpression.getStopIndex()));
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/SubquerySegmentBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/SubquerySegmentBinderTest.java
index c08d85da16f..1dd245111b0 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/SubquerySegmentBinderTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/SubquerySegmentBinderTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.expression.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.type.SimpleTableSegmentBinderContext;
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
@@ -43,8 +46,6 @@ import org.junit.jupiter.api.Test;
 import java.sql.Types;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -73,8 +74,9 @@ class SubquerySegmentBinderTest {
         ColumnSegment boundNameColumn = new ColumnSegment(7, 13, new IdentifierValue("user_id"));
         boundNameColumn.setColumnBoundInfo(new ColumnSegmentBoundInfo(
                 new IdentifierValue(DefaultDatabase.LOGIC_NAME), new IdentifierValue(DefaultDatabase.LOGIC_NAME), new IdentifierValue("t_order_item"), new IdentifierValue("user_id")));
-        sqlStatementBinderContext.getExternalTableBinderContexts().put("t_order_item", new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundNameColumn))));
-        Map<String, TableSegmentBinderContext> outerTableBinderContexts = new LinkedHashMap<>();
+        sqlStatementBinderContext.getExternalTableBinderContexts().put(new CaseInsensitiveString("t_order_item"),
+                new SimpleTableSegmentBinderContext(Collections.singleton(new ColumnProjectionSegment(boundNameColumn))));
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts = LinkedHashMultimap.create();
         SubquerySegment actual = SubquerySegmentBinder.bind(subquerySegment, sqlStatementBinderContext, outerTableBinderContexts);
         assertNotNull(actual.getSelect());
         assertTrue(actual.getSelect().getFrom().isPresent());
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/JoinTableSegmentBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/JoinTableSegmentBinderTest.java
index 0fab947cb4d..b8fbed79a2d 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/JoinTableSegmentBinderTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/JoinTableSegmentBinderTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.from.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.infra.database.core.DefaultDatabase;
@@ -41,9 +44,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.CoreMatchers.is;
@@ -67,14 +68,14 @@ class JoinTableSegmentBinderTest {
         when(joinTableSegment.getLeft()).thenReturn(leftTable);
         when(joinTableSegment.getRight()).thenReturn(rightTable);
         ShardingSphereMetaData metaData = createMetaData();
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
         JoinTableSegment actual = JoinTableSegmentBinder.bind(joinTableSegment,
-                new SQLStatementBinderContext(metaData, DefaultDatabase.LOGIC_NAME, databaseType, Collections.emptySet()), tableBinderContexts, Collections.emptyMap());
+                new SQLStatementBinderContext(metaData, DefaultDatabase.LOGIC_NAME, databaseType, Collections.emptySet()), tableBinderContexts, LinkedHashMultimap.create());
         assertThat(actual.getLeft(), instanceOf(SimpleTableSegment.class));
         assertThat(actual.getRight(), instanceOf(SimpleTableSegment.class));
         assertJoinTableProjectionSegments(actual.getDerivedJoinTableProjectionSegments());
-        assertTrue(tableBinderContexts.containsKey("o"));
-        assertTrue(tableBinderContexts.containsKey("i"));
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("o")));
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("i")));
     }
     
     private void assertJoinTableProjectionSegments(final Collection<ProjectionSegment> joinTableProjectionSegments) {
@@ -105,14 +106,14 @@ class JoinTableSegmentBinderTest {
         when(joinTableSegment.getLeft()).thenReturn(leftTable);
         when(joinTableSegment.getRight()).thenReturn(rightTable);
         ShardingSphereMetaData metaData = createMetaData();
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
         JoinTableSegment actual = JoinTableSegmentBinder.bind(joinTableSegment, new SQLStatementBinderContext(metaData, DefaultDatabase.LOGIC_NAME, databaseType, Collections.emptySet()),
-                tableBinderContexts, Collections.emptyMap());
+                tableBinderContexts, LinkedHashMultimap.create());
         assertThat(actual.getLeft(), instanceOf(SimpleTableSegment.class));
         assertThat(actual.getRight(), instanceOf(SimpleTableSegment.class));
         assertJoinTableProjectionSegments(actual.getDerivedJoinTableProjectionSegments());
-        assertTrue(tableBinderContexts.containsKey("t_order"));
-        assertTrue(tableBinderContexts.containsKey("t_order_item"));
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("t_order")));
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("t_order_item")));
     }
     
     @Test
@@ -127,14 +128,14 @@ class JoinTableSegmentBinderTest {
         when(joinTableSegment.isNatural()).thenReturn(true);
         when(joinTableSegment.getJoinType()).thenReturn(JoinType.RIGHT.name());
         ShardingSphereMetaData metaData = createMetaData();
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
         JoinTableSegment actual = JoinTableSegmentBinder.bind(joinTableSegment, new SQLStatementBinderContext(metaData, DefaultDatabase.LOGIC_NAME, databaseType, Collections.emptySet()),
-                tableBinderContexts, Collections.emptyMap());
+                tableBinderContexts, LinkedHashMultimap.create());
         assertThat(actual.getLeft(), instanceOf(SimpleTableSegment.class));
         assertThat(actual.getRight(), instanceOf(SimpleTableSegment.class));
         assertJoinTableProjectionSegmentsWithNaturalJoin(actual.getDerivedJoinTableProjectionSegments());
-        assertTrue(tableBinderContexts.containsKey("o"));
-        assertTrue(tableBinderContexts.containsKey("i"));
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("o")));
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("i")));
     }
     
     private void assertJoinTableProjectionSegmentsWithNaturalJoin(final Collection<ProjectionSegment> joinTableProjectionSegments) {
@@ -163,14 +164,14 @@ class JoinTableSegmentBinderTest {
         when(joinTableSegment.getJoinType()).thenReturn(JoinType.RIGHT.name());
         when(joinTableSegment.getUsing()).thenReturn(Arrays.asList(new ColumnSegment(0, 0, new IdentifierValue("status")), new ColumnSegment(0, 0, new IdentifierValue("order_id"))));
         ShardingSphereMetaData metaData = createMetaData();
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
         JoinTableSegment actual = JoinTableSegmentBinder.bind(joinTableSegment, new SQLStatementBinderContext(metaData, DefaultDatabase.LOGIC_NAME, databaseType, Collections.emptySet()),
-                tableBinderContexts, Collections.emptyMap());
+                tableBinderContexts, LinkedHashMultimap.create());
         assertThat(actual.getLeft(), instanceOf(SimpleTableSegment.class));
         assertThat(actual.getRight(), instanceOf(SimpleTableSegment.class));
         assertJoinTableProjectionSegmentsWithUsing(actual.getDerivedJoinTableProjectionSegments());
-        assertTrue(tableBinderContexts.containsKey("o"));
-        assertTrue(tableBinderContexts.containsKey("i"));
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("o")));
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("i")));
     }
     
     private void assertJoinTableProjectionSegmentsWithUsing(final Collection<ProjectionSegment> joinTableProjectionSegments) {
@@ -198,17 +199,17 @@ class JoinTableSegmentBinderTest {
         when(joinTableSegment.getLeft()).thenReturn(leftTable);
         when(joinTableSegment.getRight()).thenReturn(rightTable);
         ShardingSphereMetaData metaData = createMetaData();
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
         JoinTableSegment actual = JoinTableSegmentBinder.bind(joinTableSegment,
-                new SQLStatementBinderContext(metaData, DefaultDatabase.LOGIC_NAME, databaseType, Collections.emptySet()), tableBinderContexts, Collections.emptyMap());
+                new SQLStatementBinderContext(metaData, DefaultDatabase.LOGIC_NAME, databaseType, Collections.emptySet()), tableBinderContexts, LinkedHashMultimap.create());
         assertThat(actual.getLeft(), instanceOf(JoinTableSegment.class));
         assertThat(((JoinTableSegment) actual.getLeft()).getLeft(), instanceOf(SimpleTableSegment.class));
         assertThat(((JoinTableSegment) actual.getLeft()).getRight(), instanceOf(SimpleTableSegment.class));
         assertThat(actual.getRight(), instanceOf(SimpleTableSegment.class));
         assertThat(actual.getDerivedJoinTableProjectionSegments().size(), is(10));
-        assertTrue(tableBinderContexts.containsKey("o"));
-        assertTrue(tableBinderContexts.containsKey("o2"));
-        assertTrue(tableBinderContexts.containsKey("i"));
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("o")));
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("o2")));
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("i")));
     }
     
     private JoinTableSegment mockLeftJoinSegment() {
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SimpleTableSegmentBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SimpleTableSegmentBinderTest.java
index a692cbb1386..84c7b7fd20b 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SimpleTableSegmentBinderTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SimpleTableSegmentBinderTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.from.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.infra.database.core.DefaultDatabase;
@@ -34,8 +37,6 @@ import org.junit.jupiter.api.Test;
 import java.sql.Types;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
 
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@@ -50,7 +51,7 @@ class SimpleTableSegmentBinderTest {
     void assertBindTableNotExists() {
         SimpleTableSegment simpleTableSegment = new SimpleTableSegment(new TableNameSegment(0, 10, new IdentifierValue("t_not_exists")));
         ShardingSphereMetaData metaData = createMetaData();
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
         assertThrows(TableNotFoundException.class, () -> SimpleTableSegmentBinder.bind(
                 simpleTableSegment, new SQLStatementBinderContext(metaData, DefaultDatabase.LOGIC_NAME, databaseType, Collections.emptySet()), tableBinderContexts));
     }
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SubqueryTableSegmentBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SubqueryTableSegmentBinderTest.java
index e0a49176041..d09954cc63e 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SubqueryTableSegmentBinderTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/from/type/SubqueryTableSegmentBinderTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.from.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.infra.database.core.DefaultDatabase;
@@ -43,9 +46,7 @@ import java.sql.Types;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 
 import static org.hamcrest.CoreMatchers.instanceOf;
@@ -72,12 +73,12 @@ class SubqueryTableSegmentBinderTest {
         SubqueryTableSegment subqueryTableSegment = new SubqueryTableSegment(0, 0, new SubquerySegment(0, 0, selectStatement, ""));
         subqueryTableSegment.setAlias(new AliasSegment(0, 0, new IdentifierValue("temp")));
         ShardingSphereMetaData metaData = createMetaData();
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
         SubqueryTableSegment actual = SubqueryTableSegmentBinder.bind(subqueryTableSegment, new SQLStatementBinderContext(metaData, DefaultDatabase.LOGIC_NAME, databaseType, Collections.emptySet()),
-                tableBinderContexts, Collections.emptyMap());
+                tableBinderContexts, LinkedHashMultimap.create());
         assertTrue(actual.getAlias().isPresent());
-        assertTrue(tableBinderContexts.containsKey("temp"));
-        List<ProjectionSegment> projectionSegments = new ArrayList<>(tableBinderContexts.get("temp").getProjectionSegments());
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("temp")));
+        List<ProjectionSegment> projectionSegments = new ArrayList<>(tableBinderContexts.get(new CaseInsensitiveString("temp")).iterator().next().getProjectionSegments());
         assertThat(projectionSegments.size(), is(3));
         assertThat(projectionSegments.get(0), instanceOf(ColumnProjectionSegment.class));
         assertTrue(((ColumnProjectionSegment) projectionSegments.get(0)).getColumn().getOwner().isPresent());
@@ -106,12 +107,12 @@ class SubqueryTableSegmentBinderTest {
         SubqueryTableSegment subqueryTableSegment = new SubqueryTableSegment(0, 0, new SubquerySegment(0, 0, selectStatement, ""));
         subqueryTableSegment.setAlias(new AliasSegment(0, 0, new IdentifierValue("temp")));
         ShardingSphereMetaData metaData = createMetaData();
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
         SubqueryTableSegment actual = SubqueryTableSegmentBinder.bind(subqueryTableSegment, new SQLStatementBinderContext(metaData, DefaultDatabase.LOGIC_NAME, databaseType, Collections.emptySet()),
-                tableBinderContexts, Collections.emptyMap());
+                tableBinderContexts, LinkedHashMultimap.create());
         assertTrue(actual.getAlias().isPresent());
-        assertTrue(tableBinderContexts.containsKey("temp"));
-        List<ProjectionSegment> projectionSegments = new ArrayList<>(tableBinderContexts.get("temp").getProjectionSegments());
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("temp")));
+        List<ProjectionSegment> projectionSegments = new ArrayList<>(tableBinderContexts.get(new CaseInsensitiveString("temp")).iterator().next().getProjectionSegments());
         assertThat(projectionSegments.size(), is(1));
         assertThat(projectionSegments.get(0), instanceOf(ColumnProjectionSegment.class));
         assertTrue(((ColumnProjectionSegment) projectionSegments.get(0)).getColumn().getOwner().isPresent());
@@ -129,11 +130,11 @@ class SubqueryTableSegmentBinderTest {
         when(selectStatement.getProjections()).thenReturn(projectionsSegment);
         SubqueryTableSegment subqueryTableSegment = new SubqueryTableSegment(0, 0, new SubquerySegment(0, 0, selectStatement, ""));
         ShardingSphereMetaData metaData = createMetaData();
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new LinkedHashMap<>();
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
         SubqueryTableSegment actual = SubqueryTableSegmentBinder.bind(subqueryTableSegment, new SQLStatementBinderContext(metaData, DefaultDatabase.LOGIC_NAME, databaseType, Collections.emptySet()),
-                tableBinderContexts, Collections.emptyMap());
+                tableBinderContexts, LinkedHashMultimap.create());
         assertFalse(actual.getAlias().isPresent());
-        assertTrue(tableBinderContexts.containsKey(""));
+        assertTrue(tableBinderContexts.containsKey(new CaseInsensitiveString("")));
     }
     
     private ShardingSphereMetaData createMetaData() {
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/ShorthandProjectionSegmentBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/ShorthandProjectionSegmentBinderTest.java
index 729762dbfc3..329efa58d9e 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/ShorthandProjectionSegmentBinderTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/projection/type/ShorthandProjectionSegmentBinderTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.projection.type;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.type.SimpleTableSegmentBinderContext;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
@@ -36,8 +39,6 @@ import org.apache.shardingsphere.sql.parser.statement.mysql.dml.MySQLSelectState
 import org.junit.jupiter.api.Test;
 
 import java.util.Arrays;
-import java.util.Collections;
-import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -52,8 +53,9 @@ class ShorthandProjectionSegmentBinderTest {
         shorthandProjectionSegment.setOwner(new OwnerSegment(0, 0, new IdentifierValue("o")));
         ColumnProjectionSegment invisibleColumn = new ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("status")));
         invisibleColumn.setVisible(false);
-        Map<String, TableSegmentBinderContext> tableBinderContexts = Collections.singletonMap(
-                "o", new SimpleTableSegmentBinderContext(Arrays.asList(new ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("order_id"))), invisibleColumn)));
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
+        tableBinderContexts.put(new CaseInsensitiveString("o"),
+                new SimpleTableSegmentBinderContext(Arrays.asList(new ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("order_id"))), invisibleColumn)));
         ShorthandProjectionSegment actual = ShorthandProjectionSegmentBinder.bind(shorthandProjectionSegment, mock(TableSegment.class), tableBinderContexts);
         assertThat(actual.getActualProjectionSegments().size(), is(1));
         ProjectionSegment visibleColumn = actual.getActualProjectionSegments().iterator().next();
@@ -65,8 +67,9 @@ class ShorthandProjectionSegmentBinderTest {
     void assertBindWithoutOwnerForSimpleTableSegment() {
         ColumnProjectionSegment invisibleColumn = new ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("status")));
         invisibleColumn.setVisible(false);
-        Map<String, TableSegmentBinderContext> tableBinderContexts = Collections.singletonMap(
-                "o", new SimpleTableSegmentBinderContext(Arrays.asList(new ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("order_id"))), invisibleColumn)));
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
+        tableBinderContexts.put(new CaseInsensitiveString("o"),
+                new SimpleTableSegmentBinderContext(Arrays.asList(new ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("order_id"))), invisibleColumn)));
         SimpleTableSegment boundTableSegment = new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("t_order")));
         boundTableSegment.setAlias(new AliasSegment(0, 0, new IdentifierValue("o")));
         ShorthandProjectionSegment actual = ShorthandProjectionSegmentBinder.bind(new ShorthandProjectionSegment(0, 0), boundTableSegment, tableBinderContexts);
@@ -80,8 +83,9 @@ class ShorthandProjectionSegmentBinderTest {
     void assertBindWithoutOwnerForSubqueryTableSegment() {
         ColumnProjectionSegment invisibleColumn = new ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("status")));
         invisibleColumn.setVisible(false);
-        Map<String, TableSegmentBinderContext> tableBinderContexts = Collections.singletonMap(
-                "o", new SimpleTableSegmentBinderContext(Arrays.asList(new ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("order_id"))), invisibleColumn)));
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
+        tableBinderContexts.put(new CaseInsensitiveString("o"),
+                new SimpleTableSegmentBinderContext(Arrays.asList(new ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("order_id"))), invisibleColumn)));
         SubqueryTableSegment boundTableSegment = new SubqueryTableSegment(0, 0, new SubquerySegment(0, 0, mock(MySQLSelectStatement.class), ""));
         boundTableSegment.setAlias(new AliasSegment(0, 0, new IdentifierValue("o")));
         ShorthandProjectionSegment actual = ShorthandProjectionSegmentBinder.bind(new ShorthandProjectionSegment(0, 0), boundTableSegment, tableBinderContexts);
@@ -96,7 +100,7 @@ class ShorthandProjectionSegmentBinderTest {
         ShorthandProjectionSegment shorthandProjectionSegment = new ShorthandProjectionSegment(0, 0);
         JoinTableSegment boundTableSegment = new JoinTableSegment();
         boundTableSegment.getDerivedJoinTableProjectionSegments().add(new ColumnProjectionSegment(new ColumnSegment(0, 0, new IdentifierValue("order_id"))));
-        ShorthandProjectionSegment actual = ShorthandProjectionSegmentBinder.bind(shorthandProjectionSegment, boundTableSegment, Collections.emptyMap());
+        ShorthandProjectionSegment actual = ShorthandProjectionSegmentBinder.bind(shorthandProjectionSegment, boundTableSegment, LinkedHashMultimap.create());
         assertThat(actual.getActualProjectionSegments().size(), is(1));
         ProjectionSegment visibleColumn = actual.getActualProjectionSegments().iterator().next();
         assertThat(visibleColumn.getColumnLabel(), is("order_id"));
diff --git a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinderTest.java b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinderTest.java
index e488d3723f0..84815358e63 100644
--- a/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinderTest.java
+++ b/infra/binder/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/where/WhereSegmentBinderTest.java
@@ -17,15 +17,15 @@
 
 package org.apache.shardingsphere.infra.binder.engine.segment.where;
 
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import org.apache.shardingsphere.infra.binder.engine.segment.from.context.TableSegmentBinderContext;
 import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment;
 import org.junit.jupiter.api.Test;
 
-import java.util.HashMap;
-import java.util.Map;
-
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.mockito.Mockito.mock;
@@ -36,8 +36,8 @@ class WhereSegmentBinderTest {
     void assertBind() {
         SQLStatementBinderContext sqlStatementBinderContext = mock(SQLStatementBinderContext.class);
         WhereSegment expectedWhereSegment = new WhereSegment(1, 2, mock(ExpressionSegment.class));
-        Map<String, TableSegmentBinderContext> tableBinderContexts = new HashMap<>();
-        Map<String, TableSegmentBinderContext> outerTableBinderContexts = new HashMap<>();
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> tableBinderContexts = LinkedHashMultimap.create();
+        Multimap<CaseInsensitiveString, TableSegmentBinderContext> outerTableBinderContexts = LinkedHashMultimap.create();
         WhereSegment actualWhereSegment = WhereSegmentBinder.bind(expectedWhereSegment, sqlStatementBinderContext, tableBinderContexts, outerTableBinderContexts);
         assertThat(actualWhereSegment.getStopIndex(), is(expectedWhereSegment.getStopIndex()));
         assertThat(actualWhereSegment.getStartIndex(), is(expectedWhereSegment.getStartIndex()));