我正在使用TSql110Parser在特定的T-SQL过程(以及最终的所有模块)中列出Identifier和QuotedIdentifier令牌。任务是汇编每个模块中使用的列及其表的列表,以便我们可以在脚本的基础上识别数据库中过时的列,表和模块。
我已经验证我的数据库中没有用户对象使用当前定义的T-SQL保留字作为对象名。
问题:有没有办法检测标识符何时成为T-SQL词典的一部分?也就是说,根据tree.ScriptTokenStream[idx]
中包含的信息,是否可以确定tree.ScriptTokenStream[idx].Text
是否是T-SQL词汇词? Reserved个词似乎都有一个`tree.ScriptTokenStream [idx] .TokenType'除了"标识符"之外的其他内容,因此他们已被排除在外。我要删除的单词是" NOCOUNT"," VARCHAR"," LTRIM"和" RTRIM",它们都有TokenType" Identifier"。
相关奖励问题:此列表当前输出到控制台。有关将令牌输出重新路由到SQL Server CLR中CRLF分隔文本的任何提示吗?
我是C#的新手,但是已经编写了很长时间,因此,从C#语法的角度来看,您提供的任何帮助都需要相当低级。
我的环境是VS10 / .NET 4.5.2中的SQL Server 2008R2 / C#。
感谢您的关注和帮助。
这是程序:
// Program.cs
// Cloned and kludged from Program.cs, found in the BasicUsage project, available from the Samples download link in
// http://blogs.msdn.com/b/arvindsh/archive/2013/11/06/slides-and-samples-for-my-sql-pass-scriptdom-talk.aspx
//
// See also: http://michaeljswart.com/2014/04/removing-comments-from-sql/
//
// The page that VS10 "Help" should reference instead of the useless one it does:
// https://msdn.microsoft.com/en-us/library/kx37x362(v=vs.100).aspx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.SqlServer.TransactSql.ScriptDom;
namespace BasicUsage
{
class Program
{
static void Main(string[] args)
{
// before proceeding, add a reference to the ScriptDom assembly
IList<ParseError> errors = null;
//TextReader rdr = new StreamReader(@"C:\ScriptDom\SampleProc.sql");
TextReader rdr = new StreamReader(@"C:\ScriptDom\pTestProc.sql");
// pass the reader to the scriptdom
TSql110Parser parser = new TSql110Parser(true);
TSqlFragment tree = parser.Parse(rdr, out errors);
// some placeholders to avoid typing!
foreach (ParseError err in errors)
{
Console.WriteLine(err.Message);
}
string strtokentype ;
string strtokentext ;
int strtokentextlen ;
int tokencount;
int identifiercount = 0;
tokencount = tree.ScriptTokenStream.Count; // 249
Console.WriteLine(tree.ScriptTokenStream.Count);
Console.WriteLine("====== Listing only Identifiers ======");
// walk through the tokens
int idx = 0;
for (idx=0; idx < tokencount; idx++ ) // remember: zero-based arrays here.
{
//if (String.Equals(tree.ScriptTokenStream[idx].TokenType, "QuotedIdentifier", StringComparison.OrdinalIgnoreCase) = true ||
// String.Equals(tree.ScriptTokenStream[idx].TokenType, "Identifier", StringComparison.OrdinalIgnoreCase) = true)
// Make string ops easier by doing the conversion only once, and operating on a string basis thereafter.
strtokentype = Convert.ToString(tree.ScriptTokenStream[idx].TokenType);
// if it's a quoted identifier, remove the first and last character, e.g. "[Rate]" becomes "Rate".
if (strtokentype == "QuotedIdentifier" ||
strtokentype == "Identifier"
)
{
identifiercount++;
// do the conversion first,
strtokentext = Convert.ToString(tree.ScriptTokenStream[idx].Text);
// then extract the meaningful part if needed.
if (strtokentype == "QuotedIdentifier")
{
strtokentextlen = strtokentext.Length - 2;
strtokentext = strtokentext.Substring(1, strtokentextlen);
}
else
{
strtokentype = " Identifier"; // Provide leading spaces to clean up the output text for a nicer presentation.
}
Console.Write("[" + idx + "] = " + strtokentype);
Console.WriteLine(" " + strtokentext);
Console.WriteLine();
}
};
Console.WriteLine();
Console.WriteLine(identifiercount + " Identifiers found.");
Console.WriteLine();
rdr.Dispose(); // Set breakpoint here so console remains visible during development
}
}
}
答案 0 :(得分:1)
事实证明,我所提出的MVP之间的共识是,确实没有完整的T-SQL关键词列表。
但是,安装SSMS时会创建包含许多关键字的XML文件。该文件位于您的计算机上C:\Program Files (x86)\Microsoft SQL Server\120\Tools\Binn\ManagementStudio\SqlToolsData\1033\SqlCommonObjects.xml
那些与保留字相结合(参见上面问题中的链接)组成了一个包含600多个不同单词的列表[包括ODBC和未来使用的单词],这些单词对T-SQL有“或特殊含义”。
顺便说一句:请注意,关键字与保留字不同,关键字可以合法地(如果不明智)用于创建有效的DDL,例如
CREATE TABLE varchar(varchar varchar NOT NULL)
完全有效,但在混淆中超过顶部。