none
如何解析sql语句 RRS feed

  • 问题

  • 我想获取一段sql语句在 mssql2005下解析成的语句,
    主要是想获取这个sql所用到的所有的表的名字。(ps:复杂的sql语句的)
    请高手帮忙  在线等~  
    我的意思是要从用户输入的sql语句中提取该语句中所用的表
    或者是:
    sql 执行的步骤

    1. 解析器

    第 1 阶段是解析器阶段,它将 SQL 文本转换成语法树。这个阶段不查找系统目录中的任何信息,不访问数据库。

    2. 语义分析

    第 2 阶段分析由解析器创建的语法树,并产生用于查询的查询控制块和表达式树。要构建这些内部数据结构,它执行以下操作:

    验证对象

    第 2 阶段访问数据库中不同的系统目录,以验证查询所引用的所有数据库对象(诸如表、列、视图、类型、UDR 等等)是否都存在。它在数据库中找到这些对象的标识,然后创建查询控制块和表达式树。


    我要的就是验证对象步骤里的表的信息

    蜗牛
    2009年3月24日 1:37

答案

  • 你可以使用QueryPlan分析
    set
     showplan_xml on
    
    go
    SELECT
         Categories.CategoryID, Products.ProductID, Products.ProductCode, Products.ProductName
    FROM
             Products INNER
     JOIN
    
                          Categories_Products ON
     Products.ProductID = Categories_Products.ProductID INNER
     JOIN
    
                          Categories ON
     Categories_Products.CategoryID = Categories.CategoryID
    go
    set
     showplan_xml off
    
    go
        
    
    然后分析返回的query plan中<object >节中的table就可以了

    我是抓了一个Trace看到的
    2009年3月30日 10:20

