可以
方法一
1
sqlserver
2
select
a/b,a+b,ab
数字类型的计算,可以直接这样写的
3
方法二
1
select
aa/bb,aa+bb
2
from
a
left
join
b
on
ac=bc
3
transact-sql介绍
transact-sql语言是用在微软的sql
server
的关系型数据库管理系统中编程语言。
4
主要有六大类:
算术运算符、赋值运算符、位运算符、比较运算符、逻辑运算符和字符串联运算符。
1
算术运算符包括(+)、减(-)、乘()、除(/)和取模(%)
2
赋值运算符"="
3
位运算符
"
&
^
|"
4
比较运算符
=、>、<、>=、<=、<>、!=、!>、!<
5
逻辑运算符
and、or、not
6
字符串联运算符
+
你好,我帮你找到下面的资料,希望对你有帮助。
下面主要的内容:
(1)、计算机四级考纲
(2)、计算机四级考试通关攻略
(3)、计算机四级复习方法:
(4)、计算机四级考试词汇
(1)、计算机四级考纲
一、计算机系统组成及工作原理
⒈计算机系统组成:
⑴计算机的发展。
⑵计算机的分类及应用。
⑶计算机硬件结构。
⑷主要部件功能。
⑸计算机软件的功能与分类。
⑹系统软件与应用软件。
⒉计算机工作原理:
⑴计算机中数的表示。
⑵运算器。
⑶控制器。
⑷存储器。
⑸输入与输出系统。
⒊计算机的主要性能:
⑴计算机系统性能指标。
⑵处理机指标。
⑶存储容量能力。
⑷I/O总线能力。
⑸系统通信能力。
⑹联机事务处理能力。
⑺软件支持。
二、数据结构与算法
⒈基本概念:
⑴数据结构的基本概念。
⑵算法的描述与分析。
⒉线性表:
⑴线性表的逻辑结构。
⑵线性表的顺序存储结构。
⑶线性表的链式存储结构。
⒊数组:
⑴数组的定义与运算。
⑵数组的顺序存储结构。
⑶矩阵的压缩存储。
⒋栈与队列:
⑴栈的定义和运算。
⑵栈的存储结构。
⑶队列的定义和运算。
⑷链队列与循环队列。
⒌串:
⑴串及其 *** 作。
⑵串的存储结构。
⒍树和二叉树:
⑴树的定义。
⑵二叉树的定义及性质。
⑶二叉树与树的转换。
⑷二叉树的存储。
⑸遍历二叉树与线索二叉树。
⒎图:
⑴图及其存储结构。
⑵图的遍历。
⑶图的连通性。
⑷有向无环图。
⑸最短路径。
⑹拓扑排序。
⒏查找:
⑴线性表查找。
⑵树形结构与查找。
⑶散列查找。
⒐排序:
⑴插入排序。
⑵交换排序。
⑶选择排序。
⑷归并排序。
⑸基数排序。
⒑文件组织:
⑴顺序文件。
⑵索引文件。
⑶散列文件。
三、离散数学
⒈数理逻辑:
⑴命题及其符号化。
⑵命题公式及其分类。
⑶命题逻辑等值演算。
⑷范式。
⑸命题逻辑推理理论。
⑹谓词与量词。
⑺谓词公式与解释。
⑻谓词公式的分类。
⑼谓词逻辑等值演算与前束范式。
⑽谓词逻辑推理理论。
⒉集合论:
⑴集合及其表示。
⑵集合的运算。
⑶有序对与笛卡尔积。
⑷关系及其表示法。
⑸关系的运算。
⑹关系的性质。
⑺关系的闭包。
⑻复合关系与逆关系。
⑼等价关系与偏序关系。
⑽函数及其性质。
⑾反函数与复合函数。
⒊代数系统:
⑴代数运算及其性质。
⑵同态与同构。
⑶半群与群。
⑷子群与陪集。
⑸正规子群与商群。
⑹循环群与置换群。
⑺环与域。
⑻格与布尔代数。
⒋图论:
⑴无向图与有向图。
⑵路、回路与图的连通性。
⑶图的矩阵表示。
⑷最短路径与关键路径。
⑸二部图。
⑹欧拉图与哈密尔顿图。
⑺平面图。
⑻树与生成树。
⑼根树及其应用。
四、 *** 作系统
⒈ *** 作系统的基本概念:
⑴ *** 作系统的功能。
⑵ *** 作系统的基本类型。
⑶ *** 作系统的组成。
⑷ *** 作系统的接口。
⒉进程管理:
⑴进程、线程与进程管理。
⑵进程控制。
⑶进程调度。
⑷进程通信。
⑸死锁。
⒊作业管理:
⑴作业与作业管理。
⑵作业状态及其转换。
⑶作业调度。
⑷作业控制。
⒋存储管理:
⑴存储与存储管理。
⑵虚拟存储原理。
⑶页式存储。
⑷段式存储。
⑸段页式存储。
⑹局部性原理与工作集概念。
⒌文件管理:
⑴文件与文件管理。
⑵文件的分类。
⑶文件结构与存取方式。
⑷文件目录结构。
⑸文件存储管理。
⑹文件存取控制。
⑺文件的使用。
⒍设备管理:
⑴设备与设备分类。
⑵输入输出控制方式。
⑶中断技术。
⑷通道技术。
⑹设备分配技术与SPOOLING系统。
⑺磁盘调度。
⑻设备管理。
⒎一种典型 *** 作系统( DOS/Unix/Windows)的使用:
⑴DOS的特点与使用。
⑵UNIX的特点与使用。
⑶Windows的特点与使用。
五、软件工程
1软件工程基本概念:
⑴软件与软件危机。
⑵软件生命周期与软件工程。
⑶软件开发技术与软件工程管理。
⑷软件开发方法与工具、环境。
2结构化生命周期方法 :
⑴瀑布模型。
⑵可行性研究与可行性研究报告。
⑶软件计划与进度安排。
⑷软件需求分析。
⑸数据流程图(DFD)、数据字典(DD)。
⑹软件需求说明书。
⑺系统设计。
⑻概要设计与详细设计。
⑼模块结构设计与数据结构设计。
⑽接口设计与安全性设计。
⑾系统设计说明书。
⑿程序设计。
⒀程序设计语言。
⒁结构化程序设计。
3原型化方法:
⑴原型化的基本原理。
⑵原型化的生命周期。
⑶原型化的人员与工具。
⑷原型化的实施。
⑸原型化的项目管理。
⑹原型化方法与结构化方法的关系。
⒋软件测试:
⑴软件测试基本概念。
⑵软件测试方法。
⑶软件测试计划。
⑷单元测试、集成测试与系统测试。
⑸测试用例设计。
⑹测试分析报告。
⒌软件维护:
⑴软件可维护性。
⑵校正性维护。
⑶适应性维护。
⑷完善性维护。
⒍软件开发工具与环境:
⑴软件开发工具。
⑵软件开发环境。
⑶计算机辅助软件工程(CASE)。
⒎软件质量评价:
⑴软件质量的度量与评价模型。
⑵软件复杂性的度量。
⑶软件可靠性的评价。
⑷软件性能的评价。
⑸软件运行评价。
⒏软件管理:
⑴软件管理职能。
⑵软件开发组织。
⑶软件计划管理。
⑷标准化管理。
⑸软件工程国家标准。
⑹软件配置管理。
⑺软件产权保护。
六、数据库
⒈数据库基本概念:
⑴数据与数据模型。
⑵数据库体系结构。
⑶数据库管理系统与数据库系统。
⑷数据库工程与应用。
⒉关系数据库:
⑴关系数据库的基本概念。
⑵关系数据模型。
⑶关系定义、关系模型、关系模式与关系子模式。
⑷数据 *** 纵语言。
⑸关系代数。
⑹集合运算(并,差,交,笛卡尔积)与关系运算(投影,选择,连接)。
⑺关系演算。
⑻元组关系演算与域关系演算。
⑼数据库查询语言。
⑽SQL语言。
⒊关系数据库设计理论:
⑴关系数据理论。
⑵函数依赖。
⑶关系模式分解。
⑷关系模式的范式。
⒋数据库设计:
⑴数据库设计目标。
⑵数据库设计方法。
⑶数据库的设计步骤。
⑷数据库规划。
⑸需求分析。
⑹概念设计。
⑺逻辑设计。
⑻物理设计。
⑼数据库的实现与维护。
⒌数据库的保护:
⑴数据库恢复。
⑵数据库的完整性。
⑶数据库的并发控制。
⑷数据库的安全性。
⒍一种数据库管理系统(FoxPro/Oracle)应用:
⑴FoxPro DBMS的结构、特点及应用。
⑵Oracle DBMS的结构、特点及应用。
七、计算机体系统结构
⒈体系结构的基本概念:
⑴体系结构的定义。
⑵系统的功能层次。
⑶系统的分类。
⑷体系结构的继承与发展。
⑸系统的安全性。
⒉指令系统:
⑴指令格式及其优化。
⑵指令系统的复杂化。
⑶RISC技术。
⑷MIPS与MFLOPS。
⒊存储体系:
⑴存储层次。
⑵虚存工作原理。
⑶Cache工作原理。
⒋通道及新型部线:
⑴I/O方式的发展。
⑵通道工作原理。
⑶EISA与MCA。
⑷局部总线:VFSA与PCI。
⒌并行处理技术:
⑴流水线技术。
⑵超流水线与超标量技术。
⑶向量处理机。
⑷多机系统。
⒍系统性能评价:
⑴性能评价的概念。
⑵测试程序的分类。
⑶Benchmark的举例。
八、计算机网络与通信
⒈计算机网络的基本概念:
⑴网络的定义。⑵网络的分类。⑶网络的功能。⑷网络拓扑。 ⑸典型计算机网络组成。
⒉数据通信技术:
⑴数据通信的基本概念。
⑵数据通信系统的组成。
⑶传输介质的类型与特点。
⑷数据传输方式。
⑸数据编码方式。
⑹同步方式。
⑺线路复用技术。
⑻数据交换方式。
⑼差错控制方法。
⒊网络体系结构:
⑴网络体系结构的基本概念。
⑵ISO/OSI RM。
⑶物理层协议。
⑷数据链路层协议。
⑸网络层协议与X25网层次。
⑹传输层协议。
⑺高层协议。
⒋局域网技术:
⑴局域网拓扑。
⑵局域网传输介质。
⑶IEEE802模型与标准 。
⑷CSMA/CD工作原理。
⑸Token Bus工作原理。
⑹Token Ring工作原理。
⑺FDDI工作原理。
⑻局部网互连与TCP/IP协议。
⑼局域网 *** 作系统。
⑽避域网组网技术。
⑾局域网应用系统的安全性设计。
⒌网络技术的发展:
⑴高速局域网。
⑵ISDN与B-ISDN。
⑶城域网。
⑷帧中继。
⑸ATM技术。
⑹智能大厦与网络综合布线技术。
⑺Client/Server的应用技术。
⑻ISO网络管理概念与标准
(2)、计算机四级考试通关攻略
我于2000年通过了计算机四级考试,在备考的过程中有一些体会和感受,在这里将它们写下来,也许对各位备考的朋友有借鉴作用。
考试介绍
计算机四级考试是计算机等级考试最高级别的考试,考核计算机应用项目或应用系统的分析和设计的必备能力。它要求应试者具有计算机应用的基础知识、计算机 *** 作系统、软件工程和数据库系统的原理和应用知识,具有计算机系统结构、系统配置和性能评介的基础知识、计算机网络和通信的基础知识、计算机应用系统安全性和保密性知识。考试合格者能综合应用上述知识,并能从事应用项目(系统)开发,即具有项目分析、设计和实施能力。
应对考试,最重要的是先了解考试大纲,因为它包括了所有的考试内容,只有依照考纲来进行复习备考,才能做到有的放矢,节省时间和精力。考试复习应该依据“全国计算机等级考试四级考试大纲”来进行,它是最基本的考试指导。
备考指南
1 看书
首先需要把教材读透彻。教材最好选择国家考试中心指定的教材,如由教育部考试中心和高等教育出版社出版的《全国计算机等级考试考试大纲》和《全国计算机等级考试指导(四级)》。在初次学习教材的过程中应以通俗易懂为出发点,可打破教材安排,暂时回避困难问题,抓住主干,忽略小的细节,以掌握全书的理论体系及知识点为中心任务。
计算机硬件知识、软件知识和网络知识,如果以前接触过,只需要考前一个月进行强化记忆;如果没有接触过,则需要花半年左右的时间看书,大概了解一下知识点,这三个部分主要是识记内容。
数学水平仅仅通过识记是无法提高的,如果学过相关课程,只需要拾起书本,将习题演练一下就可以了。如果没有学过,那就必须老老实实看书了,而且要做一定量的习题。这个基础是非常重要的,也许很枯燥,但是只要你学进去了,一生都会受益。
英语知识的积累也没有诀窍,平时多看看英文的文章,可以看看《计算机专业英语》,多上网看看报纸,用英文原版的软件、看英文帮助文件都是培养英语能力的好习惯。
我用大概20天的时间进行了一下强化复习就顺利通过了考试,主要得益于我旁听了计算机专业的核心课程,《离散数学》、《数据结构》、《 *** 作系统》等,而且我平时坚持使用英文版的软件,有问题就查英文帮助,经常上网看英文期刊。所谓“厚积薄发,水到渠成”。
2 做习题
习题是检验对知识掌握程度的,考生不仅要达到能熟练做题的程度,更要明白题目中所考查的知识点是什么?难点何在?相类似的问题以后能否解决?做题目的过程中,可以把不清晰的题目汇集起来,在电脑上做实验。如果是程序题,就把程序输进电脑进行运行,看得出什么结果,与自己的思维结果是否有差异,这样便能深入发现一些技巧和加深对问题的理解。
下午是上机题,做上机题没有技巧,一定要多看题,多思考,多上机。这时可以做一些三级考试的历年试题,我自己当时是做完了三级考试的下午试题盘中的所有试题。自己先做,不会做再看参考的例程,想通了以后再上机实践,这样反复练习20多道题后,基本上就能达到考纲的要求。
3 模拟测试
检验自己的考试实力的最好方法是用全真模拟考试软件进行自测,然后针对不足部分重点进行复习。模拟考试软件是历届考试题的汇集,包括上机和笔试,基本上涵盖了考试的要求和题型。在读懂教材、做透习题、勤于上机的基础上,可以去看一些报刊和杂志,这样能够帮助自己开扩思路,把握考试脉搏,及时了解最新消息。
题型介绍
下面以我所参加的2000年的四级考试为例,为大家介绍一下四级考试中的基本题型和考试重点内容。
一、选择题 (共70题,每题1分,满分70分。其中1~55题为中文题,56~70题为英文题)。
题目不算太难,我在考纲中基本上都看到了,有几个新技术题,在《中国电脑教育报》和一些网站上见过,很快就答完了。
二、论述题 (四个论述题可任选其一,并只选其一,多选无效,满分30分)。
论述题1 数据库题:数据库概念设计和逻辑结构设计。
论述题2 软件工程题: 原型化方法与传统的结构化生命周期法各自的特点和内在联系。
论述题3 *** 作系统题:进程调度的主要功能及算法。
论述题4 计算机网络题:Internet网络层IP协议目前应用最为广泛。试根据你对IP协议的理解,讨论以下问题:
⑴ 论点1:Internet中没有两台或两台以上的主机或路由器可以同时使用同一个IP地址。论点1正确吗?为什么?(10分)
⑵ 论点2:连接在Internet中的一台主机或路由器只能有一个IP地址。论点2正确吗?为什么?(10分)
⑶ 有一台主机的IP地址是“1924125620”。你认为这个IP地址有没有错误。为什么?(10分)
我选取了最后一道题做答,因为关于IP地址的知识我非常有自信。
解答:
⑴ 论点1错误,因为同一时刻Internet上每台主机或路由器的IP地址是惟一的,不会出现两台或两台以上的主机或路由器使用同一个IP地址的情况。
⑵ 论点2正确,因为每台主机或路由器在不同时段可以有不同的IP地址,不同主机或路由器在不同时刻可以使用同一个IP地址。
⑶ 这个IP地址是错误的,因为IP地址是由四个8位二进制数字组成,转换为10进制就是0~255,题中出现了256,所以是错误的。
三、下午题
题目要求从200个数中取出符合不同条件的数进行计数、求和、求平均数。由于在三级试题库中接触过相同类型的题目,所以很轻松就搞定了。
注意:一定要存盘,否则会变为0分。当时跟我一个考场的不少同学就是因为慌乱忘记存盘,造成下午的考试没有通过。
(3)计算机四级复习方法:
复习过程中要扣住教材,按笔者的亲身经历,看三遍书的复习效果比较好。第一遍要通读教材,不要纠缠于艰难的部分,要注重于基础知识、基本概念。结合以前的知识,建立知识网络,注意各种原理的理解,不必太注意细节。所用的时间也不宜过长,一到两周时间就好。
第二遍是攻坚阶段,要结合手中的辅导书进行,一本好的辅导书会给你带来巨大的帮助,由于四级考试已经举行多年,各出版社出的辅导书内容都比较翔实。我强烈推荐大连理工出版社出版的《全国计算机等级考试题典(四级)》,这本书贴近考试,解答详尽。选好辅导书之后开始一章一章地作题,遇到不懂的部分就到教材相关的地方找答案,帮助自己理解和识记相关知识。复习过一章之后要整理一下本章的知识点。
最后一遍复习以辅导书为主,将辅导书从头到尾的看一遍,对辅导书中出现的知识作一下强化记忆,并开始每隔一两天作一套模拟题或以前的考题,最好是近五年以内的试题。最后一周结合教材把第二遍复习时整理的知识点看一看,主要是为论述题做准备。最后一轮复习对考试成绩影响最大,切不可掉以轻心,一定要认真对待。
奇怪了,找半天没找到考试大纲。只能上书店了,唉,偏偏到我要考试的时候换大纲,害得我前一阵子辛苦在学长那抢来的书都成了垃圾了!
(4)、计算机四级考试词汇
access 访问、存取、通路、进入
adjacency list method 邻接表表示法
adjacency matrix method 邻接矩阵表示法
algorithm 算法
array 数组
ATM(asynchronous transfer mode) 异步传输模式
b real programs kernels 实程序 核心程序
b toy benchmark synthetic benchmark 简单基准程序 复合基准程序
bandwidth 带宽
benchmark 基准测试程序
best - fit algorithm 最佳适应算法
BFS(breadth first search) 广度优先搜索法
binary 二进制
binary relation 二元关系
binary tree 二叉树
bit series 比特序列
black - box white - box 黑盒 白盒
block miss 块失效
blocked 阻塞(等待状态也称阻塞或封锁状态)
boundary 界线 分界
bridge 网桥
bubble sort 冒泡排序
candidate key 候选键(辅键)
capacity 容量
cartesian product 笛卡尔积
CASE(com aided sof engineering) 计算机辅助软件工程
CCP(communication control processor) 通信控制处理机
cell 信元
characteristic 特征 特性
circuit switching 线路交换
circular wait 循环等待
CISC(complex instruction set computer) 复杂指令集计算机
class 类
Client/Server 客户机/服务器
clock cycle/clock rate 时钟周期/时钟频率
coaxial cable 同轴电缆
cohesion/coupling 内聚/耦合
coincidental logical procedural functional 偶然内聚 逻辑内聚 过程内聚 功能内聚
communication 通信
complement number 补码
constrain 约束
contain 包含
correspond(corresponding) 相符合(相应的一致的)
CPETT 计算机性能评价工具与技术
CPI 每条指令需要的周期数
CSMA/CD 带冲突检测的载波监听多路访问
cursor 游标
cyclic redundancy check 循环冗余检验
database: integrity consistency re story 完整性 一致性 可恢复性
database: security efficiency 数据库设计的目标:安全性 效率
deadlock: mutual exclusion 死锁条件:互斥
deadlock: circular wait no preemption 死锁条件:循环等待 无优先权
decimal 十进位的
decision 决定 判断
decomposition 双重的 混合的
definition 定义
definition phase 定义阶段
design phase 设计阶段
DFS(depth first search) 深度优先搜索法
diagram 图表
Difference Manchester 差分曼彻斯特
directed graph/undirected graph 有向图/无向图
distributed system 分布式系统
divide union intersection difference 除 并 交 差
document 文件 文档
DQDB(distributed queue dual bus) 分布队列双总线
dual 二元的 双的
dynamic design process 动态定义过程
element 元素 要素
elevator(scan) algorithm 电梯算法(扫描算法)
encapsulation inheritance 封装(压缩)继承(遗传)
entity 实体
entity integrity rule 实体完整性规则
equation 方程式 等式
Ethernet 以太网
exchange sort 交换排序
exclusive locks 排它锁(X锁)
external(internal) fragmentation 外(内)碎片
fault page fault 中断 过错 页中断
FDDI(fiber distributed data interface) 光纤分布式数据接口
FDM(frequency division multiplexing) 频分多路复用
fiber optic cable 光缆
FIFO replacement policy 先进先出替换算法
figure 数字 图形
first normal form 第一范式
floppy 活动盘片(软盘)
foreign key domain tuple 外来键 值域 元组
formula 公式 表达式
frame page frame 帧 结构 页结构
frequency 频率
FTP 文件传送服务
function 函数
functionally dependant 函数依赖
gateway 网间连接器
general - purpose registers 通用寄存器
generate 产生
grade 等级 标准
graph(graphic) 图
Groper 将用户的请求自动转换成FTP
hash table/hash function/ collision 哈希表/哈希函数(散列函数)/碰撞
HDLC 面向比特型数据链路层协议
hit rate 命中率
host 主计算机
host language statement 主语言语句
hypertext 超级文本
index 索引
insertion sort 插入排序
instruction format 指令格式
instruction set 指令集
interface 接口 分界面 连接体
interrupt 中断
IPC 工业过程控制
ISAM VSAM 索引顺序存取方法 虚拟存储存取方法
join/natural join/semi join 连接/自然连接/半连接
kernel executive supervisor user 核心 执行 管理 用户
kernels 核心程序
key comparison 键(码)值比较
LAN(local area network) 局域网
load 负载 载入
logical functional 逻辑内聚 功能内聚
longitudinal 水平的
maintenance phase 维护(保养)阶段
MAN(metropolitan area network) 城域网
Manchester 曼彻斯特
map 地图 映射图
matrix 矩阵 点阵
memory reference 存储器参量
message switching 报文交换
MFLOP(million floating point operate per second) 每秒百万次浮点运算
MIPS(millions of instruction per second) 没秒百万条指令
module 单位 基准
monitor(model benchmark physical) mothod 监视 (模型 基准 物理)法
multilevel data flow chart 多层数据流图
multiple - term formula 多项式
multiplexing 多路复用技术
multiplication 乘法
mutual exclusion 互相 排斥
non - key attributes 非码属性
Nyquist 奈奎斯特
object oriented 对象 趋向的 使适应的
object oriented analysis 面向对象的分析
object oriented databases 面向对象数据库
object oriented design 面向对象的设计
object oriented implementation 面向对象的实现
occurrence 事件
one - dimensional array 一维数组
OODB(object oriented data base) 面向对象数据库
OOM(object oriented method) 面向对象的方法
oom: information object message class 信息 对象 消息 类
oom: instance method message passing 实例 方法消息传递
open system 开放系统
operand *** 作数
overflow 溢出
overlapping register windows 重叠寄存器窗口
packet switching 报文分组交换
page fault 页面失效
page replacement algorithm 页替换算法
paged segments 段页式管理
PCB(process control block) 进程控制块
peer entities 对等实体
period 时期 周期
phase 阶段 局面 状态
physical data link network layer 物理层 数据链路层 网络层
pipeline 管道
platter/track/cluster 面/磁道/簇
predicate 谓语
preemption 有优先权的
prefix(Polish form) 前缀(波兰表达式)
preorder/inorder/postorder 前序/中序/后序
presentation application layer 表示层 应用层
primary key attributes 主码属性
principle 原则 方法
procedural coincidental 过程内聚 偶然内聚
process 过程 加工 处理
program debugging 程序排错
projection selection join 投影 选择 连接
protocol 协议
prototype 原型 样板
prototyping method(model) 原型化周期(模型)
pseudo - code 伪码(程序设计语言PDL)
punctuation 标点
queue 队列
ready/blocked/running 就绪/阻塞(等待)/运行
real page number 实页数
real programs 实程序
redirected 重定向
redundancy 冗余
reference integrity rule 引用完整性规则
register(registry) 寄存器 登
数据库函数只有一个Dproduct可以求乘积,但也只是行与行的乘积,不能是列与列的乘积,你的问题只能这样解(A2:G17依次为你的数据,标题在第一行):
=SUMPRODUCT((A2:A17=I4)(B2:B17>=80)(B2:B17<=100)(F2:F17)G2:G17)
解决方案:
比如说表t,有三个int型字段xintyintzint要求实现z=xy那么,如果是SQLSERVER的话,可以写一个Job定时扫描表t,把xy的结果赋值给zJob要做的事情就是:updatetsetz=xywherexisnotnullandyisnotnull或者,在表t上建一个触发器,当满足x、y均有值的时候,把xy的结果更新给zaccess不清楚怎么创建Job或者触发器你可以写一个小程序,定时执行,用这个小程序去刷表t,更新z的值!
借助一些Excel公式,您可以在Excel的两种最广泛使用的表设计之间移动数据并自动将数据从源文件转换为更有用的形式。
越来越多的企业Excel用户将其报告和分析链接到Excel表。这样,他们可以在几秒钟而不是几小时内更新它们。
用户通常依赖两种类型的表来获取数据:垂直表和水平表。尽管每种表都有其优点,但是当您需要一种格式的数据但使用另一种格式的数据时,使用两种类型的表可能会带来挑战。
但是,使用三个Excel工作表功能将使您可以轻松地在这些表格式之间移动数据。
垂直Excel表垂直Excel表格
如果您拥有Excel 2007或更高版本,并且在一家拥有大量数据的公司中工作,您可能已经看到过类似此类的Excel表。
(我已在此页面上的大多数表格中间隐藏了大多数行和/或列,这使您可以看到表格的所有四个角。)
我将其称为“垂直表”,因为日期当然在垂直的列中。
该表的一般格式是从关系数据库获得的数据的典型格式。它有日期字段,键码和金额字段,每行都有很长的列。
请注意,该表没有代码说明,也没有有关每个代码的其他信息。这是因为如果关系数据库的表又高又瘦,则关系数据库以及Power Pivot for Excel的效率会大大提高。
Excel中关键代码的尺寸表
垂直尺寸查询表
要获取有关代码的其他信息,您必须从维查询表中提取数据,有点像这样。
下表显示了有关每个代码的两种信息。首先,它显示了描述。(当然,对您自己的数据的描述将提供更多信息。)
其次,此表具有一个乘法(“多”)列,通常以两种方式使用。
首先,一些外部数据(例如经济和股市数据)以数千或数百万为单位。因此,如果打算在内部使用此数据,将其转换为报表中的数据始终是一个好主意。在这里,代码C009的源数据总是成千上万,因此在报告中将其乘以1,000会将数据转换成一个。
其次,如果数据包含借方和贷方(借方为正数,贷方为负数),则将每个总帐帐户的值乘以其自然符号通常很有用。也就是说,您将应借记的帐户乘以1,将应贷记的帐户乘以-1。这样做时,每个带有自然符号的帐户都将变为正数,这通常使这些帐户更易于在报表中使用。
当然,从关系文件导出的数据通常包括描述和其他维度数据。但这并不总是一件好事。首先,由于许多描述可以重复很多次,因此您的工作簿变得比原来大得多。
其次,这些数据通常可能是不正确的,包括拼写错误的描述,奇怪的缩写,不寻常的大小写文本以及过时的信息。第三,可能不会包含您需要的某些尺寸数据,例如上面显示的“乘法”列。
因此,即使您从关系数据库下载的数据中获得了有关代码和其他关键项的信息,通常也最好维护自己的维查找表,就像上面的表一样。
水平“灰色单元”表
我的 Kyd作战室仪表板模板使用此水平表。由于行和列的边框为灰色,因此我将其称为灰色单元格表。
水平Excel表格
该表包含与前两个表相同的数据。您可以通过将其左上角和右下角数字与第一个表中的顶部和底部数字进行比较来确认这一点。
与竖直桌子相比,此桌子的设计具有多个优点。首先,设计将上述两个垂直表中的数据合并为一个水平表。因此,通常更容易设置和维护。
其次,如果您需要手动输入数据,或从其他来源复制并粘贴数据,则这种布局通常比关系样式表(如顶部Excel表)更易于管理。
但是,如果您的源数据来自关系样式的CSV文件或数据导入,则更新此表可能需要额外的工作。
您的桌面应该放在哪里?
如果您有 Kyd War Room,我建议您复制Dash_Data_Actxlsx工作簿,以用于以下讨论。如果您喜欢结果,可以将新版本换成旧版本。
通过这种方法,您的仪表板和其他报表仍可以从灰色单元数据库返回数据,该数据库可以使用链接到Excel Table的公式来获取其 数据。该表每个月都会通过快速复制和粘贴进行更新。
如何设置公式以从Excel表填充灰单元数据库
假设每个月您下载的数据看起来像下面左侧的蓝色表格,并且您想使用此数据填充右侧的灰色表格。更具体地说,假设您要设置2012年12月的数据,如下表所示。
从垂直Excel表更新水平表
步骤如下:
1在灰色单元格表中插入新列以包含新月的数据。例如,在这里,我插入了列BA来包含2012年12月的数据。
2将日期单元格从前一列复制到新列,然后根据需要更新日期。例如,在这里,我将单元格AZ2复制到单元格BA2,然后将日期更改为12/1/2012。
3将新月的数据添加到蓝色源表的底部,该表位于不同的工作表中,但与灰色数据表位于同一工作簿中。通常,您只需要复制数据导入或Excel中打开的CSV文件中的数据,然后粘贴到蓝色表格底部下方的第一行即可。
粘贴数据时,表格应自动展开以包括新数据。如果不是,请选择表中的任何单元格,然后选择“数据工具”,“设计”,“属性”,“调整大小表”,然后在“调整大小表”对话框中为表指定新的底部行。
4您将使用 SUMIFS函数从表中检索数字数据。如果您不熟悉此功能,则可能需要花费一分钟时间来浏览链接并继续阅读。这样做时,您会发现这是SUMIFS函数的语法:
SUMIFS(总和范围,标准范围,标准)
sum_range 必需。一个或多个要在行或列中求和的单元格,包括数字,范围名称或包含数字的单元格引用。空白和文本值将被忽略。
条件范围 。评估关联标准的第一个范围。条件范围中的错误值将被忽略。
要求的标准 。以数字,表达式,单元格引用或文本形式的条件,这些条件定义了将在Criteria_range1参数中添加哪些单元格。例如,标准可以表示为99,“> 99”,B4,“ sales”或“ 99”。
可选。重复对criterias_range和criterias参数对,总共为127对。
5在为以下公式显示的单元格中输入公式:
BA4:= SUMIFS(TableAct [Amount],TableAct [Codes],$ B4,TableAct [Date],BA $ 2)
这里
sum_range是TableAct [Amount]。 TableAct是我命名为蓝色Excel表格的名称,而 Amount是该表格中我将在其中找到所需编号的列的名称。也就是说,我希望SUMIFS函数从表的Amount列返回数据。
·条件范围1是 TableAct [Codes]。这是我决定使用的表格中的第一个条件列。
·条件1是$ B4,其值为C001。也就是说,在此行中,我希望SUMIFS函数仅在TableAct [Codes]中找到“ Code C001”的情况下返回数据。
·条件范围2是 TableAct [Date]。
·条件2为BA $ 2,价值为12/1/2012。也就是说,在本专栏中,我希望SUMIFS函数仅在TableAct [Date]中找到2018/12/1的情况下才返回数据。
5将该公式复制到上图所示的列中。
当然,如果要更新现有表,则可能只是从相邻列中复制公式列。
如何设置公式以使用维数据填充灰色单元数据库
上一组公式更新了灰单元数据库中的数字。但是我们显然不能使用和公式在此处的灰色单元格表格中填充描述字段。
相反,我们使用 INDEX 和MATCH 函数。
(在这个特定示例中,我们也可以使用 VLOOKUP函数。但是由于INDEX-MATCH比VLOOKUP灵活得多,而且速度通常更快,因此我从未在实际工作中使用VLOOKUP。)
假设您具有上面显示的灰色单元格表,并且想要在单元格C4中输入公式以从左侧的蓝色尺寸表返回正确的描述。为显示的单元格输入以下公式:
C4:= INDEX(TableDim [Desc],MATCH($ B4,TableDim [Code],0))
此处,INDEX函数从上图所示的蓝色TableDim表的Desc列返回数据。MATCH函数指定INDEX函数应返回哪个行索引号。
为了计算正确的行索引号,MATCH在TableDim表的“代码”字段中查找在单元格B4中输入的值(即“ C001”)。由于第三个参数为零,因此不需要对数据进行排序,如果未找到“ C001”,则MATCH将返回#N / A。但事实证明,C001是找到的第一项,因此MATCH返回值1。
因此,INDEX返回在蓝色表的Desc列中找到的第一个描述:“ C001 Act Desc”。
一个类似的公式返回Mult值:
D4:= IF(INDEX(TableDim [Mult],MATCH($ B4,TableDim [Code],0))= 0,“”,
INDEX(TableDim [Mult],MATCH($ B4,TableDim [Code],0) ))
(尽管此公式显示在两行中,但是您当然要在一行中输入它。)
在此公式中,第一个INDEX-MATCH节返回第4行的Mult值。如果该值通常为零,则该公式返回一个空字符串;否则,该公式将返回非零的Mult值。
如何设置公式以从灰色单元格表填充Excel表
我们还可以使用SUMIFS朝另一个方向发展。也就是说,我们可以使用它从灰色单元数据库填充Excel表。
要首次设置蓝色表格,我们首先需要设置“日期”和“代码”列的值。与在C列中设置公式相比,这样做所需的时间更长。
设置日期和代码值
1在新工作表中,输入右上方蓝色表格第2行中显示的三个列标题。
2从灰色单元格表中复制带有29个代码的区域,并将该区域粘贴到蓝色表中的单元格B3中。
3在单元格A3中输入日期1/1/2009,并将其向下复制到该列中,直到29个Codes为止。
4因为灰色单元数据库有48个月的数据,每个月有29个代码,所以蓝色表将具有1392(48 x 29)行数据。因此,请在C列中设置一个临时数字列作为参考,该列从1到1392。
为此,请在单元格C3中输入值1,然后按Ctrl + Shift +向下键以选择从C3到电子表格底部的所有单元格。现在选择“主页”,“编辑”,“填充”,“系列”。在“系列”对话框中,将“停止值”指定为1392,然后按OK ,这将为您提供数字列用作参考。
5将B列中的29个代码复制并粘贴到最后一个代码下面的第一个单元格中。这应该填充范围B32:B60。
6在表格中最后一个2009年1月下方的第一个单元格中,输入显示的单元格的公式
A32:= DATE(YEAR(A3),MONTH(A3)+1,1)
该公式返回2009年2月。将公式向下复制到范围A33:A60 ,与您刚刚粘贴的代码相邻。
7复制范围A32:B60,然后将其与您设置的计数器列平行粘贴。这是一种简单的方法:
·按Ctrl + C复制范围后,选择C列中的一个计数器单元格。
·按Ctrl +向下键可“滑动”至该数字列的底部。
·按两次向左箭头键,移至该底行的A列。
·按Ctrl + Shift +向上键将活动单元上方的所有单元格选择为A列中公式的最后一行。
·仅按住Shift键,然后按一次向下箭头键,以便仅选择空白单元格。
·按Ctrl + V粘贴到区域A61:B1394。
8将日期值和日期公式列更改为日期值。为此,请选择整个日期列。按Ctrl + C复制它们;按Ctrl + Alt + V启动“选择性粘贴”对话框;选择值,然后按确定。
现在,您可以输入从灰细胞数据库返回适当值的公式。在这里,我们为显示的单元格使用INDEX-MATCH-MATCH公式:
A3:= INDEX(例如ActData,MATCH($ B3,例如ActCodes,0),MATCH($ A3,例如ActDates,0))
该公式从为Kyd War Room仪表板模板设置的数据库中返回数据。该数据库使用范围名称(例如ActCodes,ActCodes和ActDates)指定可以找到数据,代码和日期的区域。
INDEX公式返回由两个MATCH函数指定的egActData范围内的值。第一个MATCH函数返回指定的Code值的行索引号,第二个MATCH函数返回指定的Date值的列索引号。
最后,既然普通表已经完成,您可以将其更改为Excel表。为此,选择表中的任何单元格,然后选择“插入”,“表”,“表”;在“创建表”对话框中,确保选中“ 我的表具有标题”;然后选择确定。
如何检查工作
我第一次设置这些表格和公式时,会“四舍五入”它们。也就是说,我从灰色单元格表开始,用链接到灰色单元格表的公式设置蓝色的Excel表,然后设置第二个带有链接到蓝色Excel表的公式的灰色单元格表。
最后,我建立了一个对帐表,该表对开始和结束的灰色单元格表进行了比较。这样,我确保所有公式都可以双向使用。
摘要 特定于领域的语言已经成为一个热门话题 很多函数性语言之所以受欢迎 主要是因为它们可以用于构建特定于领域的语言 鉴于此 在 面向 Java? 开发人员的 Scala 指南 系列的第 篇文章中 Ted Neward 着手构建一个简单的计算器 DSL 以此来展示函数性语言的构建 外部 DSL 的强大功能 他研究了 Scala 的一个新的特性 case 类 并重新审视一个功能强大的特性 模式匹配
上个月的文章发表后 我又收到了一些抱怨/评论 说我迄今为止在本系列中所用的示例都没涉及到什么实质性的问题 当然在学习一个新语言的初期使用一些小例子是很合理的 而读者想要看到一些更 现实的 示例 从而了解语言的深层领域和强大功能以及其优势 这也是理所当然的 因此 在这个月的文章中 我们来分两部分练习构建特定于领域的语言(DSL)— 本文以一个小的计算器语言为例
关于本系列
Ted Neward 将和您一起深入探讨 Scala 编程语言 在这个新的 developerWorks 系列 中 您将深入了解 Sacla 并在实践中看到 Scala 的语言功能 进行比较时 Scala 代码和 Java 代码将放在一起展示 但(您将发现)Scala 中的许多内容与您在 Java 编程中发现的任何内容都没有直接关联 而这正是 Scala 的魅力所在!如果用 Java 代码就能够实现的话 又何必再学习 Scala 呢?
特定于领域的语言
可能您无法(或没有时间)承受来自于您的项目经理给您的压力 那么让我直接了当地说吧 特定于领域的语言无非就是尝试(再一次)将一个应用程序的功能放在它该属于的地方 — 用户的手中
通过定义一个新的用户可以理解并直接使用的文本语言 程序员成功摆脱了不停地处理 UI 请求和功能增强的麻烦 而且这样还可以使用户能够自己创建脚本以及其他的工具 用来给他们所构建的应用程序创建新的行为 虽然这个例子可能有点冒险(或许会惹来几封抱怨的电子邮件) 但我还是要说 DSL 的最成功的例子就是 Microsoft® Office Excel 语言 用于表达电子表格单元格的各种计算和内容 甚至有些人认为 SQL 本身就是 DSL 但这次是一个旨在与关系数据库相交互的语言(想象一下如果程序员要通过传统 API read() / write() 调用来从 Oracle 中获取数据的话 那将会是什么样子)
这里构建的 DSL 是一个简单的计算器语言 用于获取并计算数学表达式 其实 这里的目标是要创建一个小型语言 这个语言能够允许用户来输入相对简单的代数表达式 然后这个代码来为它求值并产生结果 为了尽量简单明了 该语言不会支持很多功能完善的计算器所支持的特性 但我不也不想把它的用途限定在教学上 — 该语言一定要具备足够的可扩展性 以使读者无需彻底改变该语言就能够将它用作一个功能更强大的语言的核心 这意味着该语言一定要可以被轻易地扩展 并要尽量保持封装性 用起来不会有任何的阻碍
关于 DSL 的更多信息
DSL 这个主题的涉及面很广 它的丰富性和广泛性不是本文的一个段落可以描述得了的 想要了解更多 DSL 信息的读者可以查阅本文末尾列出的 Martin Fowler 的 正在进展中的图书 特别要注意关于 内部 和 外部 DSL 之间的讨论 Scala 以其灵活的语法和强大的功能而成为最强有力的构建内部和外部 DSL 的语言
换句话说 (最终的)目标是要允许客户机编写代码 以达到如下的目的
清单 计算器 DSL 目标
// This is Java using the Calculator String s = (( ) + ) ; double result = tedneward calcdsl Calculator evaluate(s); System out println( We got + result); // Should be
我们不会在一篇文章完成所有的论述 但是我们在本篇文章中可以学习到一部分内容 在下一篇文章完成全部内容
从实现和设计的角度看 可以从构建一个基于字符串的解析器来着手构建某种可以 挑选每个字符并动态计算 的解析器 这的确极具诱惑力 但是这只适用于较简单的语言 而且其扩展性不是很好 如果语言的目标是实现简单的扩展性 那么在深入研究实现之前 让我们先花点时间想一想如何设计语言
根据那些基本的编译理论中最精华的部分 您可以得知一个语言处理器(包括解释器和编译器)的基本运算至少由两个阶段组成
● 解析器 用于获取输入的文本并将其转换成 Abstract Syntax Tree(AST) ● 代码生成器(在编译器的情况下) 用于获取 AST 并从中生成所需字节码 或是求值器(在解释器的情况下) 用于获取 AST 并计算它在 AST 里面所发现的内容
拥有 AST 就能够在某种程度上优化结果树 如果意识到这一点的话 那么上述区别的原因就变得更加显而易见了 对于计算器 我们可能要仔细检查表达式 找出可以截去表达式的整个片段的位置 诸如在乘法表达式中运算数为 的位置(它表明无论其他运算数是多少 运算结果都会是 )
您要做的第一件事是为计算器语言定义该 AST 幸运的是 Scala 有 case 类 一种提供了丰富数据 使用了非常薄的封装的类 它们所具有的一些特性使它们很适合构建 AST
case 类
在深入到 AST 定义之前 让我先简要概述一下什么是 case 类 case 类是使 scala 程序员得以使用某些假设的默认值来创建一个类的一种便捷机制 例如 当编写如下内容时
清单 对 person 使用 case 类
case class Person(first:String last:String age:Int){}
Scala 编译器不仅仅可以按照我们对它的期望生成预期的构造函数 — Scala 编译器还可以生成常规意义上的 equals() toString() 和 hashCode() 实现 事实上 这种 case 类很普通(即它没有其他的成员) 因此 case 类声明后面的大括号的内容是可选的
清单 世界上最短的类清单
case class Person(first:String last:String age:Int)
这一点通过我们的老朋友 javap 很容易得以验证
清单 神圣的代码生成器 Batman!
C:\Projects\Exploration\Scala>javap PersonCompiled from case scala public class Person extends java lang Object implements scala ScalaObject scala Product java io Serializable{ public Person(java lang String java lang String int); public java lang Object productElement(int); public int productArity(); public java lang String productPrefix(); public boolean equals(java lang Object); public java lang String toString(); public int hashCode(); public int $tag(); public int age(); public java lang String last(); public java lang String first();}
如您所见 伴随 case 类发生了很多传统类通常不会引发的事情 这是因为 case 类是要与 Scala 的模式匹配(在 集合类型 中曾简短分析过)结合使用的
使用 case 类与使用传统类有些不同 这是因为通常它们都不是通过传统的 new 语法构造而成的 事实上 它们通常是通过一种名称与类相同的工厂方法来创建的
清单 没有使用 new 语法?
object App{ def main(args : Array[String]) : Unit = { val ted = Person( Ted Neward ) }}
case 类本身可能并不比传统类有趣 或者有多么的与众不同 但是在使用它们时会有一个很重要的差别 与引用等式相比 case 类生成的代码更喜欢按位(biise)等式 因此下面的代码对 Java 程序员来说有些有趣的惊喜
清单 这不是以前的类
object App{ def main(args : Array[String]) : Unit = { val ted = Person( Ted Neward ) val ted = Person( Ted Neward ) val amanda = Person( Amanda Laucher ) System out println( ted == amanda: + (if (ted == amanda) Yes else No )) System out println( ted == ted: + (if (ted == ted) Yes else No )) System out println( ted == ted : + (if (ted == ted ) Yes else No )) }}/C:\Projects\Exploration\Scala>scala Appted == amanda: Noted == ted: Yested == ted : Yes/
case 类的真正价值体现在模式匹配中 本系列的读者可以回顾一下模式匹配(参见 本系列的第二篇文章 关于 Scala 中的各种控制构造) 模式匹配类似 Java 的 switch/case 只不过它的本领和功能更加强大 模式匹配不仅能够检查匹配构造的值 从而执行值匹配 还可以针对局部通配符(类似局部 默认值 的东西)匹配值 case 还可以包括对测试匹配的保护 来自匹配标准的值还可以绑定于局部变量 甚至符合匹配标准的类型本身也可以进行匹配
有了 case 类 模式匹配具备了更强大的功能 如清单 所示
清单 这也不是以前的 switch
case class Person(first:String last:String age:Int);object App{ def main(args : Array[String]) : Unit = { val ted = Person( Ted Neward ) val amanda = Person( Amanda Laucher ) System out println(process(ted)) System out println(process(amanda)) } def process(p : Person) = { Processing + p + reveals that + (p match { case Person(_ _ a) if a > => they re certainly old case Person(_ Neward _) => they e from good genes case Person(first last ageInYears) if ageInYears > => first + + last + is + ageInYears + years old case _ => I have no idea what to do with this person }) }}/C:\Projects\Exploration\Scala>scala AppProcessing Person(Ted Neward ) reveals that they re certainly old Processing Person(Amanda Laucher ) reveals that Amanda Laucher is years old /
清单 中发生了很多 *** 作 下面就让我们先慢慢了解发生了什么 然后回到计算器 看看如何应用它们
首先 整个 match 表达式被包裹在圆括号中 这并非模式匹配语法的要求 但之所以会这样是因为我把模式匹配表达式的结果根据其前面的前缀串联了起来(切记 函数性语言里面的任何东西都是一个表达式)
其次 第一个 case 表达式里面有两个通配符(带下划线的字符就是通配符) 这意味着该匹配将会为符合匹配的 Person 中那两个字段获取任何值 但是它引入了一个局部变量 a p age 中的值会绑定在这个局部变量上 这个 case 只有在同时提供的起保护作用的表达式(跟在它后边的 if 表达式)成功时才会成功 但只有第一个 Person 会这样 第二个就不会了 第二个 case 表达式在 Person 的 firstName 部分使用了一个通配符 但在 lastName 部分使用常量字符串 Neward 来匹配 在 age 部分使用通配符来匹配
由于第一个 Person 已经通过前面的 case 匹配了 而且第二个 Person 没有姓 Neward 所以该匹配不会为任何一个 Person 而被触发(但是 Person( Michael Neward ) 会由于第一个 case 中的 guard 子句失败而转到第二个 case)
第三个示例展示了模式匹配的一个常见用途 有时称之为提取 在这个提取过程中 匹配对象 p 中的值为了能够在 case 块内使用而被提取到局部变量中(第一个 最后一个和 ageInYears) 最后的 case 表达式是普通 case 的默认值 它只有在其他 case 表达式均未成功的情况下才会被触发
简要了解了 case 类和模式匹配之后 接下来让我们回到创建计算器 AST 的任务上
计算器 AST
首先 计算器的 AST 一定要有一个公用基类型 因为数学表达式通常都由子表达式组成 通过 + ( ) 就可以很容易地看到这一点 在这个例子中 子表达式 ( ) 将会是 + 运算的右侧运算数
事实上 这个表达式提供了三种 AST 类型
● 基表达式 ● 承载常量值的 Number 类型 ● 承载运算和两个运算数的 BinaryOperator
想一下 算数中还允许将一元运算符用作求负运算符(减号) 将值从正数转换为负数 因此我们可以引入下列基本 AST
清单 计算器 AST(src/calc scala)
package tedneward calcdsl{ private[calcdsl] abstract class Expr private[calcdsl] case class Number(value : Double) extends Expr private[calcdsl] case class UnaryOp(operator : String arg : Expr) extends Expr private[calcdsl] case class BinaryOp(operator : String left : Expr right : Expr) extends Expr}
注意包声明将所有这些内容放在一个包( tedneward calcdsl)中 以及每一个类前面的访问修饰符声明表明该包可以由该包中的其他成员或子包访问 之所以要注意这个是因为需要拥有一系列可以测试这个代码的 JUnit 测试 计算器的实际客户机并不一定非要看到 AST 因此 要将单元测试编写成 tedneward calcdsl 的一个子包
清单 计算器测试(testsrc/calctest scala)
package tedneward calcdsl test{ class CalcTest { import junit _ Assert _ @Test def ASTTest = { val n = Number( ) assertEquals( n value) } @Test def equalityTest = { val binop = BinaryOp( + Number( ) Number( )) assertEquals(Number( ) binop left) assertEquals(Number( ) binop right) assertEquals( + binop operator) } }}
到目前为止还不错 我们已经有了 AST
再想一想 我们用了四行 Scala 代码构建了一个类型分层结构 表示一个具有任意深度的数学表达式集合(当然这些数学表达式很简单 但仍然很有用) 与 Scala 能够使对象编程更简单 更具表达力相比 这不算什么(不用担心 真正强大的功能还在后面)
接下来 我们需要一个求值函数 它将会获取 AST 并求出它的数字值 有了模式匹配的强大功能 编写这样的函数简直轻而易举
清单 计算器(src/calc scala)
package tedneward calcdsl{ // object Calc { def evaluate(e : Expr) : Double = { e match { case Number(x) => x case UnaryOp( x) => (evaluate(x)) case BinaryOp( + x x ) => (evaluate(x ) + evaluate(x )) case BinaryOp( x x ) => (evaluate(x ) evaluate(x )) case BinaryOp( x x ) => (evaluate(x ) evaluate(x )) case BinaryOp( / x x ) => (evaluate(x ) / evaluate(x )) } } }}
注意 evaluate() 返回了一个 Double 它意味着模式匹配中的每一个 case 都必须被求值成一个 Double 值 这个并不难 数字仅仅返回它们的包含的值 但对于剩余的 case(有两种运算符) 我们还必须在执行必要运算(求负 加法 减法等)前计算运算数 正如常在函数性语言中所看到的 会使用到递归 所以我们只需要在执行整体运算前对每一个运算数调用 evaluate() 就可以了
大多数忠实于面向对象的编程人员会认为在各种运算符本身以外 执行运算的想法根本就是错误的 — 这个想法显然大大违背了封装和多态性的原则 坦白说 这个甚至不值得讨论 这很显然违背 了封装原则 至少在传统意义上是这样的
在这里我们需要考虑的一个更大的问题是 我们到底从哪里封装代码?要记住 AST 类在包外是不可见的 还有就是客户机(最终)只会传入它们想求值的表达式的一个字符串表示 只有单元测试在直接与 AST case 类合作
但这并不是说所有的封装都没有用了或过时了 事实上恰好相反 它试图说服我们在对象领域所熟悉的方法之外 还有很多其他的设计方法也很奏效 不要忘了 Scala 兼具对象和函数性 有时候 Expr 需要在自身及其子类上附加其他行为(例如 实现良好输出的 toString 方法) 在这种情况下可以很轻松地将这些方法添加到 Expr 函数性和面向对象的结合提供了另一种选择 无论是函数性编程人员还是对象编程人员 都不会忽略到另一半的设计方法 并且会考虑如何结合两者来达到一些有趣的效果
从设计的角度看 有些其他的选择是有问题的 例如 使用字符串来承载运算符就有可能出现小的输入错误 最终会导致结果不正确 在生产代码中 可能会使用(也许必须使用)枚举而非字符串 使用字符串的话就意味着我们可能潜在地 开放 了运算符 允许调用出更复杂的函数(诸如 abs sin cos tan 等)乃至用户定义的函数 这些函数是基于枚举的方法很难支持的
对所有设计和实现的来说 都不存在一个适当的决策方法 只能承担后果 后果自负
但是这里可以使用一个有趣的小技巧 某些数学表达式可以简化 因而(潜在地)优化了表达式的求值(因此展示了 AST 的有用性)
● 任何加上 的运算数都可以被简化成非零运算数 ● 任何乘以 的运算数都可以被简化成非零运算数 ● 任何乘以 的运算数都可以被简化成零
不止这些 因此我们引入了一个在求值前执行的步骤 叫做 simplify() 使用它执行这些具体的简化工作
清单 计算器(src/calc scala)
def simplify(e : Expr) : Expr = { e match { // Double negation returns the original value case UnaryOp( UnaryOp( x)) => x // Positive returns the original value case UnaryOp( + x) => x // Multiplying x by returns the original value case BinaryOp( x Number( )) => x // Multiplying by x returns the original value case BinaryOp( Number( ) x) => x // Multiplying x by returns zero case BinaryOp( x Number( )) => Number( ) // Multiplying by x returns zero case BinaryOp( Number( ) x) => Number( ) // Dividing x by returns the original value case BinaryOp( / x Number( )) => x // Adding x to returns the original value case BinaryOp( + x Number( )) => x // Adding to x returns the original value case BinaryOp( + Number( ) x) => x // Anything else cannot (yet) be simplified case _ => e } }
还是要注意如何使用模式匹配的常量匹配和变量绑定特性 从而使得编写这些表达式可以易如反掌 对 evaluate() 惟一一个更改的地方就是包含了在求值前先简化的调用
清单 计算器(src/calc scala)
def evaluate(e : Expr) : Double = { simplify(e) match { case Number(x) => x case UnaryOp( x) => (evaluate(x)) case BinaryOp( + x x ) => (evaluate(x ) + evaluate(x )) case BinaryOp( x x ) => (evaluate(x ) evaluate(x )) case BinaryOp( x x ) => (evaluate(x ) evaluate(x )) case BinaryOp( / x x ) => (evaluate(x ) / evaluate(x )) } }
还可以再进一步简化 注意一下 它是如何实现只简化树的最底层的?如果我们有一个包含 BinaryOp( Number( ) Number( )) 和 Number( ) 的 BinaryOp 的话 那么内部的 BinaryOp 就可以被简化成 Number( ) 但外部的 BinaryOp 也会如此 这是因为此时外部 BinaryOp 的其中一个运算数是零
我突然犯了作家的职业病了 所以我想将它留予读者来定义 其实是想增加点趣味性罢了 如果读者愿意将他们的实现发给我的话 我将会把它放在下一篇文章的代码分析中 将会有两个测试单元来测试这种情况 并会立刻失败 您的任务(如果您选择接受它的话)是使这些测试 — 以及其他任何测试 只要该测试采取了任意程度的 BinaryOp 和 UnaryOp 嵌套 — 通过
结束语
显然我还没有说完 还有分析的工作要做 但是计算器 AST 已经成形 我们无需作出大的变动就可以添加其他的运算 运行 AST 也无需大量的代码(按照 Gang of Four 的 Visitor 模式) 而且我们已经有了一些执行计算本身的工作代码(如果客户机愿意为我们构建用于求值的代码的话)
lishixinzhi/Article/program/Java/hx/201311/25735
以上就是关于sql语句能做乘除法逻辑运算么全部的内容,包括:sql语句能做乘除法逻辑运算么、计算机4级都考什么、如何用EXCEL数据库函数计算满足条件的两列数的乘积(有具体题目!)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)