sql 필드 해석 기 구현 예제

16353 단어 sql필드해석 기
예:sql 문 구 는 후속 적 인 유형 추정 이나 별명 필드 추출 정 의 를 위해 모든 필드 부분 을 캡 처 해 야 합 니 다.이 분석 방법 을 알려 주 십시오.
sql 의 필드 목록 때문에 사용 방식 이 제한 되 어 있 습 니 다.예 를 들 어 a as b,a,a...
1.문제 풀이 사고방식
복잡 한 처 리 를 하지 않 으 려 면 가장 생각 하기 쉬 운 것 은 바로 어떤 특징 으로 분할 하면 된다 는 것 이다.예 를 들 어 필드 목록 부분 을 먼저 캡 처 한 다음 에 쉼표','분할 하면 하나의 필드 를 얻 을 수 있 습 니 다.그리고 세분 화 를 해 야 합 니 다.사실은 as 로 분할 하면 됩 니 다.
가능 해 보이 지만 많은 구멍 이 존재 합 니 다.우선,이 안 에는 너무 많은 가설 이 있 습 니 다.각종 절 취 된 부분 은 요구 에 부합 되 어야 하고 불필요 한 쉼표 가 없어 야 하 며 as 등 이 있어 야 합 니 다.이것 은 분명히 요구 에 부합 되 지 않 는 다.
둘째,우 리 는 전환 방식 을 바 꿀 수 있다.예 를 들 어 field 부분 을 먼저 캡 처 한 다음 에 as 로 분할 한 다음 에 쉼표 로 분할 한 다음 에 마지막 단 어 를 field 로 한다.
더 나 빠 진 것 같 아 요.어디 까지 캡 처 했 는 지 전혀 모 르 겠 어 요.즉,원문 이 거의 파괴 되 었 고 as 변환 라벨 이 있어 야 하 며 함수 가 as 가 있 는 장면 을 노 리 는 것 은 완전히 잘못된 것 이다.
셋째,스스로 한 단어 씩 해석 하 는 것 이 좋 습 니 다.field 필드 는 몇 가지 상황 밖 에 없습니다.1.일반 필드 는 select a 와 같 습 니 다.2.selecta as b 와 같은 as 가 있 는 일반 필드;3.select coalesce(a,b)와 같은 함수 필드;4.함 수 를 가지 고 as 를 가 진 필드,예 를 들 어 select coalesce(a,b)ab;5.select cast(a as string)b 와 같은 함수 내 as 필드;...   우 리 는 차례대로 대응 하 는 상황 을 열거 하기 만 하면 필드 를 해석 할 수 있다.
좋 은 생각 인 것 같 습 니 다.하지만 구체 적 으로 실현 하 는 것 은 어 떨 까?
2.구체 적 해석 실현
주로 두 부분 으로 나 뉘 는데 1.분석 후의 결과 데이터 구 조 를 정의 하여 필드 정 보 를 명확 하 게 묘사 해 야 한다.2.단 어 를 나 누 어 sql 을 분석 하고 구조 체 로 되 돌려 줍 니 다.
우 리 는 먼저 전체 알고리즘 의 핵심 을 살 펴 보 자.

/**
 *     :   sql     
 *
 *           1:
 *          select COALESCE(t1.xno, t2.xno, t3.xno) as xno,
 *             case when t1.no is not null then 1 else null end as xxk001,
 *             case when t2.no is not null then 1 else null end as xxk200,
 *             case when t3.xno is not null then 1 else null end as xx3200
 *             from xxk001 t1
 *               full join xxkj100 t2 on t1.xno = t2.xno
 *               full join xxkj200 t3 on t1.xno = t3.xno;
 *
 *           2:
 *          select cast(a as string) as b from ccc;
 *
 *           3:
 *          with a as(select cus,x1 from b1), b as (select cus,x2 from b2)
 *              select a.cus as a_cus from a join b on a.cus=b.cus where xxx;
 *
 *           4:
 *         select a.xno,b.xx from a_tb as a join b_tb as b on a.id = b.id
 *
 *           5:
 *          select cast  \t(a as string) a_str, cc (a as double) a_double from x
 *
 */
public class SimpleSqlFieldParser {

