11/12, 91«89101112»

[原]视觉模型心得

2008-6-6 13:59:05 开发者 抢沙发(0)

几次开发后一个很简单,但用处很广泛的视觉模型总结为一张图,如下:

身材研究---七头身和九头身

2008-5-31 23:58:59 开发者 抢沙发(0)

九头身意思就是头部的长度与身高的比例为1:9。

  这样是最好的身材比例!九头身就是身体的长度(除了头部)等于九个头的长度。通常很多国际名模都是九头身 。

  人家评论一个人的身材比例好,九头身是一个人人向往的比例,就是说身高是头高的九倍,头大个子矮是最不好看的。我最近看了林志玲的照片,发现她就是个九头身,高挑的身材,甜美的小脸。东亚人的身材平均比例是6.75头左右,欧美人是7.15头左右,男女平均差不多.一般来说,同身高的亚洲人身材比例要比同身高的欧美人来得好,同身高的女子身材比例要比同身高的男子来得好,这是前者比后者头小的缘故.当然这是一般来说,从人体美学来讲,净身长7个头是最接近于普通人的比例,看上去不长也不短.而美感最强的比例是净身长7.5--8个之间,净身长7.5头是好看的比例,而净身长8个头是黄金比例,是最完美的,古希腊伟大睿智的雕塑家早已发现8这个人体黄金比例数值,并创出许多令世人惊艳的震撼之作。


 

九头身一般指多高?


      9头身有多高.按照一个正常女性头长20CM来算的话,就应该是180CM.现在的模特,大概都是这个身高~当然如果头小的话,可以不用那么高也达到9头身.正常人,也就是平日目测感觉最好的头身比例应该是一比8.5。也就是20CM的头部的女人身高一米70。
 

来源:

http://baike.baidu.com/view/1295471.htm

  20世纪以来,日本动漫界出现了一些用九头身的比例来塑造人物,很有视觉震撼力的美感,但如果放到现实里,实际上的九头身是很难看的,或者说是很恐怖,因为净身长8.5头,9头显得整个身材比例很失调.而且现实中,拥有这样比例的人是极少见的.所以对于大多数人而言是身材平均比例不够长的问题,而不是太长的问题了. 那至于现在九头身的比例是完美比例之说而不是八头身是为什么呢?这是因为所谓的九头身,吴佩慈也好,林志玲也好,实际净身长是不足八头的,九头是用脸代替头切割的效果,净身长7.5头以上的人都有这个效果(净身长7.5头以上就是美的比例了),即称之九头身(九脸身太难听了),像吴佩慈,林志玲,萧淑慎全智贤等等都是净身长7.5头以上的好身材,故称为九头身美女了. 志玲姐姐的头长是22.5cm左右,175cm的她净身长近7.8头,穿上8厘米的走秀标准舞台鞋后就可以达到181或182了,即刚好黄金八头身,完美修长!

  这就是志玲姐姐作为一个走T台的模特不算高,却可以修长得那么完美的原因之一!还有纤细的骨架,很多身材比例都接近于黄金比例0.618也是原因啊。
 

体型研究---男性

2008-5-31 23:39:08 开发者 抢沙发(0)

1.肩部大於臀部類型

2.肩部與臀部相當類型

3.肩部小於臀部類型

4.肥胖體型 

5.腿短而彎曲

6.凸肚體型 

7.矮瘦平臀型

8.腿短且豐臀  

9.臉大且脖短粗型 

10.肩寬斜且手臂粗

11.臀突且圓背

体型研究---女性数据

2008-5-31 23:35:28 开发者 抢沙发(0)

所谓的女人完美体型标准是什么?

  上、下身比例:以肚脐为界,上下身比例应为5:8,符合“黄金分割”定律。

  颈围:在颈的中部最细处。颈围与小腿围相等。

  上臂围:在肩关节与肘关节之间的中部。上臂围等于大腿围的一半。

  胸围:由腋下沿胸部的上方最丰满处。胸围应为身高的一半。

  腰围:在正常情况下,腰的最细部位。腰围较胸围小20厘米。

  髋围:在体前耻骨平行于臀部最大部位。髋围较胸围大4厘米。

  大腿围:在大腿最上部位的臀折线下。大腿围较腰围小10厘。

  小腿围:在小腿最丰满处。小腿围较大腿围小20厘米。

  足颈围:在足颈的最细部位。足颈围较小腿围小10厘米。