全部回复

  • 没明白你的意思,在程序里面解析还是在数据库中拦截解析?
    2009年3月24日 1:52
  •  
    select  
        distinct O2.Name as TableName, 'name' = (s.name + '.' + o.name), o.name as ProcName, 
        type = substring(v.name, 5, 16) 
    from sys.objects o, master.dbo.spt_values v, sysdepends d,sys.schemas s,sys.objects O2 
    where o.object_id = d.id and O2.object_id=d.depid 
    and o.type = substring(v.name,1,2) collate database_default and v.type = 'O9T' 
    and o.schema_id = s.schema_id and o.Name='存儲過程' 
    and deptype < 2 
     


    吳熹
    2009年3月24日 4:47
    版主
  • SQL语句不能执行到数据库,截取sql语句里的表达式
    从良流氓*十三
    2009年3月24日 8:53
  • 楼主,你好

    不明白你上面的回复是什么意思?能否详述,谢谢。

    Microsoft Online Community Support
    2009年3月26日 3:17
  • 简单的说  用户输入一段sql语句   比如 select * from table
    然后我要想办法拿到table的名字

    用户输入的sql语句 会很复杂  有时候还会用到临时表
    我要的是 定义的临时表 也要转成 实际的表的名字

    例如

    Select Row_Number() Over(Order By B.Admincode, B.PartNo) AS Rownumber, b.AdminCode, a.*

    into #PartLocation

    From MCS_PartLocation A Inner Join

             MCS_Part B On

                       A.PartNo = B.PartNo And

                       A.Manufacturer = B.Manufacturer And

                       A.Station = B.Station And

                       A.Owner = B.Owner

    Where AvailabilityStatus = 'T'

    go

     

     

    Insert txdb_temp_mcs.DBO.TransferOwnerSeqNo_BG

    Select  Rownumber AS RowID,

             PartlocationID as OldPartlocationID,     

             null AS NewMRNo,

             null AS NewMRLineNo,

        null AS JobCostID_Issue_UP,

             null AS CostDetailID_Issue_UP,

        null AS JobCostID_Issue_P,

             null AS CostDetailID_Issue_P,

             null AS NewPONo,

             null AS NewPOLineNo,

        null AS NewGRNNo,

        null AS PlinfoNO,

             null AS CostDetailID_Binning,

             null as FreezeNo,

             null as newOwner

    From #PartLocation

    go


    从良流氓*十三
    2009年3月26日 3:27
  • 楼主,您好,
    我个人建议您好好研究研究LINQ TO SQL,我相信您目前遇到的所有问题LINQ 可以帮你解决。

    我看了您的意思:
    1. 想预先生成SQL 语句,等到最后要取数据的时候才执行这条语句,而LINQ 就是这样的机制;
    2. 想验证一下内容的正确性,LINQ的语法已经帮您过滤了,否则您的代码在编译时就出错了;
    3. 您好像想跨表,跨数据库查找数据,您可以看看我以前写的一段代码,
    http://www.cnblogs.com/OceanChen/archive/2009/01/07/1370934.html

    2009年3月27日 9:17
    版主
  • 这种需求我以前遇到过类似的

    实现模糊查询,用户通过UI自己组合相应的查询语句,系统根据功能提供可以查询的实体,并根据所选择的实体关联关系提供可以使用的过滤条件,最终通过实体和和条件执行相应的查询。我以前使用NHibernate通过实体关联和反射生成HQL实现过,如果使用LINQToSQL,需要动态生成LAMDA表达式,这个在LINQ中也是支持的
    可以看看这个参考资料
    http://msdn.microsoft.com/en-us/vbasic/bb688085.aspx
    2009年3月30日 1:48
  • 能否使用正则表达式来分析用户sql语句,实现你的要求:
    我的意思是要从用户输入的sql语句中提取该语句中所用的表”

    2009年3月30日 3:36
  • 我觉得解决你这个问题的思路

    就是分析SQL 语句中的每一个词,然后在sys.objects中进行查询。如果找到了,并且根据信息判断是不是用户表。


    2009年3月30日 3:46
  • 谢谢各位的答复

    我的需求是  我要在某个表里自己设定用户的数据库权限(不通过SQL2005去定义的),后台登陆的用户名和密码是这个数据库的owner,所以我必须获取到用户登录到我的软件界面的时候,他所输入的SQL语句所使用到的table or view  然后通过我自定义的数据库去获取该用户的权限。

    用正则表达式我还在分析,不过这个方法太笨,如果用户使用了table的别名或是临时表,那就会有问题。不过也是种方法。
    用LINQ:用户是可以导入自己写的SQL语句的,有可能会很复杂,我需要的是先获取他所用到的所有的table or view 而不是去数据库里执行

    Howey Huo  你的方法如果是找到有权限的table,还可以,如果他select一个没有权限的table 那你的方法就没办法判断了 

    最好最好的方案是: 把用户输入的sql语句,交给sql2005 去分析语义,分析语义的步骤中有一个步骤是验证对象, 如果这里能截获出 sql2005的验证对象的所有信息,那我就可以从这里获取 这段SQL语句所使用到的所有的table and view ,只是不知道是否有这样的SQL语句 或是SQL2005接口!

    谢谢大家!
    从良流氓*十三
    2009年3月30日 7:19
  • 你的意图已经很明显了,据我所知,您需要“验证对象”的时候截获这个信息我想是不太可能。你自己可以想象一下这个是sql的内部工作机制,而且在服务器端执行。不太可能获取这个信息。

    相反,我倒是觉得正则表达式反而是最好的选择。至于您说道的 办法太笨(不知道笨在哪里?)或者使用别名或者零时表(别名总有原来的名字才能取别名,零时表也总有原来数据提取的表吧)有问题。这样很简单的办法就能获取所有表或者视图了。

    2009年3月30日 7:26
  • 你的SQL语句是用户输入的?即使实现了,也会有注入的问题。

    另外及时十分复杂的SQL语句也会有规律,从你的需求上来看其实分析一下SQL语句就可以了。如果我没记错,能否输入表名称的肯定是在from子句,你只需要能够分割出from子句就可以了。from子句后面能够连接的关键字是可以统计的,所以复杂的SQL也都是有这种规律
    2009年3月30日 10:00
  • 你可以使用QueryPlan分析
    set
     showplan_xml on
    
    go
    SELECT
         Categories.CategoryID, Products.ProductID, Products.ProductCode, Products.ProductName
    FROM
             Products INNER
     JOIN
    
                          Categories_Products ON
     Products.ProductID = Categories_Products.ProductID INNER
     JOIN
    
                          Categories ON
     Categories_Products.CategoryID = Categories.CategoryID
    go
    set
     showplan_xml off
    
    go
        
    
    然后分析返回的query plan中<object >节中的table就可以了

    我是抓了一个Trace看到的
    2009年3月30日 10:20
  • set
    showplan_xml on
     
    这个的确很酷

    但是我用系统表测试发现object内容和用用户表测试情况不一样:
    sql语句:

    set showplan_xml on
    
    go
    
    SELECT  c.name
    
    FROM         sysobjects o,syscolumns c 
    
    where c.id=o.id
    
    go
    
    set showplan_xml off
    
    go
    
    

    object :

    <Object Database="[mssqlsystemresource]" Schema="[sys]" Table="[syscolrdb]" Index="[ncl]" />
    
    
    
    
    
    

    非系统表测试的object:
    <Object Database="[db_test]" Schema="[dbo]" Table="[A1]" />

    测试sql:

    set showplan_xml on
    
    go
    
    SELECT A1.DataDay
    
    FROM A1,B1 
    
    where A1.DataDay=B1.DataDay
    
    go
    
    set showplan_xml off
    
    go
    
    

    仔细看后,发现这个和查询计划是和是否使用索引什么的有关系,也就是说object内显示的不是最终的表,可能是索引等其他信息,这个需要拿到这个节点后在做分析,同时对于系统表而返回的表名如:syscolrdb,syscolpars等在联机帮组内没有找到说明。

    2009年3月30日 11:08
  • SQL 2005以后的版本系统数据库与之前都不一样了,我们看到的master库都是mssqlsystemresource数据库,这个库文件可以在数据文件夹中看到,我们看到的sys表也都是视图,所以有点不一样。
    另外对于索引的那个问题,只要你去访问表无非就是几种方法,表扫描、索引等,不论这些都与这个表相关,所以可以找到需要的表
    2009年3月30日 11:39
  • 谢谢回复!
    先回复 stone z 的  之所以为“笨”,主要是我要考虑到所有的情况,正则表达式只会找到匹配的,找不到不匹配的,所以工作量太多了,不是针对,如果误会了,对不起啊

    SUN WEI 谢谢你。我又忘记说明一个问题了, 这个数据库是服务器的数据库,有并发的,如果你
          set showplan_xml on
    后 那么其他的用户都不能执行SQL语句。
       
       也就是SUN WEI所说的注入的问题,所以我才一直要弄到SQL2005的验证信息,这个也是正则表达式麻烦的地方,
    另外一个  SQL语句里的表 不一定都跟在FROM 后面  比如 update 语句  JOIN 语句 Insert 语句 create语句

    是否有高手能把这个问题反馈到SQL service开发组去~


    从良流氓*十三
    2009年3月31日 0:42
  • 1 我也是就问题论问题

    不怎么理解你说的“正则表达式只会找到匹配的,找不到不匹配的,所以工作量太多了”。

    对于sql server他自己在分析你的语句的时候也会有一个类似的工作机制,就是词法分析,来解析sql语句。使用正则表达式来读取sql语句中的表对象,的确要考虑的问题比较多。update,select,insert等等,但是这些都是有语法规则的,必须按照一定语法来书写,这个也就决定了你要么写一个和sql server本身类似的词法分析,要么就是按照这个语法写一个正则表达式。我想后者应该是不会太难。

    2 set showplan_xml on这个操作是只对当前用户有效的不影响其他连接用户。

    3 sql注入问题,如果是数据破坏,这个就不好控制了,本身你容许别人执行很多sql语句。如果是通过数据库做权限提升,这个如果本身数据库用户的权限控制好了,应该没有多少问题。

    2009年3月31日 6:51
  • 你的需求只是和表的架构有关系,可以使用一个空的数据库,这个数据库只有表的结构,没有数据,仅仅利用这个数据库获取你需要的表关联的信息,这样就不会影响其他的用户了,这个方法比较简单也比较安全。
    SQL中的Select,Update,Delete,Insert都有Query Plan
    2009年3月31日 9:40