    /**
     *        sql       
     *
     * @param sql   sql,    select xx from xxx join ...   
     * @return     
     */
    public static List<SelectFieldClauseDescriptor> parse(String sql) {
        String columnPart = adaptFieldPartSql(sql);
        int deep = 0;
        List<StringBuilder> fieldTokenSwap = new ArrayList<>();
        StringBuilder currentTokenBuilder = new StringBuilder();
        List<SelectFieldClauseDescriptor> fieldList = new ArrayList<>();
        fieldTokenSwap.add(currentTokenBuilder);
        int len = columnPart.length();
        char[] columnPartChars = columnPart.toCharArray();
        for(int i = 0; i < len; i++) {
            //     ,    ,tab  
            //      
            //  (   ,++deep;
            //  )   ,--deep;
            // deep>0           
            // as        fieldName
            // case      end  ;
            //,    token,     
            char currentChar = columnPartChars[i];
            switch (currentChar) {
                case '(':
                    ++deep;
                    currentTokenBuilder.append(currentChar);
                    break;
                case ')':
                    --deep;
                    currentTokenBuilder.append(currentChar);
                    break;
                case ',':
                    if(deep == 0) {
                        addNewField(fieldList, fieldTokenSwap, true);
                        fieldTokenSwap = new ArrayList<>();
                        currentTokenBuilder = new StringBuilder();
                        fieldTokenSwap.add(currentTokenBuilder);
                        break;
                    }
                    currentTokenBuilder.append(currentChar);
                    break;
                case ' ':
                case '\t':
                case '\r':
                case '
': if(deep > 0) { currentTokenBuilder.append(currentChar); continue; } if(currentTokenBuilder.length() == 0) { continue; } // original_name as --> alias if(i + 1 < len) { int j = i + 1; // StringBuilder spaceHolder = new StringBuilder(); boolean isNextLeftBracket = false; do { char nextChar = columnPart.charAt(j++); if(nextChar == ' ' || nextChar == '\t' || nextChar == '\r' || nextChar == '
') { spaceHolder.append(nextChar); continue; } if(nextChar == '(') { isNextLeftBracket = true; } break; } while (j < len); if(isNextLeftBracket) { currentTokenBuilder.append(currentChar); } if(spaceHolder.length() > 0) { currentTokenBuilder.append(spaceHolder); i += spaceHolder.length(); } if(isNextLeftBracket) { // continue next for, function begin continue; } } if(fieldTokenSwap.size() == 1) { if(fieldTokenSwap.get(0).toString().equalsIgnoreCase("case")) { String caseWhenPart = CommonUtil.readSplitWord( columnPartChars, i, " ", "end"); currentTokenBuilder.append(caseWhenPart); if(caseWhenPart.length() <= 0) { throw new BizException(" , case..when "); } i += caseWhenPart.length(); } } addNewField(fieldList, fieldTokenSwap, false); currentTokenBuilder = new StringBuilder(); fieldTokenSwap.add(currentTokenBuilder); break; // default: currentTokenBuilder.append(currentChar); break; } } // addNewField(fieldList, fieldTokenSwap, true); return fieldList; } /** * * * @param fieldList * @param fieldTokenSwap */ private static void addNewField(List<SelectFieldClauseDescriptor> fieldList, List<StringBuilder> fieldTokenSwap, boolean forceAdd) { int ts = fieldTokenSwap.size(); if(ts == 1 && forceAdd) { // db.original_name, String fieldName = fieldTokenSwap.get(0).toString(); String alias = fieldName; if(fieldName.contains(".")) { alias = fieldName.substring(fieldName.lastIndexOf('.') + 1); } fieldList.add(new SelectFieldClauseDescriptor(fieldName, alias)); return; } if(ts < 2) { return; } if(ts == 2) { // original_name alias, if(fieldTokenSwap.get(1).toString().equalsIgnoreCase("as")) { return; } fieldList.add(new SelectFieldClauseDescriptor( fieldTokenSwap.get(0).toString(), fieldTokenSwap.get(1).toString())); } else if(ts == 3) { // original_name as alias, fieldList.add(new SelectFieldClauseDescriptor( fieldTokenSwap.get(0).toString(), fieldTokenSwap.get(2).toString())); } else { throw new BizException(" , 3 :" + ts); } } // field private static String adaptFieldPartSql(String fullSql) { int start = fullSql.lastIndexOf("select "); int end = fullSql.lastIndexOf(" from"); String columnPart = fullSql.substring(start + "select ".length(), end); return columnPart.trim(); } }
비교적 간단 하 다 고 해 야 지,for 하나,switch 하나 면 돼.다른 것 은 논리 적 판정 이 더 많다.
다음은 필드 설명 류 의 쓰기 방법 을 살 펴 보 겠 습 니 다.사실은 두 필드,소스 필드 와 별명 입 니 다.

/**
 *     : sql     select      
 *
 */
public class SelectFieldClauseDescriptor {
    private String fieldName;
    private String alias;

    public SelectFieldClauseDescriptor(String fieldName, String alias) {
        this.fieldName = fieldName;
        this.alias = alias;
    }

    public String getFieldName() {
        return fieldName;
    }

    public String getAlias() {
        return alias;
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        SelectFieldClauseDescriptor that = (SelectFieldClauseDescriptor) o;
        return Objects.equals(fieldName, that.fieldName) &&
                Objects.equals(alias, that.alias);
    }

    @Override
    public int hashCode() {
        return Objects.hash(fieldName, alias);
    }

    @Override
    public String toString() {
        return "SelectFieldClauseDescriptor{" +
                "fieldName='" + fieldName + '\'' +
                ", alias='" + alias + '\'' +
                '}';
    }
}

그것 이 존재 하 는 의 미 는 단지 사용자 가 더욱 편리 하 게 가 치 를 얻 기 위해 더욱 진일보 한 해석 에 근 거 를 제공 했다 고 생각 하 는 것 이다.
3.유닛 테스트
사실 이런 도구 류 를 쓰 는 것 처럼 단원 테스트 가 가장 편리 하고 간단 하 다.최초의 결과 로,우 리 는 테스트 구동 개발 이 가장 적합 할 것 이 라 고 이미 예 상 했 기 때문이다.그리고 기본적으로 예상 치 에 맞지 않 는 값 이 나 오 면 빠르게 포 지 셔 닝 문제 가 생 긴 다.

/**
 *     : sql       
 **/
public class SimpleSqlFieldParserTest {

    @Test
    public void testParse() {
        String sql;
        List<SelectFieldClauseDescriptor> parsedFieldList;
        sql = "select COALESCE(t1.xno, t2.xno, t3.xno) as xno,
" + " case when t1.xno is not null then 1 else null end as xxk001,
" + " case when t2.xno is not null then 1 else null end as xxk200,
" + " case when t3.xno is not null then 1 else null end as xx3200
" + " from xxk001 t1
" + " full join xxkj100 t2 on t1.xno = t2.xno
" + " full join xxkj200 t3 on t1.xno = t3.xno;"; parsedFieldList = SimpleSqlFieldParser.parse(sql); System.out.println("result:"); parsedFieldList.forEach(System.out::println); Assert.assertEquals(" ", 4, parsedFieldList.size()); Assert.assertEquals(" ", "xno", parsedFieldList.get(0).getAlias()); Assert.assertEquals(" ", "xx3200", parsedFieldList.get(3).getAlias()); sql = "select cast(a as string) as b from ccc;"; parsedFieldList = SimpleSqlFieldParser.parse(sql); System.out.println("result:"); parsedFieldList.forEach(System.out::println); Assert.assertEquals(" ", 1, parsedFieldList.size()); Assert.assertEquals(" ", "b", parsedFieldList.get(0).getAlias()); sql = "with a as(select cus,x1 from b1), b as (select cus,x2 from b2)
" + " select a.cus as a_cus, cast(a
as string) as a_cus2, " + "b.x2 b2 from a join b on a.cus=b.cus where xxx;"; parsedFieldList = SimpleSqlFieldParser.parse(sql); System.out.println("result:"); parsedFieldList.forEach(System.out::println); Assert.assertEquals(" ", 3, parsedFieldList.size()); Assert.assertEquals(" ", "a_cus", parsedFieldList.get(0).getAlias()); Assert.assertEquals(" ", "b2", parsedFieldList.get(2).getAlias()); sql = "select a.xno,b.xx,qqq from a_tb as a join b_tb as b on a.id = b.id"; parsedFieldList = SimpleSqlFieldParser.parse(sql); System.out.println("result:"); parsedFieldList.forEach(System.out::println); Assert.assertEquals(" ", 3, parsedFieldList.size()); Assert.assertEquals(" ", "xno", parsedFieldList.get(0).getAlias()); Assert.assertEquals(" ", "qqq", parsedFieldList.get(2).getAlias()); sql = "select cast (a.a_int as string) a_str, b.xx, coalesce
( a, b, c) qqq from a_tb as a join b_tb as b on a.id = b.id"; parsedFieldList = SimpleSqlFieldParser.parse(sql); System.out.println("result:"); parsedFieldList.forEach(System.out::println); Assert.assertEquals(" ", 3, parsedFieldList.size()); Assert.assertEquals(" ", "a_str", parsedFieldList.get(0).getAlias()); Assert.assertEquals(" ", "cast (a.a_int as string)", parsedFieldList.get(0).getFieldName()); Assert.assertEquals(" ", "qqq", parsedFieldList.get(2).getAlias()); Assert.assertEquals(" ", "coalesce
( a, b, c)", parsedFieldList.get(2).getFieldName()); } }
이로써 간단 한 필드 해석 기 가 완성 되 었 습 니 다.작은 도구,참고 하 세 요!
sql 필드 해석 기 구현 예제 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 sql 필드 해석 기 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 도 많은 지원 바 랍 니 다!

좋은 웹페이지 즐겨찾기