非标准体型研究--女性

2008-5-31 23:07:16 开发者 抢沙发(0)

很显然可以看出不同基型角点在什么位置。

虽然都属于上半身变化,但依次可以做出人体2D正面模型了

SQLite B+树实现代码

2008-5-13 2:10:49 开发者 抢沙发(0)

 from: http://www.sqlite.com.cn/MySqlite/6/373.Html

C++代码
  1. /* btrees.h */    
  2. /*   
  3. * 平衡多路树的一种重要方案。   
  4. * 在 1970 年由 R. Bayer 和 E. McCreight 发明。   
  5. */    
  6. #define M 1    
  7. /* B 树的阶,即非根节点中键的最小数目。   
  8. * 有些人把阶定义为非根节点中子树的最大数目。   
  9. */    
  10. typedef int typekey;    
  11. typedef struct btnode { /* B-Tree 节点 */    
  12. int d; /* 节点中键的数目 */    
  13. typekey k[2*M]; /* 键 */    
  14. char *v[2*M]; /* 值 */    
  15. struct btnode *p[2*M+1]; /* 指向子树的指针 */    
  16. } node, *btree;    
  17. /*   
  18. * 每个键的左子树中的所有的键都小于这个键,   
  19. * 每个键的右子树中的所有的键都大于等于这个键。   
  20. * 叶子节点中的每个键都没有子树。   
  21. */    
  22.   
  23. /* 当 M 等于 1 时也称为 2-3 树   
  24. * +----+----+   
  25. * | k0 | k1 |   
  26. * +-+----+----+---   
  27. * | p0 | p1 | p2 |   
  28. * +----+----+----+   
  29. */    
  30. extern int btree_disp; /* 查找时找到的键在节点中的位置 */    
  31. extern char * InsValue; /* 与要插的键相对应的值 */    
  32.   
  33. extern btree search(typekey, btree);    
  34. extern btree insert(typekey,btree);    
  35. extern btree delete(typekey,btree);    
  36. extern int height(btree);    
  37. extern int count(btree);    
  38. extern double payload(btree);    
  39. extern btree deltree(btree);    
  40. /* end of btrees.h */    
  41.   
  42. /*******************************************************/  
