精华内容
下载资源
问答
  • 关于sql和MySQL的语句执行顺序(必看!!!)

    万次阅读 多人点赞 2016-03-29 12:15:09
    目前还在查看,但是在查阅资料时发现了一些有益的知识,给大家分享一下,就是关于sql以及MySQL语句执行顺序: sql和mysql执行顺序,发现内部机制是一样的。最大区别是在别名的引用上。 一、sql执行顺序 (1)from (3)...

    今天遇到一个问题就是mysql中insert into 和update以及delete语句中能使用as别名吗?目前还在查看,但是在查阅资料时发现了一些有益的知识,给大家分享一下,就是关于sql以及MySQL语句执行顺序:

    sql和mysql执行顺序,发现内部机制是一样的。最大区别是在别名的引用上。 


    一、sql执行顺序 

    1. from 
    2. join 
    3. on 
    4. where 
    5. group by(开始使用select中的别名,后面的语句中都可以使用)
    6.  avg,sum.... 
    7. having 
    8. select 
    9. distinct 
    10. order by
    11. limit 


    从这个顺序中我们不难发现,所有的 查询语句都是从from开始执行的,在执行过程中,每个步骤都会为下一个步骤生成一个虚拟表,这个虚拟表将作为下一个执行步骤的输入。 


    第一步:首先对from子句中的前两个表执行一个笛卡尔乘积,此时生成虚拟表 vt1(选择相对小的表做基础表)。 
    第二步:接下来便是应用on筛选器,on 中的逻辑表达式将应用到 vt1 中的各个行,筛选出满足on逻辑表达式的行,生成虚拟表 vt2 。
    第三步:如果是outer join 那么这一步就将添加外部行,left outer jion 就把左表在第二步中过滤的添加进来,如果是right outer join 那么就将右表在第二步中过滤掉的行添加进来,这样生成虚拟表 vt3 。

    第四步:如果 from 子句中的表数目多余两个表,那么就将vt3和第三个表连接从而计算笛卡尔乘积,生成虚拟表,该过程就是一个重复1-3的步骤,最终得到一个新的虚拟表 vt3。 

    第五步:应用where筛选器,对上一步生产的虚拟表引用where筛选器,生成虚拟表vt4,在这有个比较重要的细节不得不说一下,对于包含outer join子句的查询,就有一个让人感到困惑的问题,到底在on筛选器还是用where筛选器指定逻辑表达式呢?on和where的最大区别在于,如果在on应用逻辑表达式那么在第三步outer join中还可以把移除的行再次添加回来,而where的移除的最终的。举个简单的例子,有一个学生表(班级,姓名)和一个成绩表(姓名,成绩),我现在需要返回一个x班级的全体同学的成绩,但是这个班级有几个学生缺考,也就是说在成绩表中没有记录。为了得到我们预期的结果我们就需要在on子句指定学生和成绩表的关系(学生.姓名=成绩.姓名)那么我们是否发现在执行第二步的时候,对于没有参加考试的学生记录就不会出现在vt2中,因为他们被on的逻辑表达式过滤掉了,但是我们用left outer join就可以把左表(学生)中没有参加考试的学生找回来,因为我们想返回的是x班级的所有学生,如果在on中应用学生.班级='x'的话,left outer join会把x班级的所有学生记录找回(感谢网友康钦谋__康钦苗的指正,所以只能在where筛选器中应用学生.班级='x' 因为它的过滤是最终的。 

    第六步:group by 子句将中的唯一的值组合成为一组,得到虚拟表vt5。如果应用了group by,那么后面的所有步骤都只能得到的vt5的列或者是聚合函数(count、sum、avg等)。原因在于最终的结果集中只为每个组包含一行。这一点请牢记。 

    第七步:应用cube或者rollup选项,为vt5生成超组,生成vt6. 
    第八步:应用having筛选器,生成vt7。having筛选器是第一个也是为唯一一个应用到已分组数据的筛选器。 
    第九步:处理select子句。将vt7中的在select中出现的列筛选出来。生成vt8. 

    第十步:应用distinct子句,vt8中移除相同的行,生成vt9。事实上如果应用了group by子句那么distinct是多余的,原因同样在于,分组的时候是将列中唯一的值分成一组,同时只为每一组返回一行记录,那么所以的记录都将是不相同的。 

    第十一步:应用order by子句。按照order_by_condition排序vt9,此时返回的一个游标,而不是虚拟表。sql是基于集合的理论的,集合不会预先对他的行排序,它只是成员的逻辑集合,成员的顺序是无关紧要的。对表进行排序的查询可以返回一个对象,这个对象包含特定的物理顺序的逻辑组织。这个对象就叫游标。正因为返回值是游标,那么使用order by 子句查询不能应用于表表达式。排序是很需要成本的,除非你必须要排序,否则最好不要指定order by,最后,在这一步中是第一个也是唯一一个可以使用select列表中别名的步骤。 

    第十二步:应用top选项。此时才返回结果给请求者即用户。 

     

    二、mysql的执行顺序 


    1、SELECT语句定义 

    一个完成的SELECT语句包含可选的几个子句。SELECT语句的定义如下: 
    SQL代码 

    <SELECT clause> [<FROM clause>] [<WHERE clause>] [<GROUP BY clause>] [<HAVING clause>] [<ORDER BY clause>] [<LIMIT clause>] 

    SELECT子句是必选的,其它子句如WHERE子句、GROUP BY子句等是可选的。 
    一个SELECT语句中,子句的顺序是固定的。例如GROUP BY子句不会位于WHERE子句的前面。 

    2、SELECT语句执行顺序 

    SELECT语句中子句的执行顺序与SELECT语句中子句的输入顺序是不一样的,所以并不是从SELECT子句开始执行的,而是按照下面的顺序执行: 

    开始->FROM子句->WHERE子句->GROUP BY子句->HAVING子句->ORDER BY子句->SELECT子句->LIMIT子句->最终结果 

    每个子句执行后都会产生一个中间结果,供接下来的子句使用,如果不存在某个子句,就跳过 
    对比了一下,mysql和sql执行顺序基本是一样的, 标准顺序的 SQL 语句为: 

    select 考生姓名, max(总成绩) as max总成绩 
    
    from tb_Grade 
    
    where 考生姓名 is not null 
    
    group by 考生姓名 
    
    having max(总成绩) > 600 
    
    order by max总成绩 


     在上面的示例中 SQL 语句的执行顺序如下: 

       (1). 首先执行 FROM 子句, 从 tb_Grade 表组装数据源的数据 

       (2). 执行 WHERE 子句, 筛选 tb_Grade 表中所有数据不为 NULL 的数据 

       (3). 执行 GROUP BY 子句, 把 tb_Grade 表按 "学生姓名" 列进行分组(注:这一步开始才可以使用select中的别名,他返回的是一个游标,而不是一个表,所以在where中不可以使用select中的别名,而having却可以使用,感谢网友  zyt1369  提出这个问题)
       (4). 计算 max() 聚集函数, 按 "总成绩" 求出总成绩中最大的一些数值 

       (5). 执行 HAVING 子句, 筛选课程的总成绩大于 600 分的. 

       (7). 执行 ORDER BY 子句, 把最后的结果按 "Max 成绩" 进行排序. 

     

    希望此篇文章能让大家对mysql执行顺序有一个了解,另外为大家推荐两篇MySQL优化的文章:

    MySQL优化之推荐使用规范

    MySQL优化之my.conf配置详解

    大家可关注我的微信公众号:裸睡的猪,后期会为大家推荐更多有用的文章!


     

    展开全文
  • SQL语句执行结果集的获取

    万次阅读 2018-01-28 17:16:23
    数据源在执行完SQL语句后会返回一个结果集对象,将SQL执行结果返回到结果集对象中,应用程序在执行完SQL语句后,解析结果集对象中的结果,得到具体的结果,这次的主要内容是如何解析结果集对象并获取其中的值。...

    上次说到命令对象是用来执行SQL语句的。数据源在执行完SQL语句后会返回一个结果集对象,将SQL执行的结果返回到结果集对象中,应用程序在执行完SQL语句后,解析结果集对象中的结果,得到具体的结果,这次的主要内容是如何解析结果集对象并获取其中的值。

    如何执行SQL语句

    执行SQL语句一般的步骤如下:
    1. 创建ICommandText接口.
    2. 使用ICommandText接口的SetCommandText方法设置SQL命令
    3. 使用ICommandText接口的Excute方法执行SQL语句并接受返回的结果集对象,这个结果集对象一般是IRowset.

    其实OLEDB并不一定非要传入SQL语句,他可以传入简单的命令,只要数据源能够识别,也就是说我们可以根据数据源的不同传入那些只有特定数据源才会支持的命令,已达到简化操作或者实现某些特定功能的目的.
    针对有的SQL语句,我们并不是那么关心它返回了那些数据,比如说Delete语句,insert语句,针对这种情况我们可以将对应返回结果集的参数设置为NULL,比如像下面这样

    pICommandText->Execute(NULL, IID_NULL, NULL, NULL, NULL)

    明确告诉数据源程序不需要返回结果集,这样数据源不会准备结果集,减少了数据源的相关操作,从某种程度上减轻了数据源的负担。

    设置command对象的属性

    与之前数据源对象和会话对象的属性不同,command对象的属性是作用在返回的数据源对象上的,比如我们没有设置对应的更新属性,那么数据源就不允许我们使用结果集进行更新数据的操作。这些属性必须在执行SQL语句得到结果集的操作之前定义好。因为在获得数据源返回的结果集的时候数据源已经设置了对应的属性。
    command对象的属性集ID是PROPSET_ROWSET.该属性集中有很多能够影响结果集对象的属性。
    下面是一个执行SQL语句的例子:

        LPOLESTR lpSql = OLESTR("select * from aa26");
        CreateDBSession(pIOpenRowset);
        HRESULT hRes = pIOpenRowset->QueryInterface(IID_IDBCreateCommand, (void**)&pIDBCreateCommand);
        COM_SUCCESS(hRes, _T("查询接口IDBCreateCommand失败,错误码:%08x\n"), hRes);
    
        hRes = pIDBCreateCommand->CreateCommand(NULL, IID_ICommandText, (IUnknown**)&pICommandText);
        COM_SUCCESS(hRes, _T("创建接口IDBCreateCommand失败,错误码:%08x\n"), hRes);
    
        hRes = pICommandText->SetCommandText(DBGUID_DEFAULT, lpSql);
        COM_SUCCESS(hRes, _T("设置sql语句失败,错误码:%08x\n"), hRes);
    
        DBPROP dbProp[16] = {0};
        DBPROPSET dbPropset[1] = {0};
    
        //设置结果集可以进行增删改操作
        dbProp[0].colid = DB_NULLID;
        dbProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
        dbProp[0].dwPropertyID = DBPROP_UPDATABILITY;
        dbProp[0].vValue.vt = VT_I4;
        dbProp[0].vValue.lVal = DBPROPVAL_UP_DELETE | DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT;
    
        //申请打开书签功能
        dbProp[1].colid = DB_NULLID;
        dbProp[1].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[1].dwPropertyID = DBPROP_BOOKMARKS;
        dbProp[1].vValue.vt = VT_BOOL;
        dbProp[1].vValue.boolVal = VARIANT_TRUE;
    
        //申请打开行查找功能
        dbProp[2].colid = DB_NULLID;
        dbProp[2].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[2].dwPropertyID = DBPROP_IRowsetFind;
        dbProp[2].vValue.vt = VT_BOOL;
        dbProp[2].vValue.boolVal = VARIANT_TRUE;
    
        //申请打开行索引
        dbProp[3].colid = DB_NULLID;
        dbProp[3].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[3].dwPropertyID = DBPROP_IRowsetIndex;
        dbProp[3].vValue.vt = VT_BOOL;
        dbProp[3].vValue.boolVal = VARIANT_TRUE;
    
        //申请打开行定位功能
        dbProp[4].colid = DB_NULLID;
        dbProp[4].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[4].dwPropertyID = DBPROP_IRowsetLocate;
        dbProp[4].vValue.vt = VT_BOOL;
        dbProp[4].vValue.boolVal = VARIANT_TRUE;
    
        //申请打开行滚动功能
        dbProp[5].colid = DB_NULLID;
        dbProp[5].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[5].dwPropertyID = DBPROP_IRowsetScroll;
        dbProp[5].vValue.vt = VT_BOOL;
        dbProp[5].vValue.boolVal = VARIANT_TRUE;
    
        //申请打开行集视图功能
        dbProp[6].colid = DB_NULLID;
        dbProp[6].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[6].dwPropertyID = DBPROP_IRowsetView;
        dbProp[6].vValue.vt = VT_BOOL;
        dbProp[6].vValue.boolVal = VARIANT_TRUE;
    
        //申请打开行集刷新功能
        dbProp[7].colid = DB_NULLID;
        dbProp[7].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[7].dwPropertyID = DBPROP_IRowsetRefresh;
        dbProp[7].vValue.vt = VT_BOOL;
        dbProp[7].vValue.boolVal = VARIANT_TRUE;
    
        //申请打开列信息扩展接口
        dbProp[8].colid = DB_NULLID;
        dbProp[8].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[8].dwPropertyID = DBPROP_IColumnsInfo2;
        dbProp[8].vValue.vt = VT_BOOL;
        dbProp[8].vValue.boolVal = VARIANT_TRUE;
    
        //申请打开数据库同步状态接口
        dbProp[9].colid = DB_NULLID;
        dbProp[9].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[9].dwPropertyID = DBPROP_IDBAsynchStatus;
        dbProp[9].vValue.vt = VT_BOOL;
        dbProp[9].vValue.boolVal = VARIANT_TRUE;
    
        //申请打开行集分章功能
        dbProp[10].colid = DB_NULLID;
        dbProp[10].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[10].dwPropertyID = DBPROP_IChapteredRowset;
        dbProp[10].vValue.vt = VT_BOOL;
        dbProp[10].vValue.boolVal = VARIANT_TRUE;
    
        dbProp[11].colid = DB_NULLID;
        dbProp[11].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[11].dwPropertyID = DBPROP_IRowsetCurrentIndex;
        dbProp[11].vValue.vt = VT_BOOL;
        dbProp[11].vValue.boolVal = VARIANT_TRUE;
    
        dbProp[12].colid = DB_NULLID;
        dbProp[12].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[12].dwPropertyID = DBPROP_IGetRow;
        dbProp[12].vValue.vt = VT_BOOL;
        dbProp[12].vValue.boolVal = VARIANT_TRUE;
    
        //申请打开行集更新功能
        dbProp[13].colid = DB_NULLID;
        dbProp[13].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[13].dwPropertyID = DBPROP_IRowsetUpdate;
        dbProp[13].vValue.vt = VT_BOOL;
        dbProp[13].vValue.boolVal = VARIANT_TRUE;
    
        dbProp[14].colid = DB_NULLID;
        dbProp[14].dwOptions = DBPROPOPTIONS_OPTIONAL;
        dbProp[14].dwPropertyID = DBPROP_IConnectionPointContainer;
        dbProp[14].vValue.vt = VT_BOOL;
        dbProp[14].vValue.boolVal = VARIANT_TRUE;
    
        dbPropset[0].cProperties = 15;
        dbPropset[0].guidPropertySet = DBPROPSET_ROWSET;
        dbPropset[0].rgProperties = dbProp;
    
        hRes = pICommandText->QueryInterface(IID_ICommandProperties, (void**)&pICommandProperties);
        COM_SUCCESS(hRes, _T("查询接口ICommandProperties失败,错误码:%08x\n"), hRes);
    
        hRes = pICommandProperties->SetProperties(1, dbPropset);
        COM_SUCCESS(hRes, _T("设置属性失败,错误码:%08x\n"), hRes);
    
        hRes = pICommandText->Execute(NULL, IID_IRowset, NULL, NULL, (IUnknown**)&pIRowset);
        COM_SUCCESS(hRes, _T("执行sql语句失败,错误码:%08x\n"), hRes);

    这段代码详细的展示了如何执行SQL语句获取结果集并设置COMMANDUI对象的属性。

    结果集对象

    结果集一般是执行完SQL语句后返回的一个代表二维结构化数组的对象。这个结构化对象可以理解为一个与数据表定义相同的一个结构体。而结果集中保存了这个结构体的指针
    下面是结果集对象的详细定义

    CoType TRowset {
       [mandatory]   interface IAccessor;
       [mandatory]   interface IColumnsInfo;
       [mandatory]   interface IConvertType;
       [mandatory]   interface IRowset;
       [mandatory]   interface IRowsetInfo;
       [optional]    interface IChapteredRowset;
       [optional]    interface IColumnsInfo2;
       [optional]    interface IColumnsRowset;
       [optional]    interface IConnectionPointContainer;
       [optional]    interface IDBAsynchStatus;
       [optional]    interface IGetRow;
       [optional]    interface IRowsetChange;
       [optional]    interface IRowsetChapterMember;
       [optional]    interface IRowsetCurrentIndex;
       [optional]    interface IRowsetFind;
       [optional]    interface IRowsetIdentity;
       [optional]    interface IRowsetIndex;
       [optional]    interface IRowsetLocate;
       [optional]    interface IRowsetRefresh;
       [optional]    interface IRowsetScroll;
       [optional]    interface IRowsetUpdate;
       [optional]    interface IRowsetView;
       [optional]    interface ISupportErrorInfo;
       [optional]    interface IRowsetBookmark;
    }

    结果集对象的一般用法

    得到结果集后,它的使用步骤一般如下:
    1. 首先Query出IColumnsInfo接口
    2. 通过调用IColumnsInfo::GetColumnInfo方法得到关于结果集的列的详细信息DBCOLUMNINFO结构的数组,包括:列序号,列名,类型,字节长度,精度,比例等
    3.通过该结构数组,准备一个对应的DBBINDING结构数组,并计算每行数据实际需要的缓冲大小,并填充结构DBBINDING。这个过程一般叫做绑定
    4.利用DBBINDING数组和IAccessor::CreateAccessor方法创建一个数据访问器并得到句柄HACCESSOR
    5. 调用IRowset::GetNextRow遍历行指针到下一行,第一次调用就是指向第一行,并得到行句柄HROW,这个行句柄表示我们访问的当前是结果中的第几行,一般它的值是一个依次递增的整数
    6. 调用IRowset::GetData传入准备好的行缓冲内存指针,以及之前创建的访问器HACCESSOR句柄和HROW句柄。最终行数据就被放置到了指定的缓冲中。循环调用GetNextRow和GetData即可遍历整个二维结果集。

    列信息的获取

    取得结果集对象后,紧接着的操作一般就是获取结果集的结构信息,也就是获取结果集的列信息(有些材料中称为字段信息)要获取列信息,就需要QueryInterface出结果集对象的IColumnsInfo接口,并调用IColumnsInfo::GetColumnInfo方法获得一个称为DBCOLUMNINFO结构体的数组该结构体中反映了列的逻辑结构信息(抽象数据类型)和物理结构信息(内存需求大小等信息)
    函数GetColumnInfo定义如下:

    HRESULT GetColumnInfo (
       DBORDINAL     *pcColumns,
       DBCOLUMNINFO **prgInfo,
       OLECHAR      **ppStringsBuffer);

    第一个参数表示总共有多少列,第二个参数是一个DBCOLUMNINFO,返回一个列信息的数组指针,第三个参数返回一个字符串指针,这个字符串中保存的是个列的名称,每个名称间以\0\0分割。但是我们一般不使用它来获取列名,我们一般使用DBCOLUMNINFO结构的pwszName成员。
    DBCOLUMNINFO定义如下:

    typedef struct tagDBCOLUMNINFO {
       LPOLESTR        pwszName; //列名
       ITypeInfo      *pTypeInfo; //列的类型信息
       DBORDINAL       iOrdinal; //列序号
       DBCOLUMNFLAGS   dwFlags; //列的相关标识
       DBLENGTH        ulColumnSize; //列最大可能的大小,对于字符串来说,它表示的是字符个数
       DBTYPE          wType; //列类型
       BYTE            bPrecision; //精度(它表示小数点后面的位数)
       BYTE            bScale; //表示该列的比例,目前没有用处,一般给的是0
       DBID            columnid; //列信息在数据字典表中存储的ID
    } DBCOLUMNINFO;

    对于columnid成员,DBMS系统一般会有多个系统表来表示众多的信息,比如用户信息,数据库信息,数据表信息等等,其中针对每个表中的列的相关信息DBMS系统使用特定的系统表来存储,而查询这个系统表来获取列信息时使用的就是这个columnid值。

    数据绑定

    一般绑定需要两步,1是获取列信息的DBCOLUMNINFO结构,接着就是根据列信息来填充DBBINDING数据结构。
    有的时候可能会觉得绑定好麻烦啊,还不如直接返回一个缓冲,将所有结果放入里面,应用程序根据需求自己去解析它,这样岂不是更方便。之所以需要绑定,有下面一个理由:
    1. 并不是所有的数据类型都能被应用程序支持,比如说数据库中的NUMBER类型在VC++中找不到对应的数据结构来支持。
    2. 有时一行数据并不能完全读取到内存中,比如说我们给的缓冲不够或者是数据库中的数据本身比较大,比如存储了一个视频文件等等。
    3. 在程序中并不是所有的访问器都是为了读取数据,而且使用返回所有结果的方式太简单粗暴了,比如我只想要一列的数据那个数据可能占用内存不足1K,但是数据库表中某一列数据特别大,可能占用内存会超过一个G,如果全都返回的话太浪费内存了。所以在绑定时候可以灵活的指定返回那些数据,返回数据长度是多少,针对特别大的数据,我们可以指定它只返回部分,比如只返回前面的1K
    4. 使用绑定可以灵活的安排返回数据在内存中的摆放形式。

    绑定结构的定义如下:

    typedef struct tagDBBINDING
    {
        DBORDINAL iOrdinal; //列号
        DBBYTEOFFSET obValue;
        DBBYTEOFFSET obLength;
        DBBYTEOFFSET obStatus;
        ITypeInfo *pTypeInfo; 
        DBOBJECT *pObject;
        DBBINDEXT *pBindExt;
        DBPART dwPart;
        DBMEMOWNER dwMemOwner;
        DBPARAMIO eParamIO;
        DBLENGTH cbMaxLen; //数据的最大长度,一般给我们为这个列的数据准备的缓冲的长度
        DWORD dwFlags;
        DBTYPE wType; //将该列转化为何种数据类型展示
        BYTE bPrecision;
        BYTE bScale;
    }DBBINDING;

    参数的详细说明:
    1. obValue、obLength、obStatus:数据源在返回结果的时候一般会返回该列信息的三中数据,数据长度、数据状态、数据值。数据状态表示数据源在提供数据的一个状态信息,比如该列信息为空时它会返回一个DBSTATUS_S_ISNULL,列数据比较长,而提供的数据可能不够,这个时候会返回一个状态表示发生了截断。而数据长度表示返回结果的长度。这个值是返回的数据对应的字节长度,注意这里需要与前面ulColumnSize区分开来。三个数据在内存中摆放的顺序如下:
    数据摆放
    其中每列数据都是按照status length value结构排布,而不同的列的数据按照顺序依次向后排放,这个内存的布局有点像结构体数组在内存中的的布局方式。而绑定结构中的obValue、obLength、obStatus规定了它们三者在一块内存缓冲中的偏移,要注意后面一列的开始位置是在前面一列的结束位置而不是所有数据都是从0开始。
    2. dwPart:前面说数据源返回结果中有3个部分,但是我们可以指定数据源返回这3个部分的哪些部分,它的值是一些标志位,根据这些标志来决定需要返回哪些数据,不需要返回哪些数据.它的值主要有:DBPART_LENGTH、 DBPART_STATUS、DBPART_VALUE;
    3. dwMemOwner,这个值表示将使用何种内存缓冲来保存数据源返回的结果,我们一般使用DBMEMOWNER_CLIENTOWNED,表示使用用户自定义内存的方式,即这个缓冲需要自行准备。
    4. eParamIO:我们将返回的值做何种用途,DBPARAMIO_NOTPARAM表示不做特殊用途,DBPARAMIO_INPUT,作为输入值,一般在需要更新列数据的时候使用这个标志,DBPARAMIO_OUTPUT,作为输出值,这个输出时相对于数据源来说的,表示输出到应用程序程序缓冲,作为展示用。
    5. wType:将数据源中的原始数据做何种类型的转化,比如原来数据库中存储的是整数的123456,而这个值是DBTYPE_WSTR的话,数据源中的结果会被转化为字符串的”123456”,放入到缓冲中。

    DBBINDING 与DBCOLUMNSINFO结构的比较

    它们二者中有许多数据成员是相同的,表示的含义也基本相同,但是二者也有显著的区别:
    1. DBCOLUMNINFO是数据提供者给使用者的信息,它是固定的,对相同的查询来说,列总是相同的,因此数据提供者返回的 DBCOLUMNINFO数组也是固定的.而DBBINDING是作为数据消费者创建之后给数据提供者的一个结构数组,它的内容则由调用者来完全控制,通过这个结构可以指定数据提供者最终将数据摆放成调用者指定的格式,并进行指定的数据类型转换.针对相同的查询我们可以指定不同的DBBINDINGS结构。
    2. DBCOLUMNINFO反映的是二维结果集的原始列结构信息而DBBINDING则反映的是二维结果集数据最终按要求摆放在内存中的样式
    下面是一个针对绑定的列子:

    ExecSql(pIOpenRowset, pIRowset);
    
        //创建IColumnsInfo接口
        HRESULT hRes = pIRowset->QueryInterface(IID_IColumnsInfo, (void**)&pIColumnsInfo);
        COM_SUCCESS(hRes, _T("查询接口IComclumnsInfo,错误码:%08x\n"), hRes);
    
        //获取结果集的详细信息
        hRes = pIColumnsInfo->GetColumnInfo(&cClumns, &rgColumnInfo, &lpClumnsName);
        COM_SUCCESS(hRes, _T("获取列信息失败,错误码:%08x\n"), hRes);
    
        //绑定
        pDBBindings = (DBBINDING*)MALLOC(sizeof(DBBINDING) * cClumns);
        for (int iRow = 0; iRow < cClumns; iRow++)
        {
            pDBBindings[iRow].bPrecision = rgColumnInfo[iRow].bPrecision;
            pDBBindings[iRow].bScale = rgColumnInfo[iRow].bScale;
            pDBBindings[iRow].cbMaxLen = rgColumnInfo[iRow].ulColumnSize * sizeof(WCHAR);
            if (rgColumnInfo[iRow].wType == DBTYPE_I4)
            {
                //数据库中行政单位的长度最大为6位
                pDBBindings[iRow].cbMaxLen = 7 * sizeof(WCHAR);
            }
            pDBBindings[iRow].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            pDBBindings[iRow].dwPart = DBPART_LENGTH | DBPART_STATUS | DBPART_VALUE;
            pDBBindings[iRow].eParamIO = DBPARAMIO_NOTPARAM;
            pDBBindings[iRow].iOrdinal = rgColumnInfo[iRow].iOrdinal;
            pDBBindings[iRow].obStatus = dwOffset;
            pDBBindings[iRow].obLength = dwOffset + sizeof(DBSTATUS);
            pDBBindings[iRow].obValue = dwOffset + sizeof(DBSTATUS) + sizeof(ULONG);
            pDBBindings[iRow].wType = DBTYPE_WSTR;
    
            dwOffset = dwOffset + sizeof(DBSTATUS) + sizeof(ULONG) + pDBBindings[iRow].cbMaxLen * sizeof(WCHAR);
            dwOffset = COM_ROUNDUP(dwOffset); //进行内存对齐
        }
        //创建访问器
        hRes = pIRowset->QueryInterface(IID_IAccessor, (void**)&pIAccessor);
        COM_SUCCESS(hRes, _T("查询IAccessor接口失败错误码:%08x\n"), hRes);
        hRes = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, cClumns, pDBBindings, 0, &hAccessor, NULL);
        COM_SUCCESS(hRes, _T("创建访问器失败错误码:%08x\n"), hRes);
    
        //输出列名信息
        DisplayColumnName(rgColumnInfo, cClumns);
        //分配对应的内存
        pData = MALLOC(dwOffset * cRows);
        while (TRUE)
        {
            hRes = pIRowset->GetNextRows(DB_NULL_HCHAPTER, 0, cRows, &uRowsObtained, &phRows);
            if (hRes != S_OK && uRowsObtained != 0)
            {
                break;
            }
            ZeroMemory(pData, dwOffset * cRows);
            //显示数据
            for (int i = 0; i < uRowsObtained; i++)
            {
                pCurrData = (BYTE*)pData + dwOffset * i;
                pIRowset->GetData(phRows[i], hAccessor, pCurrData);
                DisplayData(pDBBindings, cClumns, pCurrData);
            }
    
            //清理hRows
            pIRowset->ReleaseRows(uRowsObtained, phRows, NULL, NULL, NULL);
            CoTaskMemFree(phRows);
            phRows = NULL;
        }
    
    //显示列名称
    void DisplayColumnName(DBCOLUMNINFO *pdbColumnInfo, DBCOUNTITEM iDbCount)
    {
        COM_DECLARE_BUFFER();
        for (int iColumn = 0; iColumn < iDbCount; iColumn++)
        {
            COM_CLEAR_BUFFER();
            TCHAR wszColumnName[MAX_DISPLAY_SIZE + 1] =_T("");
            size_t dwSize = 0;
            StringCchLength(pdbColumnInfo[iColumn].pwszName, MAX_DISPLAY_SIZE, &dwSize);
            dwSize = min(dwSize, MAX_DISPLAY_SIZE);
            StringCchCopy(wszColumnName, MAX_DISPLAY_SIZE, pdbColumnInfo[iColumn].pwszName);
    
            COM_PRINTF(wszColumnName);
            COM_PRINTF(_T("\t"))
        }
        COM_PRINTF(_T("\n"));
    }
    
    //显示数据
    void DisplayData(DBBINDING *pdbBindings, DBCOUNTITEM iDbColCnt, void *pData)
    {
        COM_DECLARE_BUFFER();
        for (int i = 0; i < iDbColCnt; i++)
        {
            COM_CLEAR_BUFFER();
            DBSTATUS status = *(DBSTATUS*)((PBYTE)pData + pdbBindings[i].obStatus);
            ULONG uSize = (*(ULONG*)((PBYTE)pData + pdbBindings[i].obLength)) / sizeof(WCHAR);
            PWSTR pCurr = (PWSTR)((PBYTE)pData + pdbBindings[i].obValue); 
            switch (status)
            {
                case DBSTATUS_S_OK:
                case DBSTATUS_S_TRUNCATED:
                    COM_PRINTF(_T("%s\t"), pCurr);
                    break;
                case DBSTATUS_S_ISNULL:
                    COM_PRINTF(_T("%s\t"), _T("(null)"));
                    break;
                default:
                    break;
            }
        }
    
        COM_PRINTF(_T("\n"));
    }

    在使用前一个列子中的方法设置对应的属性并执行SQL语句后,得到一个结果集,然后调用对应的Query方法,得到一个pIColumnsInfo接口,接着调用接口的GetColumnsInfo方法,获取结构的具体信息。
    最需要注意的是绑定部分的代码,根据返回的具体列数,我们定义了一个对应的绑定结构的数组,将每个赋值,赋值的时候定义了一个dwOffset结构来记录当前使用内存的情况,这样每次在循环执行一次后,它的位置永远在上一个列信息缓冲的尾部,这样我们可以很方便的进行偏移的计算。
    绑定完成后这个dwOffset的值就是所有列使用的内存的总大小,因此在后面利用这个值分配一个对应长度的内存。然后循环调用GetNextRows、GetData方法依次获取每行、每列的数据。最后调用相应的函数来进行显示,至此就完成了数据的读取操作。

    最后,我发现码云上的代码片段简直就是为保存平时例子代码而生的,所以后面的代码将不再在GitHub上更新了,而换到码云上面。
    源代码查看


    展开全文
  • SQL语句执行顺序

    千次阅读 多人点赞 2018-03-01 14:19:30
    可以参考另一篇:sql逻辑执行顺序MySQL的语句执行顺序MySQL的语句一共分为11步,如下图所标注的那样,最先执行的总是FROM操作,最后执行的是LIMIT操作。其中每一个操作都会产生一张虚拟的表,这个虚拟的表作为一个...

    可以参考另一篇:sql逻辑执行顺序

    MySQL的语句执行顺序

    MySQL的语句一共分为11步,如下图所标注的那样,最先执行的总是FROM操作,最后执行的是LIMIT操作。其中每一个操作都会产生一张虚拟的表,这个虚拟的表作为一个处理的输入,只是这些虚拟的表对用户来说是透明的,但是只有最后一个虚拟的表才会被作为结果返回。如果没有在语句中指定某一个子句,那么将会跳过相应的步骤。

    下面我们来具体分析一下查询处理的每一个阶段

    1. FORM: 对FROM的左边的表和右边的表计算笛卡尔积。产生虚表VT1
    2. ON: 对虚表VT1进行ON筛选,只有那些符合<join-condition>的行才会被记录在虚表VT2中。
    3. JOIN: 如果指定了OUTER JOIN(比如left join、 right join),那么保留表中未匹配的行就会作为外部行添加到虚拟表VT2中,产生虚拟表VT3, rug from子句中包含两个以上的表的话,那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤,一直到处理完所有的表为止。
    4. WHERE: 对虚拟表VT3进行WHERE条件过滤。只有符合<where-condition>的记录才会被插入到虚拟表VT4中。
    5. GROUP BY: 根据group by子句中的列,对VT4中的记录进行分组操作,产生VT5.
    6. CUBE | ROLLUP: 对表VT5进行cube或者rollup操作,产生表VT6.
    7. HAVING: 对虚拟表VT6应用having过滤,只有符合<having-condition>的记录才会被 插入到虚拟表VT7中。
    8. SELECT: 执行select操作,选择指定的列,插入到虚拟表VT8中。
    9. DISTINCT: 对VT8中的记录进行去重。产生虚拟表VT9.
    10. ORDER BY: 将虚拟表VT9中的记录按照<order_by_list>进行排序操作,产生虚拟表VT10.
    11. LIMIT:取出指定行的记录,产生虚拟表VT11, 并将结果返回。

     

    SQL语句执行顺序

    查询语句中select from where group by having order by的执行顺序
     
    1.查询中用到的关键词主要包含六个,并且他们的顺序依次为 
    select--from--where--group by--having--order by 
     
    其中select和from是必须的,其他关键词是可选的,这六个关键词的执行顺序 
    与sql语句的书写顺序并不是一样的,而是按照下面的顺序来执行 
    from--where--group by--having--select--order by, 
    from:需要从哪个数据表检索数据 
    where:过滤表中数据的条件 
    group by:如何将上面过滤出的数据分组 
    having:对上面已经分组的数据进行过滤的条件  
    select:查看结果集中的哪个列,或列的计算结果 
    order by :按照什么样的顺序来查看返回的数据 
     
    2.from后面的表关联,是自右向左解析的 
    而where条件的解析顺序是自下而上的。 
     
    也就是说,在写SQL文的时候,尽量把数据量大的表放在最右边来进行关联, 
    而把能筛选出大量数据的条件放在where语句的最下面。

     

    3.连接查询的执行顺序

    SQL语句中join连表时on和where后都可以跟条件,那么对查询结果集,执行顺序,效率是如何呢?
    通过查询资料发现:
    区别:
    on是对中间结果进行筛选,where是对最终结果筛选。
    执行顺序:
    先进行on的过滤, 而后才进行join。
    效率:
    如果是inner join, 放on和放where产生的结果一样, 但没说哪个效率速度更高? 如果有outer join (left or right), 就有区别了, 因为on生效在先, 已经提前过滤了一部分数据, 而where生效在后.

     
     
    SQL Select语句完整的执行顺序【从DBMS使用者角度】: 
      1、from子句组装来自不同数据源的数据; 
      2、where子句基于指定的条件对记录行进行筛选; 
      3、group by子句将数据划分为多个分组; 
      4、使用聚集函数进行计算; 
      5、使用having子句筛选分组; 
      6、计算所有的表达式; 
      7、使用order by对结果集进行排序。 

    SQL Select语句的执行步骤【从DBMS实现者角度,这个对我们用户意义不大】: 
      1)语法分析,分析语句的语法是否符合规范,衡量语句中各表达式的意义。 
      2) 语义分析,检查语句中涉及的所有数据库对象是否存在,且用户有相应的权限。 
      3)视图转换,将涉及视图的查询语句转换为相应的对基表查询语句。 
      4)表达式转换, 将复杂的 SQL 表达式转换为较简单的等效连接表达式。 
      5)选择优化器,不同的优化器一般产生不同的“执行计划” 
      6)选择连接方式, ORACLE 有三种连接方式,对多表连接 ORACLE 可选择适当的连接方式。 
      7)选择连接顺序, 对多表连接 ORACLE 选择哪一对表先连接,选择这两表中哪个表做为源数据表。 
      8)选择数据的搜索路径,根据以上条件选择合适的数据搜索路径,如是选用全表搜索还是利用索引或是其他的方式。 
      9)运行“执行计划”。 
     
     
     

    了解下T-SQL对查询逻辑处理。

    T-SQL逻辑查询的各个阶段

    (5)SELECT DISTINCT TOP(<top_specification>) <select_list>                      

    (1)FROM <left_table> <join_type> JOIN <right_table> ON <on_predicate> 

    (2)WHERE <where_predicate>

    (3)GROUP BY <group_by_specification>

    (4)HAVING <having_predicate>

    (6)ORDER BY <order_by_list>

    T-SQL在查询各个阶级分别干了什么

    (1)FROM 阶段

        FROM阶段标识出查询的来源表,并处理表运算符。在涉及到联接运算的查询中(各种join),主要有以下几个步骤:

      a.求笛卡尔积。不论是什么类型的联接运算,首先都是执行交叉连接(cross join),求笛卡儿积,生成虚拟表VT1-J1。

          b.ON筛选器。这个阶段对上个步骤生成的VT1-J1进行筛选,根据ON子句中出现的谓词进行筛选,让谓词取值为true的行通过了考验,插入到VT1-J2。

          c.添加外部行。如果指定了outer join,还需要将VT1-J2中没有找到匹配的行,作为外部行添加到VT1-J2中,生成VT1-J3。

        经过以上步骤,FROM阶段就完成了。概括地讲,FROM阶段就是进行预处理的,根据提供的运算符对语句中提到的各个表进行处理(除了join,还有apply,pivot,unpivot)

    (2)WHERE阶段

         WHERE阶段是根据<where_predicate>中条件对VT1中的行进行筛选,让条件成立的行才会插入到VT2中。

    (3)GROUP BY阶段

          GROUP阶段按照指定的列名列表,将VT2中的行进行分组,生成VT3。最后每个分组只有一行。

    (4)HAVING阶段

          该阶段根据HAVING子句中出现的谓词对VT3的分组进行筛选,并将符合条件的组插入到VT4中。

    (5)SELECT阶段

      这个阶段是投影的过程,处理SELECT子句提到的元素,产生VT5。这个步骤一般按下列顺序进行

            a.计算SELECT列表中的表达式,生成VT5-1。

            b.若有DISTINCT,则删除VT5-1中的重复行,生成VT5-2

            c.若有TOP,则根据ORDER BY子句定义的逻辑顺序,从VT5-2中选择签名指定数量或者百分比的行,生成VT5-3

    (6)ORDER BY阶段

         根据ORDER BY子句中指定的列明列表,对VT5-3中的行,进行排序,生成游标VC6. 

    One example for the inner join and where condition 

    select coulumns from table_01 inner join table_02 on 01.col1=02.col2 where 01 = 'A' and 02='B' with ur ;

    from the db2 plan it will Optimized Statement like below  which remove the join on condition and using where replace it :

     

    select coulumns from table_01 , table_02  where 01 = 'A' and 02='B'  and 01.col1=02.col2 with ur ;

     

    上面优化后的sql 未必是最佳的 ,有可能程序index 会用不到的 。

    ================华丽分割线 ==============

     

    详细说明

    from 子句--执行顺序为从后往前、从右到左

    表名(最后面的那个表名为驱动表,执行顺序为从后往前, 所以数据量较少的表尽量放后)

    oracle 的解析器按照从右到左的顺序处理,FROM 子句中的表名,FROM 子句中写在最后的表(基础表 driving table)将被最先处理,即最后的表为驱动表,在FROM 子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3 个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指被其他表所引用的表

    多表连接时,使用表的别名并把别名前缀于每个Column上。可以减少解析的时间并减少那些由Column 歧义引起的语法错误.

    where子句--执行顺序为自下而上、从右到左

    ORACLE 采用自下而上从右到左的顺序解析Where 子句,根据这个原理,表之间的连接必须写在其他Where 条件之前, 可以过滤掉最大数量记录的条件必须写在Where 子句的末尾。

     

    group by--执行顺序从左往右分组

    提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉。即在GROUP BY前使用WHERE来过虑,而尽量避免GROUP BY后再HAVING过滤。

     

    having 子句----很耗资源,尽量少用

    避免使用HAVING 子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作.

    如果能通过Where 子句在GROUP BY前限制记录的数目,那就能减少这方面的开销.
    (非oracle 中)on、where、having 这三个都可以加条件的子句中,on 是最先执行,where 次之,having 最后,因为on 是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,

    where 也应该比having 快点的,因为它过滤数据后才进行sum,在两个表联接时才用on 的,所以在一个表的时候,就剩下where 跟having比较了。

    在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,那它们的结果是一样的,只是where 可以使用rushmore 技术,而having 就不能,在速度上后者要慢。
    如果要涉及到计算的字段,就表示在没计算之前,这个字段的值是不确定的,where 的作用时间是在计算之前就完成的,而having 就是在计算后才起作用的,所以在这种情况下,两者的结果会不同。

    在多表联接查询时,on 比where 更早起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由where 进行过滤,然后再计算,计算完后再由having 进行过滤。

    由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里。

     

    select子句--少用*号,尽量取字段名称。

    ORACLE 在解析的过程中, 会将依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 使用列名意味着将减少消耗时间。

    sql 语句用大写的;因为 oracle 总是先解析 sql 语句,把小写的字母转换成大写的再执行

    order by子句--执行顺序为从左到右排序,很耗资源

    展开全文
  • mysql语句执行顺序

    千次阅读 2018-04-29 17:42:56
    MySQL的语句执行顺序MySQL的语句一共分为11步,如下图所标注的那样,最先执行的总是FROM操作,最后执行的是LIMIT操作。其中每一个操作都会产生一张虚拟的表,这个虚拟的表作为一个处理的输入,只是这些虚拟的表对...

    MySQL的语句执行顺序

    MySQL的语句一共分为11步,如下图所标注的那样,最先执行的总是FROM操作,最后执行的是LIMIT操作。其中每一个操作都会产生一张虚拟的表,这个虚拟的表作为一个处理的输入,只是这些虚拟的表对用户来说是透明的,但是只有最后一个虚拟的表才会被作为结果返回。如果没有在语句中指定某一个子句,那么将会跳过相应的步骤。

    下面我们来具体分析一下查询处理的每一个阶段

    FORM: 对FROM的左边的表和右边的表计算笛卡尔积。产生虚表VT1
    ON: 对虚表VT1进行ON筛选,只有那些符合<join-condition>的行才会被记录在虚表VT2中。
    JOIN: 如果指定了OUTER JOIN(比如left join、 right join),那么保留表中未匹配的行就会作为外部行添加到虚拟表VT2中,产生虚拟表VT3, rug from子句中包含两个以上的表的话,那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤,一直到处理完所有的表为止。
    WHERE: 对虚拟表VT3进行WHERE条件过滤。只有符合<where-condition>的记录才会被插入到虚拟表VT4中。
    GROUP BY: 根据group by子句中的列,对VT4中的记录进行分组操作,产生VT5.
    CUBE | ROLLUP: 对表VT5进行cube或者rollup操作,产生表VT6.
    HAVING: 对虚拟表VT6应用having过滤,只有符合<having-condition>的记录才会被 插入到虚拟表VT7中。
    SELECT: 执行select操作,选择指定的列,插入到虚拟表VT8中。
    DISTINCT: 对VT8中的记录进行去重。产生虚拟表VT9.
    ORDER BY: 将虚拟表VT9中的记录按照<order_by_list>进行排序操作,产生虚拟表VT10.
    LIMIT:取出指定行的记录,产生虚拟表VT11, 并将结果返回


    转载自http://www.cnblogs.com/rollenholt/p/3776923.htm

    展开全文
  • Mysql 语句执行顺序

    万次阅读 多人点赞 2016-04-26 21:51:48
    在开发中涉及到数据库,基本上只用到了sql语句,如何写sql以及对其进行优化就比较重要,那些mysql的厚本书籍针对的是DBA,我们只需要学习其中的sql就可以了。 2.既然会写sql是目标,那么怎么才能写好sql.学习下面几...
  • 如果是对MySQL整个表数据导出,可以参照文章:http://www.crazyant.net/1355.html然而也会遇到的场景是,需要执行一个SQL语句,然后将SQL语句结果输出到文件;方法一:使用MySQL的select * into outfile ‘/tmp/rs...
  • 下面程序段中带下划线的语句执行次数的数量级是( nlog2nnlog_2nnlog2​n )。 i:=1; WHILE i<n BEGIN FOR j:=1 TO n DO x:=x+1; i:=i*2; END 分析: i:=1; WHILE i<n BEGIN FOR j:=1 TO n DO x:=x+1; ...
  • 关于goto语句执行问题

    2015-10-09 10:12:53
    假设第a行有个goto语句,转到了下面的第m行,那么goto语句执行完后,继续往下执行,碰到了第m行,还会继续执行第m行吗?若第m行也是个goto语句呢?
  • finally语句与return语句执行顺序

    千次阅读 2017-11-10 18:19:09
    网上有很多人探讨Java中异常捕获机制try...catch...finally块中的finally语句是不是一定会被执行?很多人都说不是,当然他们的回答是正确的,经过我试验,至少有两种情况下finally语句是不会被执行的: try语句...
  • for循环语句执行顺序

    千次阅读 2019-05-07 15:22:28
    for循环在编程中经常遇到,这里我们探究一下其中语句执行顺序,以更加准确的确定 代码演示 结构说明for (a初始条件; b循环判断条件; c循环过程表达式) { d循环体 } a.初始条件:对刚开始执行循环体做...
  • mysql更新语句执行的时候,如果没有数据不会报错。下面是我做的实验。 首先执行建表语句:CREATE TABLE test (id VARCHAR(20),NAME VARCHAR(20)) 再执行更新语句:UPDATE test SET NAME = '1' WHERE id = '1' ...
  • Oracle sql语句执行顺序

    千次阅读 2017-11-16 22:58:23
    一、sql语句执行步骤: 1)语法分析,分析语句的语法是否符合规范,衡量语句中各表达式的意义。 2)语义分析,检查语句中涉及的所有数据库对象是否存在,且用户有相应的权限。 3)视图转换,将涉及视图的查询语句...
  • 这是在网上找到的一张流程图,写的比较好,大家可以先看图,然后看详细阅读下面的各个步骤。 执行流程: 1.连接验证及解析 客户端与MySQL Server建立连接,发送语句给MySQL Server,接收到后会针对这条语句创建...
  • While中语句执行顺序的问题

    千次阅读 2015-09-27 23:09:01
    对于花括号的语句执行顺序,从上到下依次执行,也就是先执行语句1,再接着执行语句2. 举下面的例子: #include main() {  int i=1;  while(i  {  printf("%d\n",i);  i++;  } }  执行结果如下: 而如果将...
  • MySQL查询语句执行的过程

    千次阅读 2016-09-01 19:38:05
    背景 介绍MySQL语句执行select的过程过程概览 客户端发送一条查询给服务器; 服务器先会检查查询缓存,如果命中了缓存,则立即返回存储在缓存中的结果。否则进入下一阶段; 服务器端进行SQL解析、预处理,再由优化器...
  • 今天在使用SQL语句做查询任务的时候发现,在数据库中可以直接执行语句,放在程序中结果却是None,于是乎,就实践了一下,下面是具体的实践。 #!usr/bin/env python # encoding:utf-8 ''' __Author__:沂水寒城 ...
  • SQL 查询语句执行 SELECT?兄弟你认真的么?

    万次阅读 多人点赞 2020-05-02 19:57:21
    SQL 查询的执行顺序是怎样的? 好像这个问题应该很好回答,毕竟自己已经写了无数个 SQL 查询了,有一些还很复杂的。还装不了这个逼了?! 但事实是,我仍然很难确切地说出它的顺序是怎样的。 言归正传,...
  • Mysql查询语句执行过程及运行原理

    万次阅读 多人点赞 2018-10-22 22:36:21
    Mysql查询语句执行原理 数据库查询语句如何执行? DML语句首先进行语法分析,对使用sql表示的查询进行语法分析,生成查询语法分析树。 语义检查:检查sql中所涉及的对象以及是否在数据库中存在,用户是否具有操作...
  • Oracle查询SQL语句执行的耗时 2018年07月10日 19:11:44 码农云帆哥 阅读数:1106  版权声明:本文为博主原创文章,未经博主允许不得转载。原创不易,转载请注明出处。 https://blog.csdn.net/sinat_27933...
  • Postgresql查看SQL语句执行效率

    千次阅读 2017-11-20 15:22:57
    Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看 SQL 语句执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好的优化语句。...
  • 网站或服务的性能关键点很大程度在于数据库的设计(假设你选择了合适的语言开发框架)...但对MySQL复杂查询语句执行过程和内部机制,MySQL Optimizer本身所做优化以及查询语句调整对性能所产生的影响及其原因知之甚少。
  • Java中 if-else if- else语句执行流程

    千次阅读 2020-05-21 10:32:52
    突然间想到这个问题:在if-else if- else语句块中,如果所有if中的条件都为真,是每个if对应的语句执行呢?还是只执行第一个条件为真的if对应的语句呢?答案是后者。下面是示例代码: 由此总结if-else if- else...
  • return语句执行流程详解

    千次阅读 2018-07-13 09:02:10
    今天去逛论坛 时发现了一个很有趣的问题: 谁能给我我解释一下这段程序的结果为什么是:2.而不是:3 代码如下: class Test { public int aaa() { int x = 1; try { return ++x;...
  • EF执行SQL语句

    千次阅读 2018-09-19 09:37:17
    下面介绍如何在EF中执行SQL语句。 1.EF执行 SQL查询 string sql = "SELECT sStuID,sStuName FROM [dbo].[Students] WHERE sClassID = @classID"; var student = db.Database.SqlQue...
  • 查看sql语句执行时间

    千次阅读 2009-07-09 13:22:00
    资料来自于:http://technet.microsoft.com/zh-cn/library/ms187735(SQL.90).aspx SET SHOWPLAN_ALL (Transact-SQL) 使 Microsoft SQL Server 不执行 Transact-SQL 语句。SQL Server 返回有关语句执行情况的详细信
  • 一条SQL语句是如何执行的?

    千次阅读 2019-06-01 11:22:35
    下面进入正题:一条SQL语句是如何进行的? 对于这个问题,我想将其分为两个问题来回答,分别是: 一条查询SQL是如何执行的? 一条更新SQL是如何执行的? 我们都知道MySQL内部是分为Server层和存储引擎层的;每个...
  • java for循环里面执行sql语句操作,有效结果只有一次,只执行了一次sql mybatis 循环执行update生效一次 实际只执行一次 java后台controller中,for循环执行数据库操作,但是发现实际仅仅执行了一次,或者说...
  • 对于 if-else 语句,它是 单条件双分支语句,即程序的执行流程是根据 一个条件来控制的; 如下代码演示了存在多个 if - else 时的执行顺序: int test11 = 2; if (test11 > 1) { // if语句判断 int test...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,032,497
精华内容 412,998
关键字:

下面语句的执行结果是