回答

收藏

解析SQL之类的语法,设计模式

技术问答 技术问答 509 人阅读 | 0 人回复 | 2023-09-14

我正在尝试模拟sql语法来构建一个简单的sql类似于键值存储的接口。这些值本质上是POJO
) @, w* O! b, x6 q# f& e一个例子是- B3 r( ]& c. k5 ?3 [
select A.B.C from OBJ_POOL where A.B.X = 45 AND A.B.Y > '88' AND A.B.Z != 'abc';# U0 q% T* K, i1 F( e1 K5 U
OBJ_POOL只是相同类的POJO的列表。在此示例中,A将是基类。
; b% z3 @; n( l; bClass A5 m5 F5 I, w, Z) C) F5 E  {
    Class B
- I. u# S3 X3 d; Z/ r        String C6 {$ Q3 C2 z5 r( ^2 `
        Integer X
/ c7 N" E" o/ w  _$ T        String Y9 h) N8 `$ i) t1 A& i/ p  ]
        String Z7 S" S, X5 [6 I- m8 @# b
现在ABC等效于A.getB()。getC()3 E9 j% F2 X" P& P
我正在使用Antlr解析上述语句以获得AST,然后hoping使用Apache BeanUtils反射性地获取/设置字段名称。1 }$ S# V8 [) _/ c' t
我写了构建AST的语法 / J+ v9 {! d' s- b

" ]8 n" @* [/ H$ i& f4 u 现在我面临两个问题
4 q- [9 K! u4 a/ u& S- V) I: B[ol]where子句应如何实现访客?ABX = 45表示所有具有字段X为45的对象,请问如何进行过滤?+ f9 M9 e3 {. P( L7 p" q6 k9 H& J; |
有什么方法可以遍历所生成的AST,而不会用自定义逻辑(存储访问,属性获取器/设置器等)使访问者代码混乱。 9 h1 Z) @' A  |  a  {
[/ol]1 u# s, I1 A: S! d
第二个问题更加令人担忧,因为该语句可能会做很多事情。& i1 S/ f8 h- f, c. V
简而言之,很好地解析sql select语句的一小部分的任何建议/链接/设计模式将不胜感激。
1 v2 J9 K' |5 H/ i8 W$ o0 `5 N谢谢5 Y, G$ s4 w, N" M
               
  c6 ~! P* g$ q+ N2 S6 D) V解决方案:
7 c4 v. ^& v3 }8 p                ( S# p! x% S' A- u' \* V

1 p4 s, i- ]- k0 z/ h- K& |0 O3 J+ W" A- _, H0 n9 q
                您可以像我在博客文章中演示的那样进行操作(并且由于我知道您已阅读这些内容,因此我将不做详细介绍)。在这种情况下,唯一的区别是您的每一行数据都有其自己的范围。传递此范围的一种简单方法是将其作为eval(...)方法的参数提供。