C++代码
  1. /*******************************************************/    
  2.   
  3. /* btrees.c */    
  4. #include    
  5. #include    
  6. #include "btrees.h"    
  7.   
  8. btree search(typekey, btree);    
  9. btree insert(typekey,btree);    
  10. btree delete(typekey,btree);    
  11. int height(btree);    
  12. int count(btree);    
  13. double payload(btree);    
  14. btree deltree(btree);    
  15.   
  16. static void InternalInsert(typekey, btree);    
  17. static void InsInNode(btree, int);    
  18. static void SplitNode(btree, int);    
  19. static btree NewRoot(btree);    
  20.   
  21. static void InternalDelete(typekey, btree);    
  22. static void JoinNode(btree, int);    
  23. static void MoveLeftNode(btree t, int);    
  24. static void MoveRightNode(btree t, int);    
  25. static void DelFromNode(btree t, int);    
  26. static btree FreeRoot(btree);    
  27.   
  28. static btree delall(btree);    
  29. static void Error(int,typekey);    
  30.   
  31. int btree_disp; /* 查找时找到的键在节点中的位置 */    
  32. char * InsValue = NULL; /* 与要插的键相对应的值 */    
  33. static int flag; /* 节点增减标志 */    
  34. static int btree_level = 0; /* 多路树的高度 */    
  35. static int btree_count = 0; /* 多路树的键总数 */    
  36. static int node_sum = 0; /* 多路树的节点总数 */    
  37. static int level; /* 当前访问的节点所处的高度 */    
  38. static btree NewTree; /* 在节点分割的时候指向新建的节点 */    
  39. static typekey InsKey; /* 要插入的键 */    
  40.   
  41. btree search(typekey key, btree t)    
  42. {    
  43. int i,j,m;    
  44. level=btree_level-1;    
  45. while (level >= 0){    
  46. for(i=0, j=t->d-1; i t->k[m])?(i=m+1):(j=m));    
  47. if (key == t->k){    
  48. btree_disp = i;    
  49. return t;    
  50. }    
  51. if (key > t->k) /* i == t->d-1 时有可能出现 */    
  52. i++;    
  53. t = t->p;    
  54. level--;    
  55. }    
  56. return NULL;    
  57. }    
  58.   
  59. btree insert(typekey key, btree t)    
  60. {    
  61. level=btree_level;    
  62. InternalInsert(key, t);    
  63. if (flag == 1) /* 根节点满之后,它被分割成两个半满节点 */    
  64. t=NewRoot(t); /* 树的高度增加 */    
  65. return t;    
  66. }    
  67.   
  68. void InternalInsert(typekey key, btree t)    
  69. {    
  70. int i,j,m;    
  71.   
  72. level--;    
  73. if (level < 0){ /* 到达了树的底部: 指出要做的插入 */    
  74. NewTree = NULL; /* 这个键没有对应的子树 */    
  75. InsKey = key; /* 导致底层的叶子节点增加键值+空子树对 */    
  76. btree_count++;    
  77. flag = 1; /* 指示上层节点把返回的键插入其中 */    
  78. return;    
  79. }    
  80. for(i=0, j=t->d-1; i t->k[m])?(i=m+1):(j=m));    
  81. if (key == t->k) {    
  82. Error(1,key); /* 键已经在树中 */    
  83. flag = 0;    
  84. return;    
  85. }    
  86. if (key > t->k) /* i == t->d-1 时有可能出现 */    
  87. i++;    
  88. InternalInsert(key, t->p);    
  89.   
  90. if (flag == 0)    
  91. return;    
  92. /* 有新键要插入到当前节点中 */    
  93. if (t->d < 2*M) {/* 当前节点未满 */    
  94. InsInNode(t, i); /* 把键值+子树对插入当前节点中 */    
  95. flag = 0; /* 指示上层节点没有需要插入的键值+子树,插入过程结束 */    
  96. }    
  97. else /* 当前节点已满,则分割这个页面并把键值+子树对插入当前节点中 */    
  98. SplitNode(t, i); /* 继续指示上层节点把返回的键值+子树插入其中 */    
  99. }    
  100.   
  101. /*   
  102. * 把一个键和对应的右子树插入一个节点中   
  103. */    
  104. void InsInNode(btree t, int d)    
  105. {    
  106. int i;    
  107. /* 把所有大于要插入的键值的键和对应的右子树右移 */    
  108. for(i = t->d; i > d; i--){    
  109. t->k = t->k[i-1];    
  110. t->v = t->v[i-1];    
  111. t->p[i+1] = t->p;    
  112. }    
  113. /* 插入键和右子树 */    
  114. t->k = InsKey;    
  115. t->p[i+1] = NewTree;    
  116. t->v = InsValue;    
  117. t->d++;    
  118. }    
  119. /*   
  120. * 前件是要插入一个键和对应的右子树,并且本节点已经满   
  121. * 导致分割这个节点,插入键和对应的右子树,   
  122. * 并向上层返回一个要插入键和对应的右子树   
  123. */    
  124. void SplitNode(btree t, int d)    
  125. {    
  126. int i,j;    
  127. btree temp;    
  128. typekey temp_k;    
  129. char *temp_v;    
  130. /* 建立新节点 */    
  131. temp = (btree)malloc(sizeof(node));    
  132. /*   
  133. * +---+--------+-----+-----+--------+-----+   
  134. * | 0 | ...... | M | M+1 | ...... |2*M-1|   
  135. * +---+--------+-----+-----+--------+-----+   
  136. * |<- M+1 ->|<- M-1 ->|   
  137. */    
  138. if (d > M) { /* 要插入当前节点的右半部分 */    
  139. /* 把从 2*M-1 到 M+1 的 M-1 个键值+子树对转移到新节点中,   
  140. * 并且为要插入的键值+子树空出位置 */    
  141. for(i=2*M-1,j=M-1; i>=d; i--,j--) {    
  142. temp->k[j] = t->k;    
  143. temp->v[j] = t->v;    
  144. temp->p[j+1] = t->p[i+1];    
  145. }    
  146. for(i=d-1,j=d-M-2; j>=0; i--,j--) {    
  147. temp->k[j] = t->k;    
  148. temp->v[j] = t->v;    
  149. temp->p[j+1] = t->p[i+1];    
  150. }    
  151. /* 把节点的最右子树转移成新节点的最左子树 */    
  152. temp->p[0] = t->p[M+1];    
  153. /* 在新节点中插入键和右子树 */    
  154. temp->k[d-M-1] = InsKey;    
  155. temp->p[d-M] = NewTree;    
  156. temp->v[d-M-1] = InsValue;    
  157. /* 设置要插入上层节点的键和值 */    
  158. InsKey = t->k[M];    
  159. InsValue = t->v[M];    
  160.   
  161. }    
  162. else { /* d <= M */    
  163. /* 把从 2*M-1 到 M 的 M 个键值+子树对转移到新节点中 */    
  164. for(i=2*M-1,j=M-1; j>=0; i--,j--) {    
  165. temp->k[j] = t->k;    
  166. temp->v[j] = t->v;    
  167. temp->p[j+1] = t->p[i+1];    
  168. }    
  169. if (d == M) /* 要插入当前节点的正中间 */    
  170. /* 把要插入的子树作为新节点的最左子树 */    
  171. temp->p[0] = NewTree;    
  172. /* 直接把要插入的键和值返回给上层节点 */    
  173. else { /* (d /* 把节点当前的最右子树转移成新节点的最左子树 */    
  174. temp->p[0] = t->p[M];    
  175. /* 保存要插入上层节点的键和值 */    
  176. temp_k = t->k[M-1];    
  177. temp_v = t->v[M-1];    
  178. /* 把所有大于要插入的键值的键和对应的右子树右移 */    
  179. for(i=M-1; i>d; i--) {    
  180. t->k = t->k[i-1];    
  181. t->v = t->v[i-1];    
  182. t->p[i+1] = t->p;    
  183. }    
  184. /* 在节点中插入键和右子树 */    
  185. t->k[d] = InsKey;    
  186. t->p[d+1] = NewTree;    
  187. t->v[d] = InsValue;    
  188. /* 设置要插入上层节点的键和值 */    
  189. InsKey = temp_k;    
  190. InsValue = temp_v;    
  191. }    
  192. }    
  193. t->d =M;    
  194. temp->d = M;    
  195. NewTree = temp;    
  196. node_sum++;    
  197. }    
  198.   
  199. btree delete(typekey key, btree t)    
  200. {    
  201. level=btree_level;    
  202. InternalDelete(key, t);    
  203. if (t->d == 0)    
  204. /* 根节点的子节点合并导致根节点键的数目随之减少,   
  205. * 当根节点中没有键的时候,只有它的最左子树可能非空 */    
  206. t=FreeRoot(t);    
  207. return t;    
  208. }    
  209.   
  210. void InternalDelete(typekey key, btree t)    
  211. {    
  212. int i,j,m;    
  213. btree l,r;    
  214. int lvl;    
  215.   
  216. level--;    
  217. if (level < 0) {    
  218. Error(0,key); /* 在整个树中未找到要删除的键 */    
  219. flag = 0;    
  220. return;    
  221. }    
  222. for(i=0, j=t->d-1; i t->k[m])?(i=m+1):(j=m));    
  223. if (key == t->k) { /* 找到要删除的键 */    
  224. if (t->v != NULL)    
  225. free(t->v); /* 释放这个节点包含的值 */    
  226. if (level == 0) { /* 有子树为空则这个键位于叶子节点 */    
  227. DelFromNode(t,i);    
  228. btree_count--;    
  229. flag = 1;    
  230. /* 指示上层节点本子树的键数量减少 */    
  231. return;    
  232. else { /* 这个键位于非叶节点 */    
  233. lvl = level-1;    
  234. /* 找到前驱节点 */    
  235. r = t->p;    
  236. while (lvl > 0) {    
  237. r = r->p[r->d];    
  238. lvl--;    
  239. }    
  240. t->k=r->k[r->d-1];    
  241. t->v=r->v[r->d-1];    
  242. r->v[r->d-1]=NULL;    
  243. key = r->k[r->d-1];    
  244. }    
  245. }    
  246. else if (key > t->k) /* i == t->d-1 时有可能出现 */    
  247. i++;    
  248. InternalDelete(key,t->p);    
  249. /* 调整平衡 */    
  250. if (flag == 0)    
  251. return;    
  252. if (t->p->d < M) {    
  253. if (i == t->d) /* 在最右子树中发生了删除 */    
  254. i--; /* 调整最右键的左右子树平衡 */    
  255. l = t->p;    
  256. r = t->p[i+1];    
  257. if (r->d > M)    
  258. MoveLeftNode(t,i);    
  259. else if(l->d > M)    
  260. MoveRightNode(t,i);    
  261. else {    
  262. JoinNode(t,i);    
  263. /* 继续指示上层节点本子树的键数量减少 */    
  264. return;    
  265. }    
  266. flag = 0;    
  267. /* 指示上层节点本子树的键数量没有减少,删除过程结束 */    
  268. }    
  269. }    
  270.   
  271. /*   
  272. * 合并一个节点的某个键对应的两个子树   
  273. */    
  274. void JoinNode(btree t, int d)    
  275. {    
  276. btree l,r;    
  277. int i,j;    
  278. l = t->p[d];    
  279. r = t->p[d+1];    
  280.   
  281. /* 把这个键下移到它的左子树 */    
  282. l->k[l->d] = t->k[d];    
  283. l->v[l->d] = t->v[d];    
  284. /* 把右子树中的所有键值和子树转移到左子树 */    
  285. for (j=r->d-1,i=l->d+r->d; j >= 0 ; j--,i--) {    
  286. l->k = r->k[j];    
  287. l->v = r->v[j];    
  288. l->p = r->p[j];    
  289. }    
  290. l->p[l->d+r->d+1] = r->p[r->d];    
  291. l->d += r->d+1;    
  292. /* 释放右子树的节点 */    
  293. free(r);    
  294. /* 把这个键右边的键和对应的右子树左移 */    
  295. for (i=d; i < t->d-1; i++) {    
  296. t->k = t->k[i+1];    
  297. t->v = t->v[i+1];    
  298. t->p[i+1] = t->p[i+2];    
  299. }    
  300. t->d--;    
  301. node_sum--;    
  302. }    
  303. /*   
  304. * 从一个键的右子树向左子树转移一些键,使两个子树平衡   
  305. */    
  306. void MoveLeftNode(btree t, int d)    
  307. {    
  308. btree l,r;    
  309. int m; /* 应转移的键的数目 */    
  310. int i,j;    
  311. l = t->p[d];    
  312. r = t->p[d+1];    
  313. m = (r->d - l->d)/2;    
  314.   
  315. /* 把这个键下移到它的左子树 */    
  316. l->k[l->d] = t->k[d];    
  317. l->v[l->d] = t->v[d];    
  318. /* 把右子树的最左子树转移成左子树的最右子树   
  319. * 从右子树向左子树移动 m-1 个键+子树对 */    
  320. for (j=m-2,i=l->d+m-1; j >= 0; j--,i--) {    
  321. l->k = r->k[j];    
  322. l->v = r->v[j];    
  323. l->p = r->p[j];    
  324. }    
  325. l->p[l->d+m] = r->p[m-1];    
  326. /* 把右子树的最左键提升到这个键的位置上 */    
  327. t->k[d] = r->k[m-1];    
  328. t->v[d] = r->v[m-1];    
  329. /* 把右子树中的所有键值和子树左移 m 个位置 */    
  330. r->p[0] = r->p[m];    
  331. for (i=0; id-m; i++) {    
  332. r->k = r->k[i+m];    
  333. r->v = r->v[i+m];    
  334. r->p = r->p[i+m];    
  335. }    
  336. r->p[r->d-m] = r->p[r->d];    
  337. l->d+=m;    
  338. r->d-=m;    
  339. }    
  340. /*   
  341. * 从一个键的左子树向右子树转移一些键,使两个子树平衡   
  342. */    
  343. void MoveRightNode(btree t, int d)    
  344. {    
  345. btree l,r;    
  346. int m; /* 应转移的键的数目 */    
  347. int i,j;    
  348. l = t->p[d];    
  349. r = t->p[d+1];    
  350.   
  351. m = (l->d - r->d)/2;    
  352. /* 把右子树中的所有键值和子树右移 m 个位置 */    
  353. r->p[r->d+m]=r->p[r->d];    
  354. for (i=r->d-1; i>=0; i--) {    
  355. r->k[i+m] = r->k;    
  356. r->v[i+m] = r->v;    
  357. r->p[i+m] = r->p;    
  358. }    
  359. /* 把这个键下移到它的右子树 */    
  360. r->k[m-1] = t->k[d];    
  361. r->v[m-1] = t->v[d];    
  362. /* 把左子树的最右子树转移成右子树的最左子树 */    
  363. r->p[m-1] = l->p[l->d];    
  364. /* 从左子树向右子树移动 m-1 个键+子树对 */    
  365. for (i=l->d-1,j=m-2; j>=0; j--,i--) {    
  366. r->k[j] = l->k;    
  367. r->v[j] = l->v;    
  368. r->p[j] = l->p;    
  369. }    
  370. /* 把左子树的最右键提升到这个键的位置上 */    
  371. t->k[d] = l->k;    
  372. t->v[d] = l->v;    
  373. l->d-=m;    
  374. r->d+=m;    
  375. }    
  376. /*   
  377. * 把一个键和对应的右子树从一个节点中删除   
  378. */    
  379. void DelFromNode(btree t, int d)    
  380. {    
  381. int i;    
  382. /* 把所有大于要删除的键值的键左移 */    
  383. for(i=d; i < t->d-1; i++) {    
  384. t->k = t->k[i+1];    
  385. t->v = t->v[i+1];    
  386. }    
  387. t->d--;    
  388. }    
  389. /*   
  390. * 建立有两个子树和一个键的根节点   
  391. */    
  392. btree NewRoot(btree t)    
  393. {    
  394. btree temp;    
  395. temp = (btree)malloc(sizeof(node));    
  396. temp->d = 1;    
  397. temp->p[0] = t;    
  398. temp->p[1] = NewTree;    
  399. temp->k[0] = InsKey;    
  400. temp->v[0] = InsValue;    
  401. btree_level++;    
  402. node_sum++;    
  403. return(temp);    
  404. }    
  405. /*   
  406. * 释放根节点,并返回它的最左子树   
  407. */    
  408. btree FreeRoot(btree t)    
  409. {    
  410. btree temp;    
  411. temp = t->p[0];    
  412. free(t);    
  413. btree_level--;    
  414. node_sum--;    
  415. return temp;    
  416. }    
  417.   
  418. void Error(int f,typekey key)    
  419. {    
  420. if (f)    
  421. printf("Btrees error: Insert %d! ",key);    
  422. else    
  423. printf("Btrees error: delete %d! ",key);    
  424. }    
  425.   
  426. int height(btree t)    
  427. {    
  428. return btree_level;    
  429. }    
  430.   
  431. int count(btree t)    
  432. {    
  433. return btree_count;    
  434. }    
  435. double payload(btree t)    
  436. {    
  437. if (node_sum==0)    
  438. return 1;    
  439. return (double)btree_count/(node_sum*(2*M));    
  440. }    
  441. btree deltree (btree t)    
  442. {    
  443. level=btree_level;    
  444. btree_level = 0;    
  445. return delall(t);    
  446.   
  447. }    
  448. btree delall(btree t)    
  449. {    
  450. int i;    
  451. level--;    
  452. if (level >= 0) {    
  453. for (i=0; i < t->d; i++)    
  454. if (t->v != NULL)    
  455. free(t->v);    
  456. if (level > 0)    
  457. for (i=0; i<= t->d ; i++)    
  458. t->p=delall(t->p);    
  459. free(t);    
  460. }    
  461. return NULL;    
  462. }    
  463.   
  464. /* end of btrees.c */   

SQLite的SQL语法---select

2008-5-13 1:57:03 开发者 抢沙发(0)

SELECT

sql-statement ::= SELECT [ALL | DISTINCT] result [FROM table-list]
[WHERE expr]
[GROUP BY expr-list]
[HAVING expr]
[compound-op select]*
[ORDER BY sort-expr-list]
[LIMIT integer [( OFFSET | , ) integer]]
result ::= result-column [, result-column]*
result-column ::= * | table-name . * | expr [ [AS] string ]
table-list ::= table [join-op table join-args]*
table ::= table-name [AS alias] |
(
select ) [AS alias]
join-op ::= , | [NATURAL] [LEFT | RIGHT | FULL] [OUTER | INNER | CROSS] JOIN
join-args ::= [ON expr] [USING ( id-list )]
sort-expr-list ::= expr [sort-order] [, expr [sort-order]]*
sort-order ::= [ COLLATE collation-name ] [ ASC | DESC ]
compound_op ::= UNION | UNION ALL | INTERSECT | EXCEPT
11/12, 91«89101112»