具体实施方式
图1示出了数据库管理***内的产品定单数据库的表式视图102的屏幕截图。表102包括由多行和多列数据组成的表。每一行数据一般包括单个数据记录。一般,可期望数据库中的每一列数据含有同种类型的数据元素。例如,Order ID(定单ID)列104包括数字格式的数据元素,Customer(顾客)列106包括字母数字串形式的数据,Order Date(定单日期)列108包括日期格式的数据等等。单个记录的OrderID列对应于该记录的Order ID字段。由此,字段的集合可以包含一列。本领域的技术人员可以理解,多种其它类型的数据可以保存在数据库中,且使用数据库管理***内的表来显示。本发明允许使用简单数据库表的概念化(外表上与数据库表102类似,但结构上不同)来对复杂的数据层级建模,从而减轻用户形成跨越多张表的复杂查询以及在多张表之间来回移动以查看和处理数据的负担。
假定本发明可以被实现为计算机***,提供图2来示出可在其上实现本发明的实施例的合适的计算***环境的示例。在其最基本配置中,***200包括至少一个处理单元202和存储器204。取决于计算设备的确切配置和类型,存储器204可以是易失性的(诸如RAM)、非易失性的(诸如ROM、闪存等)或两者的某种组合。该最基本的配置在图2中以虚线206示出。
除了存储器204之外,***可以包括至少一种其它形式的计算机可读介质。计算机可读介质可以是能够由***200访问的任何可用介质。作为示例,而非限制,计算机可读介质可以包括计算机存储介质和通信介质。
计算机存储介质包括以任何方法或技术实现的用于存储诸如计算机可读指令、数据结构、程序模块或其它数据等信息的易失性和非易失性、可移动和不可移动介质。存储器204、可移动存储208和不可移动存储210都是计算机存储介质的示例。计算机存储介质包括,但不限于,RAM、ROM、EEPROM、闪存或其它存储器技术、CD-ROM、数字多功能盘(DVD)或其它光盘存储、磁带盒、磁带、磁盘存储或其它磁性存储设备、或能用于存储所需信息且可以由***200访问的任何其它介质。任何这样的计算机存储介质可以是***200的一部分。
***200也可以包括允许***与其它设备通信的通信连接212。通信连接212是通信介质的示例。通信介质通常具体化为诸如载波或其它传输机制等已调制数据信号中的计算机可读指令、数据结构、程序模块或其它数据,且包含任何信息传递介质。术语“已调制数据信号”指的是这样一种信号,其一个或多个特征以在信号中编码信息的方式被设定或更改。作为示例,而非限制,通信介质包括有线介质,诸如有线网络或直接线连接,以及无线介质,诸如声学、RF、红外线和其它无线介质。此处所用的术语计算机可读介质包括存储介质和通信介质。
根据一个实施例,***200包括***设备,诸如输入设备214和/或输出设备216。示例性输入设备214包括但不限于,键盘、计算机鼠标、笔、或触针、语音输入设备、触觉输入设备等。示例性输出设备216包括但不限于,诸如显示器、扬声器和打印机等设备。为本发明的目的,显示器是主要输出设备。这些设备中的每一件在本领域中都是公知的,从而不在此详细描述。
理解了计算环境以后,下列附图是关于为实现实施本发明的各实施例的过程而执行的逻辑操作来描述的。这些逻辑操作被实现为(1)运行在计算***上的计算机实现的步骤或程序模块的序列,和/或(2)计算***内的互联机器逻辑电路或电路模块。实施方式是取决于实现本发明的计算***的性能需求的选择问题。从而,此处描述且组成本发明的实施例的逻辑操作被不同地称为操作、结构设备、动作或模块。本领域的技术人员可以认识到,这些操作、结构设备、动作或模块可以用软件、固件、专用数字逻辑及其任何组合来实现,而不背离如所附权利要求书中所述的本发明的精神和范围。
图3示出了根据本发明的一个实施例的模块。用户界面模块允许用户查看、修改、查询或以其它方式处理数据。因此,用户与数据建模模块304、查询展开模块306和游标建模模块308的交互通过用户界面模块302发生。同样地,来自所述的模块304、306和308的数据通过用户界面模块302显示。
用户界面302将表分层结构参数传递给数据建模模块304,并且另外可以从数据建模模块304中接收反馈以使用更多的表定义或修改来协助用户。用户界面模块302向查询展开模块306传递由用户提供的查询,且同样从查询展开模块306中接收查询结果。用户界面模块302将来自用户的对数据的请求传递给游标指示模块308用于数据检索,并同样从游标指示模块308接收检索到的数据。
在一个实施例中,用户界面模块302在显示器上直接呈现从模块304、306和308中的一个或多个返回的数据。在替换实施例中,用户界面302使用应用程序编程接口(API)来更新显示。
数据建模模型304允许创建并修改概念表。概念表是可以包含另一张表形式的复杂(非标量)数据以及复杂数据的数据表。数据表一般仅包括标量数据,且可以包括数字、字母数字串、分数等。复杂数据可以包括一个或多个嵌套的表,嵌套的表本身可以包括额外层次的嵌套表。概念表可以包含任意多个这样的分层相关的表。从而,概念表中的给定字段可以被完全地物理地映射至另一张表中的字段。而且,该物理映射及其结果对用户而言是完全透明的。数据建模模块304可以从用户界面302接收由用户为概念表所指定的参数。
在一个实施例中,概念表被存储为含有标量数据的一个或多个数据表。仅存在于概念表中的标量数据值被存储在特别为非映射的标量值分配的数据表中。物理映射至数据表的一个或多个数据值由数据建模模块304“切碎(shred)”,使得这些数据被物理地存储在数据表310中。作为结果,用户仅需处理单个概念表,而同时将概念表转换为用于存储的多个分层表的复杂性对用户而言是透明的。同样,切碎的实现不必涉及在数据库存储引擎或数据库查询处理器中添加任何复杂性。
在一个实施例中,当将复杂列添加至表中时,概念表中的数据值被切碎为合适的数据表。在替换实施例中,当从用户处接收到保存命令时,概念表中的数据值被切碎为合适的数据表。在又一实施例中,只要检测到值变化,概念表中的数据值就被切碎为合适的数据表。
查询展开模块306从用户界面模块302接收概念表查询,并基于该概念表的分层结构来展开该查询。在一个实施例中,查询展开模块306基于概念表的分层结构,使用由开发者定义的一组规则来展开查询。在下文表1-12中描述了一组示例性查询展开规则。
在替换实施例中,查询展开模块306通过将相关数据表的子集联结(数据库领域的术语,类似于组合)为单个数据表来展开查询,然后在该单个数据表上执行概念表查询。在另一个替换实施例中,查询展开模块306通过与相关性无关地将由概念表链接的所有数据表310联结为单个数据表来展开查询,然后在该单个数据表上执行概念表查询。
在一个实施例中,查询展开模块306直接在数据表310上执行查询。在替换实施例中,查询展开模块306将展开的查询提交给数据库服务器用于执行。这样的实施例不必要求对查询处理器或数据库服务器的任何改变。
游标指示模块308使得能够读取并导航概念表。当通过用户界面302接收到打开概念表的信号时,游标指示模块308分析存在的对数据表的任何映射。来自这些数据表的标量数据使用映射来检索,且标量数据被返回至用户界面302用于显示。
如果用户选择了包含数据表的概念表字段,那么引用该字段中的表映射。对映射至的数据表拍快照,并在概念表中显示结果。在一个实施例中,映射至的数据表也对编辑锁定,使得它们的内容不能改变。在替换实施例中,映射至的数据表不被锁定,相反,周期性地检查映射至的数据表以将更新传播给所显示的概念表。
本领域的技术人员可以认识到,尽管结合图3提供的示例性实施例涉及可包含数据表的概念表,但是可以使用任意多层间接,而不背离所要求保护的发明的范围。例如,概念表可以包括一个或多个概念表,这一个或多个概念表本身仍旧可以包括其它概念表。在该情形中,必须注意防止无限循环,即概念表引用(直接或间接地)其自身,这样造成了无限层数的间接。
在一个实施例中,数据建模模块304可以原子地执行数据存储。这意味着在任何给定的数据存储尝试中,或者全部或者没有数据表被更新。同样,可以避免读取数据的同时数据表处于过渡状态中。原子数据表写入可以通过信号量、文件锁定或本领域的技术人员已知的其它方法来执行,且可以额外地包含回退(撤销一个或多个未决的写入)。
图4示出了根据本发明的实施例的操作流程,在其中创建了概念表。接收操作402从用户处接收向现有的表或概念表添加复杂数据类型的信号。该信号可以通过用户界面从用户处、从自动化计算机过程中、或其它输入源接收。该接收触发创建操作404创建至少一张数据表。
创建操作404创建至少一张数据表来包含与该复杂数据相关联的任何标量值。当存储概念表时,输入到复杂数据字段的数据可以被切碎为对应的数据表。在一个实施例中,每一创建的数据表采用一个或多个数据库文件的形式。在另一个实施例中,每一创建的数据表采用一个或多个数据库文件内的数据结构的形式。在又一实施例中,创建操作404在每一创建的数据表内额外地将一个或多个值初始化为默认值。在其中已经存在合适的数据表的一个实施例中,创建操作404可以被省略,且可以仅链接至数据表。
在创建操作404之后,链接操作406向概念表添加一个或多个链接,对应于由创建操作404所创建的一个或多个数据表。当通过游标指示(在上文中结合图3以及在下文中结合图7描述)选择复杂数据字段时,可以使用链接来分配数据表。当添加或修改复杂数据字段内的标量值时(上文中结合图3描述),也可以使用链接来分配数据表。
确定操作408确定是否需要额外的表来容纳复杂数据。如果需要更多的表,该流程分支到“是”,以返回至创建操作404。如果不需要更多的表,该流程分支到“否”来结束流程410。
一旦到达流程410的终点,可以使用游标指示(在上文中结合图3以及在下文中结合图7描述)查看或处理复杂数据,且可以通过切碎(在上文中结合图3以及在下文中结合图5描述)来存储复杂数据。
在一个实施例中,现有数据表可以被***至概念表中。在这一实施例中,验证操作(未示出)将验证数据表的存在,且可以省略创建操作404。
图5示出了根据本发明的一个实施例的操作流程,其中来自概念表的数据被切碎并存储至一个或多个对应的数据表。
接收操作502接收存储与概念表相关联的一个或多个复杂数据值的信号。该信号可以是用户明确将数据保存在数据库管理应用程序内的结果。或者,该信号可以从同步修改的数据的自动化过程中接收。由接收操作502的对信号的接收触发分析操作504。
分析操作504分析用于存储复杂数据值的概念表,并确定该概念表的结构。基于该结构数据,确定操作506确定到数据表中的位置的一个或多个映射。这些映射可以是一组数据表坐标、指向包含数据表的存储器位置的指针、数据表文件名、唯一记录标识号或用于寻址数据的其它方式、或其任何组合的形式。
存储操作508使用这些映射将来自概念表的一个或多个数据值存储至数据值各自的数据表中,此时概念表数据被成功地切碎。数据可以稍后通过游标指示(在上文结合图3描述,在下文结合图7描述)来被“解除切碎(unshred)”。在一个实施例中,存储操作508原子地执行数据存储。在另一个实施例中,存储操作508可以退回不完整的存储。
图6示出了根据本发明的一个实施例的操作流程,其中概念表的查询被展开来处理切碎的数据。接收操作602接收对概念表的查询。在一个实施例中,这样的查询可以由用户以文本形式输入。在另一个实施例中,所述查询可以是完全或部分使用图形用户界面来构造的。在又一实施例中,所述查询可以由计算机自动生成。
分析操作604分析用于查询复杂数据的概念表,并确定概念表的结构以及到数据表的任何相关联的映射。这些映射可以采用若干不同的形式(如前文中结合图5讨论的)中的任一种。
确定操作606使用来自分析操作604的结构数据和映射,结合一组展开规则来确定是否有任何规则适用于该查询以及这些规则是否需要展开。如果没有适用于该查询的规则,或者如果合适的规则指示展开完成,那么流程分支到“否”到签发操作610。如果一条或多条规则适用于该查询,流程分支到“是”到应用操作608。
如果一条或多条展开规则适用于查询,则应用操作608根据这些规则来展开查询。在一个实施例中,应用操作可以创建新查询作为展开查询的一部分。在下文表1-12中描述了某些示例性展开规则,包括使用诸如JOIN等SQL术语的展开以在评估数据之前将数据表组合在一起。本领域的技术人员可以理解,确定操作606和应用操作608可以在查询完全展开之前反复进行,从而准备好由签发操作610来签发。可以按不同的顺序来应用一条以上规则,且单条规则可以在查询的展开过程中被应用一次以上。在实现查询的增量式展开的实施例中,查询展开规则可以被保持为彼此正交,从而保持相对简单。在执行查询的增量式展开的实施例中,数据结构对存储增量式展开规则应用程序的中间结果可能是必需的。在替换实施例中,多条查询展开规则可以由应用操作608应用。
签发操作610提交由确定和应用操作606和608展开的查询。在一个实施例中,签发操作610直接查询数据库数据。在替换实施例中,签发操作610向数据库服务器发送查询。
图7示出了根据本发明的一个实施例的操作流程,其中游标指示使得能够从切碎的概念表中检索数据。接收操作702接收打开概念表中的复杂数据的信号。这样的信号可以从用户打开含有必需被显示的复杂数据的现有概念表、从用户移动游标至含有复杂数据的概念表字段、或通过其它用户生成或计算机生成的输入而得到。
读取操作704读取到与概念表相关联的数据表中位置的一个或多个映射。如前所述,这些映射可以采用各种形式。接收操作706然后从由映射指示的数据表中检索标量数据值。由检索操作706检索出的标量值可以用于填充概念表,概念表由显示操作708显示。
显示操作708显示含有由检索操作706检索到的标量值的概念表。在一个实施例中,显示操作708可以直接在屏幕上呈现概念表,在另一个实施例中,显示操作708可以依赖于应用程序编程接口(API)来执行呈现,或者在其它构想的实施例中,显示操作708可以使用本领域的技术人员已知的用于显示数据的其它方法。
本领域的技术人员可以理解,此处所要求保护的实施例不仅可以在使用复杂数据类型的数据库和电子表应用程序的环境中使用,也可以在诸如MicrosoftSharepoint等协作服务套件的环境中使用。这样的套件可以包括含有多个值的其自身的复杂数据类型(例如,多项选择、附加文件等)。可以基本上与此处讨论的示例性实施例中相同的方式来处理这些复杂数据类型。
在一个特定实施例中,一组SQL查询展开规则由查询展开模块306(图3)、确定操作606和应用操作608(图6)使用。在表1-11中显示了一组示例性的若干SQL查询展开规则。这些规则处理不同复杂性的情景。在示例中(表1),展开了相对简单的SELECT查询。简单SELECT查询被定义为没有分组和聚集的查询。当对复杂标量字段不存在约束时,在展开的查询中仅需引用父表。当在查询的WHERE子句中存在对复杂标量的约束时,必须执行表和复杂数据类型之间的联结(见表1的基本示例)。WHERE子句中的过滤器必须如引用复杂数据类型而不是表中的复杂列所需的来修改。SELECT子句中的字段必需使用正确的表引用来被类似地修改。当在一张表和另一张表之间必须执行复杂标量上的非左联结时,展开的查询将包括联结父表及其复杂表的子查询(见表4的基本示例)。如果在未展开查询中的WHERE子句中出现NOT,那么NOT将被转换为[表].[复杂列]NOT IN(SELECT[复杂列]FROM[表]JOIN[平面表]ON[表].[复杂列]=[平面表].[外键]WHERE[平面表].[复杂标量]=值)。
表4-11示出了使用聚集的查询的展开规则。一个这样的规则是,复杂类型的聚集是针对表和复杂数据类型的LEFT JOIN(左联结)而执行的。另一个这样的规则是,当在未展开的查询中存在不同复杂类型的聚集时,每一聚集将会使用子查询来被计算。同样,HAVING子句(表10)的出现将被转化为外查询中的WHERE子句。如果HAVING子句引用了不以其它方式在聚集SELECT列表中引用的复杂类型,可以创建新的子查询来联结表和复杂类型。
用户所写的查询 |
SELECT IssueNameFROM IssuesWHERE AssignedTo.PersonID=1 |
展开的查询 |
SELECT DISTINCTROW Issues.IssueNameFROM Issues left OUTER JOINf_AssignedTo ON Issues.AssignedToID=f_AssignedTo.AssignedToIDWHERE f_AssignedTo.PersonID=1 |
表1:复杂标量上的示例过滤器
用户所写的查询 |
SELECT IssueNameFROM IssuesWHERE AssignedTo.PersonID=1 ORResolvedBy.PersonID=2 |
展开的查询 |
SELECT DI STINCTROWIssues.IssueNameFROM(Issues left OUTER JOINf_AssignedTo ON Issues.AssignedToID=f_AssignedTo.AssignedToID)leftOUTER JOIN f_ResolvedBy ONIssues.ResolvedByID=f_ResolvedBy.ResolvedByIDWHERE f_AssignedTo.PersonID=1 ORf_ResolvedByID=2 |
表2:多个复杂标量上的示例过滤器
用户所写的查询 |
SELECT Issues.IssueName,X.PersonNameFROM Issues INNER JOIN Persons X ONIssues.AssignedToID=X.PersonIDWHERE AssignedTo.PersonID=1 |
展开的查询 |
SELECT DISTINCTROW Y.IssueName.X.PersonNameFROM(SELECT Issues.IssueName,f_AssignedTo.PersonID FROM Issuesleft OUTER JOIN f_AssignedTo ONIssues.AssignedToID=f_AssignedTo.AssignedToID)AS Y INNERJOIN Persons X ON X.PersonID=Y.PersonIDWHERE Y.PersonID=1 |
表3:当在复杂标量上联结时的示例子查询
用户所写的查询 |
SELECT IssueName,COUNT(AssignedTo)FROM IssuesGROUP BY IssueName |
展开的查询 |
SELECT Issues.IssueName,COUNT(f_AssignedTo.PersonID)ASCountOfPersonIDFROM Issues left OUTER JOINf_AssignedTo ONIssues.AssignedTo=f_AssignedTo.AssignedToGROUP BY Issues.IssueName |
表4:复杂类型上的示例聚集
用户所写的查询 |
SELECT IssueName,COUNT(AssignedTo)FROM IssuesWHERE AssignedTo.PersonID=3GROUP BY IssueName |
展开的查询 |
SELECT x.IssueName.COUNT(f_AssignedTo.PersonID)ASCountOfPersonIDFROM(SELECT DISTINCTROW Issues.IssueName,Issues.AssignedToFROM Issues left JOIN f_AssignedTo ONIssues.AssignedTo=f_AssignedTo.AssignedToWHERE f_AssignedTo.PersonID=3)AS XINNER JOIN f_AssignedTo ONx.AssignedTo=f_AssignedTo.AssignedToGROUP BY Issues.IssueName |
表5:复杂类型上的聚集,在对同一复杂标量有约束
用户所写的查询 |
SELECT IssueName,COUNT(AssignedTo)FROM IssuesWHERE ResolvedBy.PersonID=3 |
展开的查询 |
SELECT x.IssueName,COUNT(f_AssignedTo.PersonID)ASCountOfPersonIDFROM(SELECT DISTINCTROW Issues.IssueName,Issues.AssignedTo,Issues.ResolvedByFROM Issues left JOIN f_ResolvedBy ONIssues.ResolvedBy=f_ResolvedBy.ResolvedByWHERE f_ResolvedBy.PersonID=3)AS XINNER JOIN f_AssignedTo ON x.AssignedTo |
|
=f_AssignedTo.AssignedToGROUP BY Issues.IssueName |
表6:复杂类型上的示例聚集,对不同的复杂标量有约束
用户所写的查询 |
SELECT IssueName,COUNT(AssignedTo)FROM IssuesWHERE AssignedTo.PersonID=2OR ResolvedBy.PersonID=3 |
展开的查询 |
SELECT x.IssueName,COUNT(f_AssignedTo.PersonID)ASCountOfPersonIDFROM(SELECT DISTINCTROW Issues.IssueName,Issues.AssignedTo,Issues.ResolvedByFROM(Issues left JOIN f_AssignedTo ONIssues.AssignedTo=f_AssignedTo.AssignedTo)left JOINf_ResolvedBy ONIssues.ResolvedBy=f_ResolvedBy.ResolvedByWHERE f_AssignedTo.PersonID=2 ORf_ResolvedBy.PersonID=3)AS XINNER JOIN f_AssignedTo ON x.AssignedTo=f_AssignedTo.AssignedToGROUP BY Issues.IssueName |
表7:复杂类型1的示例聚集,对复杂标量1和复杂标量2有约束
用户所写的查询 |
SELECT IssueName,COUNT(AssignedTo),COUNT(ResolvedBy)FROM IssuesGROUP BY IssueName |
展开的查询 |
SELECT[Count of AssignedTo PerIssue].IssueName,[Count of AssignedTo PerIssue].CountOfATPersonID,[Count ofResolvedBy Per Issue].CountOfRBPersonIDFROM(SELECT Issues.IssueName,COUNT(f_AssignedTo.PersonID)ASCountOfATPersonIDFROM Issues left JOIN f_AssignedTo ONIssues.AssignedTo=f_AssignedTo.AssignedToGROUP BY Issues.IssueName)AS[Count ofAssignedTo Per Issue]INNER JOIN(SELECT Issues.IssueName,Count(f_ResolvedBy.PersonID)ASCountOfRBPersonIDFROM Issues left JOIN f_ResolvedBy ONIssues.ResolvedBy=f_ResolvedBy.ResolvedByGROUP BY Issues.IssueName)AS[Count ofResolvedBy Per Issue]ON[Count of AssignedTo PerIssue].IssueName=[Count of ResolvedBy PerIssue].IssueName |
表8:复杂类型1和复杂类型2上的示例聚集
用户所写的查询 |
SELECT IssueName,COUNT(AssignedTo),COUNT(ResolvedBy)FROM IssuesGROUP BY IssueNameWHERE(AssignedTo.PersonID=1 ANDResolvedBy.PersonID=3)OR(AssignedTo.PersonID=3 ANDResolvedBy.PersonID=5) |
展开的查询 |
SELECT[Count of AssignedTo PerIssue].IssueName,[Count of AssignedToPer Issue].CountOfATPersonID,[Count ofResolvedBy Per Issue].CountOfRBPersonIDFROM(SELECT Issues.IssueName,COUNT(f_AssignedTo.PersonID)ASCountOfATPersonID FROM(SELECTDISTINCTROW Issues.IssueName,Issues.AssignedTo,Issues.ResolvedByFROM(Issues left OUTER JOINf_AssignedTo ON Issues.AssignedTo=f_AssignedTo.AssignedTo)left OUTERJOIN f_ResolvedBy ON Issues.ResolvedBy=f_ResolvedBy.ResolvedBy WHERE(f_AssignedTo.PersonID=1 ANDf_ResolvedBy.PersonID=3)OR(f_AssignedTo.PersonID=3 ANDf_ResolvedBy.PersonID=5))AS X leftJOIN f_AssignedTo ONX.AssignedTo=f_AssignedTo.AssignedToGROUP BY X.IssueName)AS[Count ofAssignedTo Per Issue]INNER JOIN(SELECT Issues.IssueName,COUNT(f_ResolvedBy.PersonID)ASCountOfRBPersonIDFROM(SELECT DISTINCTROWIssues.IssueName,Issues.AssignedTo,Issues.ResolvedByFROM(Issues left OUTER JOINf_AssignedTo ON Issues.AssignedTo=f_AssignedTo.AssignedTo)left OUTERJOIN f_ResolvedBy ON Issues.ResolvedBy=f_ResolvedBy.ResolvedBY WHERE(f_AssignedTo.PersonID=1 ANDf_ResolvedBy.PersonID=3)OR |
|
(f_AssignedTo.PersonID=3 ANDf_ResolvedBy.PersonID=5))AS Yleft JOIN f_ResolvedBy ONY.ResolvedBy=f_ResolvedBy.ResolvedByGROUP BY Y.IssueName)AS[Count ofResolvedBy Per Issue]ON[Count ofAssignedTo Per Issue].IssueName=[Countof ResolvedBy Per Issue].IssueName |
表9:复杂类型1和复杂类型2上的示例聚集,对复杂标量1和复杂标量2有约束
用户所写的查询 |
SELECT IssueNameFROM IssuesGROUP BY IssueNameHAVING COUNT(AssignedTo)=4 |
展开的查询 |
SELECT Issues.IssueNameFROM Issues left JOIN f_AssignedTo ONIssues.AssignedTo=f_AssignedTo.AssignedToGROUP BY Issues.IssueNameHAVINGCOUNT(f_AssignedTo.PersonID)=4 |
表10:HAVING子句中的示例复杂类型
用户所写的查询 |
SELECT IssueName,COUNT(ResolvedBy)FROM IssuesGROUP BY IssueNameHAVING Count(AssignedTo)=4 |
展开的查询 |
SELECT[Count of ResolvedBy PerIssue].IssueName,[Count of ResolvedBy PerIssue].CountOfRBPersonIDFROM(SELECT Issues.IssueName,Count(f_ResolvedBy.PersonID)ASCountOfRBPersonIDFROM Issues left JOIN f_ResolvedBy ONIssues.ResolvedBy=f_ResolvedBy.ResolvedByGROUP BY Issues.IssueName)AS[Count ofResolvedBy Per Issue]INNER JOIN(SELECT Issues.IssueName,COUNT(f_AssignedTo.PersonID)ASCountOfATPersonIDFROM Issues left JOIN f_AssignedTo ONIssues.AssignedTo=f_AssignedTo.AssignedToGROUP BY Issues.IssueName)AS[Count ofAssignedTo PerIssue]ON[Count of AssignedTo PerIssue].IssueName=[Count of ResolvedBy PerIssue].IssueNameWHERE[Count of AssignedTo PerIssue].CountOfATPersonID=4 |
表11:复杂类型1上的示例聚集,带有HAVING子句中的复杂类型2
上述的多个实施例仅作为示例提供,且不应该被解释为限制本发明。本领域的技术人员可以容易地认识到,可以对本发明进行多种修改和变化,而不遵循此处示出和描述的示例实施例和应用,且不背离在权利要求中描述的本发明的真正的精神和范围。