3 s# p; c& Y- \# o$ Q  y1 P; C以下是如何实现此功能的快速演示。请注意,我根据我的博客文章很快将它们一起破解了:并非所有功能都可用(请参阅很多功能TODO,并且其中也可能存在(小)错误,使用后果自负!)。
  @% a) C% Z; x* [( U除了ANTLR v3.3,此演示还需要以下3个文件:
" x/ n0 J& t/ @8 E选择  Z/ ^* M7 @3 v  s9 c- w$ U2 _
grammar Select;
9 p+ f, r& {( O5 moptions {
" s% O( k- P' g- r  v. @% R  output=AST;
$ o" B8 U9 \) a/ \}
+ J$ s* u9 i" V, Ltokens {
  `1 B2 ?0 E7 J# p. k$ u  // imaginary tokens$ h8 s& N- K  [, U/ ?/ N6 h/ I
  ROOT;
" S: x, ^+ @7 C/ `* N$ N1 O  ATTR_LIST;
1 f* O7 d- R( P6 ]- b8 i% l1 s  UNARY_MINUS;1 _- A8 m9 s5 u+ g
  // literal tokens
# X" y0 k4 B4 W' j. t& a7 F; ]  Eq     = '=';  W3 T+ R7 d2 Z' b; F, z0 R
  NEq    = '!=';
  g, @. c: H" g: m  LT     = '';: H; ?. r0 C( B: e% v; Z
  GTEq   = '>=';6 q$ u& A( s9 D# s2 G5 H
  Minus  = '-';: }" P1 I7 d5 U0 _/ N
  Not    = '!';
$ A' Z. l/ s' P" }3 x  Select = 'select';
& X1 F3 Y0 j+ s9 K' `  From   = 'from';8 Q7 a5 x/ u: b  [2 z: H8 |
  Where  = 'where';  \8 S6 h' j* p' S7 H4 ]& v
  And    = 'AND';+ W! M; F" s3 ^
  Or     = 'OR';+ `. X* U: [9 V6 R3 w
}1 h9 t# _6 j' M& U3 C+ Z' e
parse' `6 c5 t( i  @0 Z9 I4 n8 Q
: select_stat EOF -> ^(ROOT select_stat)
" w8 s8 P1 m) k/ Y ;
1 M. P& b! o: ]select_stat
* F* E- f, V( r6 u: r! }& a6 X : Select attr_list From Id where_stat ';' -> ^(Select attr_list Id where_stat)) o, C  U7 G2 c1 O% O+ Q& U# ]! Y
;, x: m, E; c, q
attr_list
7 m1 `* g9 \- t8 ^2 I* o : Id (',' Id)* -> ^(ATTR_LIST Id+)
: j: Q5 ^$ Y; T$ i ;9 c% C2 L) f# x4 G9 S& U& S
where_stat
  K* z; x& W* h : Where expr -> expr
5 Q. ?+ A5 l+ A$ e' f4 {# ?3 k |            -> ^(Eq Int["1"] Int["1"]) ! F# j* i3 R" [( H
                 // no 'where', insert '1=1' which is always true
" Y/ d* w5 y# ^6 B ;
* d9 F* m* f3 E( }2 w$ ~' {2 V4 Z5 }expr
% U' L; X3 `4 r7 Q  Z : or_expr: x- \) x1 c' o$ \8 X5 @
;# P! H" A& \0 N
or_expr% r9 [+ L0 s3 x6 g* @
: and_expr (Or^ and_expr)*: J  |0 z4 O4 K- y
;
  z, c2 B! v0 D, nand_expr
7 e+ [7 a* l, c1 l3 O- R0 j : eq_expr (And^ eq_expr)*
$ O  U3 ~4 v. E1 e! s4 t ;
9 e2 p4 u1 c& beq_expr2 r8 C- n$ E8 [# G8 c0 @
: rel_expr ((Eq | NEq)^ rel_expr)*2 H' c9 ~8 x8 }3 v' A
;
$ i7 O0 y. M# |/ y5 ~5 T; y8 F' H" Y* Hrel_expr
" ?6 V0 O4 K6 a* ` : unary_expr ((LT | LTEq | GT | GTEq)^ unary_expr)?
1 ~; B4 x& p% U( c8 `# @ ;( d- w2 h6 o$ W+ `  X9 c) w
unary_expr
3 L: l( R0 [, f' J$ }, r : Minus atom -> ^(UNARY_MINUS atom)
( _* _# i8 I) D! i9 m; s | Not atom   -> ^(Not atom)7 C6 Q: X' g  O# l
| atom: W$ }5 X( v# [' V
;/ R% J/ N3 r9 V. L; y
atom
! m+ ~1 S9 V' ] : Str: F$ U' o& J! p+ @9 X
| Int
6 x+ q* ]1 P+ _, ~" y  d | Id
6 F, g9 G. N2 I- K7 j  L, X& ^ | '(' expr ')' -> expr
& Y: @$ j  t. }) [7 A ;; R% a3 N6 \8 k5 Z, y* ]
Id    : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | Digit)*;
! `. F+ B4 P+ |$ e2 PStr   : '\'' ('\'\'' | ~('\'' | '\r' | '\n'))* '\''
( x# p  d1 K9 z        {
1 g+ [3 v( ]0 {         // strip the surrounding quotes and replace '' with '
0 X2 I1 J$ ^- k. U5 r8 W         setText($text.substring(1, $text.length() - 1).replace("''", "'"));
* d! G3 @* W, c% _; ^# \; ^        }
/ o& a/ c. W# Q8 S9 U3 e      ;
% ]$ f  G: i' q) zInt   : Digit+;0 \( |4 `' w2 @* r7 B2 A$ k
Space : (' ' | '\t' | '\r' | '\n') {skip();};
7 p7 J0 j# k* v3 }fragment Digit : '0'..'9';  Q3 F5 I1 Q$ P1 {2 Q0 `3 F* I
SelectWalker.g
, J( P( \3 Y& @, ^( m- B& M3 ntree grammar SelectWalker;
3 D6 b+ U% N' [- C4 Yoptions {- o' `% V, h# A
  tokenVocab=Select;3 t0 z0 X. f6 }* b0 E* E& w- ?
  ASTLabelType=CommonTree;: I7 s7 r. ?! H/ ~
}; Q2 t+ z$ [4 ~2 Y% M
@header {7 _# T. D  I* [4 p; ~% ~" _( g2 D% l
  import java.util.List;
8 T, z- c7 r2 }. A  import java.util.Map;
+ |, I; R1 `; n/ o, s( k! q  import java.util.Set;9 G2 m$ O: y- r4 P, V6 Y$ z3 F
}  u  L- \7 h8 v/ g
@members {3 ]1 s4 |8 P, Y3 ]- J6 j
  private Map dataPool;
( l- ?+ ]" B) w3 Y  public SelectWalker(CommonTreeNodeStream nodes, Map data) {
+ w7 ]$ j' V) T! a+ m- l) K    super(nodes);
9 T' v- l( C  M: a1 h! W* U    dataPool = data;4 N5 d2 m1 U1 S* H' |
  }
# P0 D' C2 ^5 l  u( |}: @) \, M* j. d( F; ~! i# k7 d- [
query returns [List> result]
' U; `4 v6 }1 {3 O2 |$ k- A1 n$ ?' Z : ^(ROOT select_stat) {$result = (List>)$select_stat.node.eval(null);}
1 n- q. N$ |3 b* J& k- m+ L ;5 j8 {* c, w8 c# {2 \" ^, X
select_stat returns [Node node]
  v' Y, s5 Q2 o* o$ K! c8 _# S : ^(Select attr_list Id expr) . P) l. d$ ]+ c
    {$node = new SelectNode($attr_list.attributes, dataPool.get($Id.text), $expr.node);}
4 O3 |" ?! Z! |6 q1 L' o6 S6 u ;( b5 K, W& w1 ~: M6 @! D
attr_list returns [List attributes]
& v: _9 B* m9 l6 D@init{$attributes = new ArrayList();}1 B3 a$ K# B/ {: x! z1 f
: ^(ATTR_LIST (Id {$attributes.add($Id.text);})+)4 B% T# |8 x# R9 |9 i/ w" }  f# @
;
3 `$ o; x0 w: Z/ Yexpr returns [Node node]
3 z5 l/ S: g; S  ^+ p4 f0 R& k  | : ^(Or a=expr b=expr)   {$node = null; /* TODO */}, X4 K2 y. E7 E) A6 E
| ^(And a=expr b=expr)  {$node = new AndNode($a.node, $b.node);}' D3 F: M) A% {3 w; N) h( K
| ^(Eq a=expr b=expr)   {$node = new EqNode($a.node, $b.node);}/ u# ^7 Q" q# `- j* M" e6 G3 n
| ^(NEq a=expr b=expr)  {$node = new NEqNode($a.node, $b.node);}# H- r* H% s0 n
| ^(LT a=expr b=expr)   {$node = null; /* TODO */}
& }# C0 i: X& e | ^(LTEq a=expr b=expr) {$node = null; /* TODO */}( w1 v# M; @8 ~9 {5 A+ c
| ^(GT a=expr b=expr)   {$node = new GTNode($a.node, $b.node);}' _3 G: L( o7 L7 D0 i0 f6 X
| ^(GTEq a=expr b=expr) {$node = null; /* TODO */}
7 t, S) v( N0 X; W3 S9 x( W | ^(UNARY_MINUS a=expr) {$node = null; /* TODO */}! ?5 X( w; K1 `# N8 i% V9 p
| ^(Not a=expr)         {$node = null; /* TODO */}
$ s/ u) M2 ]! N  u0 e7 ^3 w | Str                   {$node = new AtomNode($Str.text);}
/ t0 X- ~! a( i: ^3 O# b8 d | Int                   {$node = new AtomNode(Integer.valueOf($Int.text));}
: F# c+ i. g8 `$ V/ ^8 f  | | Id                    {$node = new IdNode($Id.text);}' r) Q& f8 t: B( d
;9 c0 V' A$ T4 q% A
Main.java: o/ Z8 p  y3 Q$ K$ h. a
(是的,坚持所有这些Java类在同一个文件:Main.java)7 z7 v" x- S0 k2 p8 g
import org.antlr.runtime.*;
2 O3 E; C. i) _3 timport org.antlr.runtime.tree.*;; d8 s6 G$ V0 g, _
import org.antlr.stringtemplate.*;
) z' ?& }! m3 p" R2 `import java.util.*;' W8 R1 @7 y* P5 ?
public class Main {$ N& B6 Q+ H/ y: Z
  static Map getData() {
8 K; m; _& d' Y! t9 s    Map map = new HashMap();1 Z# E# B- h7 |6 k) ^
    List[B] data = new ArrayList[B]();
3 [: `$ v. V, m8 t# f  _) v, i- J    data.add(new B("id_1", 345, "89", "abd"));! O: f" G9 e/ T- N, m
    data.add(new B("id_2", 45, "89", "abd"));
; P# c4 O# u7 B! }! j    data.add(new B("id_3", 1, "89", "abd"));3 _3 t: ~1 d: [2 i9 R% T  e4 V
    data.add(new B("id_4", 45, "8", "abd"));
( ]6 l6 u) d9 R' ]' E' k. M7 Y    data.add(new B("id_5", 45, "89", "abc"));9 J; t. [1 U4 }# n$ Y
    data.add(new B("id_6", 45, "99", "abC"));
: A$ |6 j. @0 b    map.put("poolX", data);
& V) B; k8 k2 X/ }8 u    return map;: E0 t6 t0 E( t$ E
  }
0 ]" Y1 l. D! A* @( k+ B  public static void main(String[] args) throws Exception {
6 w) E1 }! @/ b1 _    String src = "select C, Y from poolX where X = 45 AND Y > '88' AND Z != 'abc';";: U/ j5 N& u, V- O) T# R1 c
    SelectLexer lexer = new SelectLexer(new ANTLRStringStream(src));& X. q! U% d! w
    SelectParser parser = new SelectParser(new CommonTokenStream(lexer));: ]# o! I. E6 b8 |4 w8 z
    CommonTree tree = (CommonTree)parser.parse().getTree();  ! S% l7 c5 M$ G' c3 C: ^& V1 B0 D  @
    SelectWalker walker = new SelectWalker(new CommonTreeNodeStream(tree), getData());  
! W& C, L$ j+ ?* a6 w8 A% {    List> result = walker.query();
, c3 V% V. C* ^& P    for(List row : result) {
; e* i7 v4 q/ T  [7 N2 m      System.out.println(row);# _; C9 L' h" {# S; x7 o
    }2 s0 b3 h9 ]9 M$ O
  }) t/ n' q. [( f* R
}
2 Y, u8 a) c+ h" ?class B {# Y- N# c& q: S, o6 ~: d: M
  String C;) I  ^9 l- e* V; _9 e* F
  Integer X;$ U: |" d: Z2 N* ~& }  S  y! B
  String Y;
+ }# _, {; I- |1 |  String Z;% G; @" V% k! t/ }  |
  B(String c, Integer x, String y, String z) {
2 i! Z5 g, a6 b3 F2 ~* J    C = c;
8 C& Y; Z% d. [8 v/ A    X = x;- |1 Q) @! n  z! R  b- D
    Y = y;
: o9 D" J, }$ x) T  g" x. c# \0 N+ e    Z = z;
- Q5 ^/ o1 u# [  }6 c3 x7 W/ g- {- @# k5 k
  Object getAttribute(String attribute) {
5 p9 ?" ?; G' n& T" \8 [    if(attribute.equals("C")) return C;
; V2 B1 W" l. @. ~0 m  a+ }4 m    if(attribute.equals("X")) return X;( Z) v! i+ x# _* F; }+ Z/ v
    if(attribute.equals("Y")) return Y;
" l) A; N0 K% s9 O$ L9 Y. c& ~    if(attribute.equals("Z")) return Z;3 w$ Q& [% \  {& N! f: ?5 ]( j) |
    throw new RuntimeException("Unknown attribute: B." + attribute);; ?7 _- m* X6 M  K) |
    // or use your Apache Bean-util API, or even reflection here instead of the above...
4 M; [! G+ \, E  ^7 K) z  }
! x, x8 X1 p& c  F$ l- |# x}- }6 J$ |7 s/ x( y( x4 d4 {
interface Node {
8 s* v& y1 v( b  Object eval(B b);$ f, }) L6 m$ k  O# }$ Z9 k8 k% b
}
' @# S2 f8 y8 S& nclass AtomNode implements Node {
. |5 N* b" `+ C0 F  t' Q. ]+ h  final Object value;# _  Q* E4 G/ ^- c' A5 J3 D# J- l
  AtomNode(Object v) {
6 S1 w' E4 w  W5 v7 w5 ~+ r    value = v;
- b0 c& w+ d: |/ k  }- k* E! k* t4 E
  public Object eval(B b) {
; ^6 X" K3 ^. q$ _1 ~, f% m    return value;
' |0 c- s$ P$ v8 h  }7 [6 W* d  G3 t) t4 ]8 G8 C! v
}
! H7 }& k" q+ l- ]1 Q0 ^abstract class BinNode implements Node {# l* B2 p' m$ q; b* F3 A! O9 E
  final Node left;# d5 L. g; g" k  r
  final Node right;
# [* L# d3 x* E  BinNode(Node l, Node r) {
! \+ ^6 \! F3 x    left = l;
' m4 m+ X& D7 Y% q; R    right = r;, J( ?5 L5 C/ Q% L# T0 x& k1 k
  }: x% E( @/ s# t" a; y
  public abstract Object eval(B b);7 _  {& m& u6 ~
}
9 ^- F  S6 J- F1 B2 O" sclass AndNode extends BinNode {
3 D: H! K1 b. Z5 }7 N  AndNode(Node l, Node r) {, {% E) [2 o% n) h# s
    super(l, r);3 j: ^9 O' v% ~5 l- G/ i
  }* M0 i( Q* B- Q# q' [# W3 |
  @Override
2 d/ y  o' c  q  public Object eval(B b) {1 D7 E% y2 X. p) K: X) Y; n
    return (Boolean)super.left.eval(b) && (Boolean)super.right.eval(b);: Q' x9 u* X3 `+ d
  }
1 s% V8 y8 P8 H9 G" P. w1 i2 a}' [. T2 U& L. |0 X" s8 ?
class EqNode extends BinNode {
/ P2 o/ M% c5 g* b2 d* C  EqNode(Node l, Node r) {* I8 ~2 c. R6 W' S0 m" z
    super(l, r);
5 p5 ~4 o4 w. n* U) ~  }" V8 m/ N5 n. ~/ p
  @Override
# h$ [; i1 x) q! f" I4 g  public Object eval(B b) {
; H2 W- g- D* \2 n9 P# l    return super.left.eval(b).equals(super.right.eval(b));
  Y$ X/ z4 O2 s# b6 N  }4 a: `: m1 p; G2 W* A2 V" J
}
# ?7 q4 M9 K% b' E4 p0 |4 Sclass NEqNode extends BinNode {- D: g  d  _+ F8 d
  NEqNode(Node l, Node r) {
% @6 B+ D, n, ~, D0 y    super(l, r);
3 [( r3 v; P! e  }
% p' m1 D. }0 y+ ^: x  @Override. U% B/ ^0 h) L$ N3 y. H) u% L/ G9 ?2 \
  public Object eval(B b) {
. [, o$ u8 s/ x1 z$ S/ k    return !super.left.eval(b).equals(super.right.eval(b));0 Q! q4 \! W: \) ~  D
  }1 o4 W" W  W+ D! o  E& J
}
4 p; S) i3 m+ ]+ p) eclass GTNode extends BinNode {
3 }) i0 G+ B9 y1 j  GTNode(Node l, Node r) {
7 {0 E! `# J& `    super(l, r);% s% g: y( a4 w( V2 h: A
  }
9 M7 ]5 w; H, w; X  @Override
/ b0 G" t; M7 z( a& c  public Object eval(B b) {
: z& V, r6 k) `1 h) }& X" b0 |    return ((Comparable)super.left.eval(b)).compareTo((Comparable)super.right.eval(b)) > 0;$ ^% q* u2 A. ~% m( Z
  }& n. _( R  I3 `/ Z
}* |, h  @( E, [
class IdNode implements Node {
0 R1 y3 F; d; b: K  final String id;
- o  H: W: E8 U6 @  IdNode(String i) {2 m  U2 J2 |' H5 }$ W
    id = i;
. P$ l6 c$ G. s3 }) m# j: j3 g  }
: c* d+ A% O9 v7 @! y  @Override( R6 F8 [) e! s9 o* d4 e1 L
  public Object eval(B b) {. Z$ v. Y# Z  ^1 Q% Q5 E
    return b.getAttribute(id);" t- S) \* f3 A8 x. y
  }
! Z7 b' i7 A. \6 q" |}6 ], Q3 v/ x4 m
class SelectNode implements Node {, z& I" i2 O  B+ K" C6 \# A5 Y
  final List attributes;2 T8 R# r0 [0 @6 u$ N% r
  final List[B] data;
7 M& P2 e* b+ e6 c% D8 l  final Node expression;
5 D! M$ p) f; p/ i9 b7 g  SelectNode(List a, List[B] d, Node e) {, Y" i; J* @; f# M- \* H
    attributes = a;- [  t, l) |4 l& ?0 \
    data = d;7 B/ h! ]# L5 i+ i
    expression = e;
* i" `0 ~$ D: G" B3 J1 k: `  }
) G' |) B. C6 O1 |+ u( z4 V$ S  @Override
0 B1 i4 W, z) A$ ^) h4 n  public Object eval(B ignored) {" f" h- b  X  x/ ]6 r
    List> result = new ArrayList>();' K, g- ]4 \8 ?2 C& j
    for(B b : data) {
( [% r' R% t& o" ?$ [      if((Boolean)expression.eval(b)) {
! O+ u4 b; d. Z, M        // 'b' passed, check which attributes to include+ _% z; h( R! S6 h( F
        List row = new ArrayList();
+ Z( S/ v* \0 T6 D0 q" i        for(String attr : attributes) {2 V7 |, h/ y3 Y! ^
          row.add(b.getAttribute(attr));
) |& ^$ T" Q/ ]/ ?# P2 }        }
5 K& V2 ]) Q+ E# h; p2 z. I9 O        result.add(row);2 o) C4 ~! A) q, g9 Y
      }
. B( ?; S4 l' d/ C' h8 r    }
  S: j( _; w, n, N3 Q6 Q0 y    return result;3 o% O# C( X: d# ~1 E& |
  }
+ X1 u4 Q0 v1 Y  i}
/ j* A# T! |0 T: Y5 b* f' p; \如果现在生成词法分析器,解析器和tree walker并运行Main类:$ M3 e* _# S* I5 k, N+ D0 E0 |
java -cp antlr-3.3.jar org.antlr.Tool Select.g
/ ~8 W& ?8 D- j& O2 e: W* ]' Mjava -cp antlr-3.3.jar org.antlr.Tool SelectWalker.g
0 W9 Z) D  A: R& Jjavac -cp antlr-3.3.jar *.java! B$ Z* B5 B! x1 p
java -cp .:antlr-3.3.jar Main' J7 N$ C/ B* m0 }$ J4 z6 @8 ]
您将看到查询的输出:
: e/ ^. t& H! _! p& c9 rselect C, Y from poolX where X = 45 AND Y > '88' AND Z != 'abc';
( Z3 f, G9 H; h输入:
" i8 s4 c6 E, H5 v) DC           X       Y       Z
/ j4 l) l; e" t1 A4 |5 O"id_1"      345     "89"    "abd"1 E" h8 |2 I7 v8 i+ Z
"id_2"      45      "89"    "abd"- ]# w/ F. I0 C) E% l9 Z. D
"id_3"      1       "89"    "abd"
( k* D$ ]3 t* [! X$ d  V"id_4       45      "8"     "abd"1 j2 h: ?& m! H7 l
"id_5"      45      "89"    "abc"
- \7 C4 e4 S& `5 b; H5 y6 ["id_6"      45      "99"    "abC"
$ k( B* @* ~9 P9 Z7 z是:/ ?1 E/ B3 [3 u8 b; a
[id_2, 89]
9 U2 \) e1 q$ T+ d[id_6, 99]( t7 b6 ^' M) g. |8 u; m
并注意,如果where省略该语句,1 = 1则会自动插入表达式,从而导致查询:: R4 B( W# B7 @  p2 C. A- e6 L
select C, Y from poolX;* c9 W( L3 |9 l5 c
打印以下内容:- L2 t( \1 M) e) D' \5 v
[id_1, 89], T$ b* F$ M- J$ P
[id_2, 89]
, @( o% {8 H" ?8 o[id_3, 89]( |# t2 N- T$ A) N% u3 G: P: q
[id_4, 8]
% B, P8 L$ @+ q1 ~3 k1 U$ M[id_5, 89]
: l% z- g( N3 D* j# Y[id_6, 99]

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则