로그에서 예제 SQL 문 추출

26973 단어 denojavascriptsql
최근에 building JavaScript RegExp from T-SQL statements 에 대한 StackOverflow 질문에 대한 링크를 게시했습니다.

그래서 좋은 도움을 받았지만 다른 접근 방식으로 접선을 시작했습니다. RegExp를 피하고 더 간단한 패턴 일치 접근 방식을 선호했습니다.

아래는 두 가지 접근 방식을 모두 보여주기 위해 만든 Deno 코드입니다. 더 간단한 접근 방식은 실제로 RegExp보다 내가 원하는 것에 더 가까워지며, 이는 RegExp가 더 정교해야 함을 시사합니다.

글을 작성하는 과정에서(일주일의 대부분이 걸렸습니다) 정말 유용한 몇 가지를 발견했습니다.
  • 고유한 항목만 배열로 지정:list = [...new Set(list)] as Array<string>
  • 사용자 지정 정렬(.sort() 문의 익명 함수 참조. 알겠습니다. 몇 년 동안 알고 있었지만 이것은 도움이 되는 복습이었습니다.)
  • console.time()console.timeEnd() Google Apps Script 프로젝트에서 가져온 것입니다.
  • Deno.args , 이제 로컬 파일을 제공할 수 있습니다. 이것은 github의 요점이 T-SQL 문의 225MB 파일 저장을 거부했기 때문에 특히 유용했습니다.

  • 이것의 흥미로운 결과 중 하나는 find missing indexes 프로세스에 입력할 몇 가지 명령문을 제공하는 것 외에도 잘못 지정된 TSQL 명령문이 생성되는 빈도를 보는 것입니다. 사용자는 문제가 발생했을 때 저에게 연락하는 방법을 알고 있지만 아무도 모릅니다. 그들이 나에게 말하지 않는(또는 하지 않을) 것을 나는 이제 알아내기 시작했습니다.

    // usage.ts
    //  pull sqlStatement list from a public gist
    //    otherwise from a local file.
    
    let list:string[];
    
    if (Deno.args.length > 0) {
      const text = await Deno.readTextFile(Deno.args[0]);
      list = text.split(/\r\n|\r|\n/g);
    } else {
      const sqlStatmentsOnGist = await fetch(
        "https://gist.githubusercontent.com/axtens/fe99f49a7b9d12c4467cb6b3ea509532/raw/7a688b70e5b2502d6116e66efcc28e6fc5bb97ad/Sample%2520SQL%2520selects",
      );
      const body = new Uint8Array(await sqlStatmentsOnGist.arrayBuffer());
      list = new TextDecoder("utf-8").decode(body).split(/\r\n|\r|\n/g);  
    }
    
    list = list.map((elem) => {
      return elem
        .toUpperCase()
        .replace(/\s{2,}/g, " ") /* compress runs of spaces */
        .replace(/;$/g, "") /* remove occasional trailing semicolon */
        .trim() + ";"; /* and then put one back on every line */
    });
    
    list = [...new Set(list)] as Array<string>; // keep unique lines
    
    list.sort((a: string, b: string): number => {
      const aa = a.replace(/\s+/g, "");
      const bb = b.replace(/\s+/g, "");
      if (aa.length < bb.length) {
        return 1;
      }
      if (aa.length > bb.length) {
        return -1;
      }
      if (aa < bb) {
        return 1;
      }
      if (aa > bb) {
        return -1;
      }
      return 0;
    }); /* sort longest lines first, then alphabetically */
    
    await Deno.writeTextFile("./sql-unique.txt", list.join("\r\n"));
    console.log("wrote sql-unique.txt");
    
    console.time("filterUsingRegularExpression");
    let result = filterUsingRegularExpression(list);
    console.timeEnd("filterUsingRegularExpression");
    await Deno.writeTextFile("./regex_filtered.txt", result.filtered.join("\r\n"));
    await Deno.writeTextFile("./regex_patterns.txt", result.patterns.join("\r\n"));
    
    console.time("filterUsingTokens");
    result = filterUsingTokens(list);
    console.timeEnd("filterUsingTokens");
    await Deno.writeTextFile("./token_filtered.txt", result.filtered.join("\r\n"));
    await Deno.writeTextFile("./token_patterns.txt", result.patterns.join("\r\n"));
    
    function filterUsingRegularExpression(
      list: string[],
    ): { filtered: string[]; patterns: string[] } {
      const safe = [];
      const check = [];
      while (true) {
        if (void 0 === list[0]) break;
        safe.push(list[0]);
        const expr2 = list[0]
          .replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
          .replace(/('[^']+')/g, "'.*'")
          .replace(/\d+/g, "\\d+")
          .replace(/\s+/g, "\\s+");
        check.push([expr2, list[0]].join("\t"));
        const newList = stripAccordingToPattern(list, new RegExp(expr2, "g"));
        //console.log("found %s not matching", newList.length);
        if (newList.length > 0) {
          if (list.length === newList.length) {
            list = newList.slice(1);
          } else {
            list = newList.slice(0);
          }
        } else {
          break;
        }
      }
      return { filtered: safe, patterns: check };
    }
    
    function filterUsingTokens(
      list: string[],
    ): { filtered: string[]; patterns: string[] } {
      const safe = [];
      const check = [];
      while (true) {
        if (void 0 === list[0]) break;
        safe.push(list[0]);
        const expr = tokenize(list[0]); //getPattern(list[0]);
        check.push([expr, list[0]].join("\t"));
        const newList = stripAccordingToToken(list, expr); //e.search(patt) === -1);
        //console.log("found %s not matching", newList.length);
        if (newList.length > 0) {
          if (list.length === newList.length) {
            list = newList.slice(1);
          } else {
            list = newList.slice(0);
          }
        } else {
          break;
        }
      }
      return { filtered: safe, patterns: check };
    }
    
    function tokenize(arg0: string): string {
      return arg0.replace(/\d+/g, "|NUMBER|").replace(/'[^']*'/g, "|STRING|");
    }
    
    function stripAccordingToToken(sqlList: string[], patt: string): string[] {
      const output = [];
      for (let i = 0; i < sqlList.length; i++) {
        const item = sqlList[i];
        if (tokenize(item) !== patt) output.push(sqlList[i]);
      }
      return output;
    }
    
    function stripAccordingToPattern(list: string[], patt: RegExp): string[] {
      const output = [];
      for (let i = 0; i < list.length; i++) {
        if (!patt.test(list[i])) output.push(list[i]);
      }
      return output;
    }
    

    좋은 웹페이지 즐겨찾기