SQL-File 技术用于 Transact-SQL






4.71/5 (5投票s)
静态参数化 SQL 语言简介
目录
- 引言(滚动到)
- 什么是 SQL-File 技术(大致解释)
- 简单的“Hello”脚本示例
- 使用 SQL-File 有什么好处?
- CMD 非常适合轻量级上层结构,具有用户命令和设置。
- 多平台设置代表了一种强大的编程方法,可用于两种或多种语言,如果您能够通过语言预处理器或源代码生成任务来访问配置值(设置)。
- SQL-File 技术与实验性 Web 应用程序
- 我的工作,通用构造函数,名为 SQL-File
- 正文结尾(滚动到许可)
引言
本文介绍了所谓的静态参数化 SQL 语言,提出使用增强的 SQL 代码,该代码驻留在专门组织的 SQL 文件项目中,这些文件位于相应的配置好的文件/子文件夹树中。关联的 SQL 文件(静态脚本)与名为 SQL-settings 的简单值定义文件一起存储,其中包含静态 SQL 的参数。(这是一个简短的表述。)
我实现的想法是选择一套工具作为替代 IDE,它能够处理文件中的参数化 SQL:带有文本编辑器的命令面板、文件树、命令等。同时,开发附加的构建实用程序,以便在一定程度上支持从数据库交互的角度来看的一种替代方法,用于构建和/或编程(从开发人员或管理员的机器,SQL Server 的客户端),这主要基于文件中的源文本编辑器(作为代码源的中心位置)。这种方法的一种方式是使用老式的传统文件管理器,它包含简单但通用的文本编辑器,并能够为需要复杂 SQL 处理的各种情况编写命令行脚本(不只是单一的 SQL)。此外,作为 SQL-File 创建的意图之一,编写了一些辅助 SQL 代码,一套有用的帮助程序,以库(客户端定义,加上服务器端的辅助例程)的形式。
我的小发明被称为 **SQL-File 技术(用于 MSSQL 和 T-SQL 语言)**。尽管 SQL-File 的实现很朴素,但我认为这个想法具有一定的价值和意义。
**I.** SQL-File 技术是什么(大致解释)
微软有一个官方实用程序 **SQLCMD**。乍一看,SQL-File 技术与之类似。事实上,它在很大程度上基于这个强大且有用的面向文件的实用程序。在 SQL-File 创建时(从其早期版本开始),组织一个完全独立、真正自主的客户端脚本处理器是不合理的,而与您的方法中的其他 MSSQL 功能进行良好集成和兼容性是可取的。SQLCMD
是一个基本的文件翻译器(SQL Server 的客户端实用程序),但它绝不是一个完整的程序环境,它不提供文件项目集成之类的东西。它确实支持环境变量(属性)作为文件脚本参数(SQLCMD
插入到 SQL 代码中,如 $(<VariableName>)
),但没有一种有效且统一的方法来配置复杂的属性集合,就像我们可以在“.props”文件(XML, MSBuild)中进行的那样。另一方面,SQL Server Management Studio(它是默认的 IDE)在处理文件方面也不是那么好。事实上,这个图形控制台并不真正(完全)处理文件,而是执行数据库中的 SQL 脚本更正(这是这个 dev.tool
的主要脚本位置)。因此,在这样的 GUI(数据库控制台)中,文件脚本的支持更像是幻觉,该工具没有高级的文件输入处理。在客户端工具方面,缺乏用于处理数据库(作为 SQL 脚本的主要存储)的特殊工具。SQL-File 技术是创建一个(组织)相应客户端组件(工具/实用程序)的一个朴素尝试,作为 DBMS 的附加(至少是实验性的)套件,面向管理员和/或开发人员,它专门用于处理文件中的 SQL 源代码(作为 SQL 脚本的主要位置)。
本文包含了大量的技术细节:文件名、变量名、配置的微片段等。这并不意味着所有这些东西读者都能立即理解。细节相对容易理解,它们的目的是让您了解应用技术的精神并部分介绍一些方法。为了正常了解,文章中放置了指向相应图像的本地链接,名为屏幕截图。(文章的感知取决于这些应用的图像。)
SQL 文件被应用(翻译)到数据库,可以说是从源文件项目(在分组文件夹中)的位置:(**1**)在编辑器中;(**2**)通过激活 UI(文件管理器或另一个面板)中的列表(文件项)中的单个文件;(**3**)从专门组织的命令行脚本(例如,多步的复杂翻译)。文件组可以一步(作为单个操作)进行处理(翻译到数据库):(**1**)选择一个 SQL 文件(加上一些附加的特殊文件);(**2**)简单的脚本组,如“*.sql”或“<asterisk_pattern.sql>”(可以指定“$sql_order.list”中的某些项目名称,以纠正处理的文件顺序);(**3**)按名称模式的子目录(全部一次),加上本地 SQL 文件(如“*.sql”),这是一个大组(用于单个翻译,一次连接执行)。SQL 文件项目中的每个脚本都位于树中的正确位置,源文件的正确位置在这里很重要。请参阅图片($SQLTRANS
示例):表结构创建($SqlTrans, SQLCMD),数据填充($SqlTrans, SQLCMD),SQLAUX 函数一次性完成,应用过程翻译($SqlTrans, SQLCMD),行中的语法错误。(最后两张图片中的一些西里尔字母是由于作者机器的本地化,这些消息中没有重要的东西,它们只是 SQL 翻译命令的确认和结束暂停。)
SQL-File 程序环境中的主要用户交互工具是 Far Manager 3(广泛为人知且强大的文件管理器),它是一个丰富的控制台模式应用程序,这是主要 IDE(提示编辑器和命令控制台)。还可以使用其他一些工具与 SQL-File 一起使用:(**1**)Windows 资源管理器(作为稀疏的命令面板);(**2**)SSMS,官方 IDE(但有一些限制);(**3**)独立的外部源文本编辑器(GUI)。
如果应用程序代码的一部分在数据库中:SP、函数、视图等,将这些“程序”(具有 SQL 代码的活动 DB 对象)的源存储在相应的 SQL 文件项目中是合理的。存储过程和函数应具有适当的名称前缀,以便能够有效地销毁应用程序的整个 DB 组件(其相应的 DB 子系统)。通过配置脚本的文件树,仔细考虑程序依赖关系,确定它们的翻译顺序,我们就为在 DB 中重新创建应用程序组件(全部、部分或单个对象)做好准备,使其成为一项轻松的任务。通常,目标程序代码(服务器端)正确的程序(文件)可以在 SQL DB 中快速生成(一次、两次、三次、四次、五次……不太长),这种翻译通常在开发过程中进行。通过(文件编辑+翻译)在工作应用程序或服务上纠正某些对象(在某个暂停间隔内)也是正常的,即使不中断其与 SQL 的连接。(例如,SQLAUX 脚本库的复杂翻译,包括在 DB 中翻译 **173** 个对象,以及它们的首次销毁,对于本地数据库通常只需不到 10 秒,由同一台机器上安装的 SQL Server 处理。)
SQL-FILE 技术与 HANDICRAFT-SDK
SQL-File 技术是一个通用概念。抽象地说,它可以被视为一种在文件中支持增强 T-SQL 语言的方法,甚至可以是文件中另一种 SQL 方言(对应于相应的 DBMS)。(在文章的最后一部分,提到了修改后的方法,SQL-File App.,这是一个完整的抽象。)然而,在本文中,我主要讨论我在 MSSQL 上的具体实现,以 Far Manager 作为主要 IDE(FAR 和 SSMS),并使用一个相关的特殊名称:**Handicraft-SDK**。这个小型 SDK 由本文作者提供。对于 SQL-File,它代表了一组命令行实用程序(在“CMD-utilities”文件夹中),SQLAUX 脚本库(在“SQL\SQLAUX”子文件夹中)以及其他一些有趣的东西(不仅支持 SQL-File)。因此,用于 Transact-SQL 的 SQL-File 技术基于 Handicraft-SDK
,这个关键依赖项使得文件中的增强 T-SQL 可运行。与 Handicraft-SDK
相关的其他名称,在本文中使用的是:“**Handicraft Toolkit**”(完整的代码包)和“**Handicraft-CODE**”,它们指的是与 SDK 相似的东西,但意味着一些附加项(如 SDK + 高级示例等)。
SQL-File 技术、$SQLTRANS-utility、SQLAUX 脚本库
SQL-File 技术提供了一些组件,用于在 MSSQL 数据库中进行高级编程(基于文件源代码)
- $**SQLTRANS** 实用程序(参见 $SQLTRANS 语法打印),它是 SQL-File 不可或缺的一部分,它基于 SQLCMD(官方命令行实用程序,配备了 MS 的预处理器),以及 SqlCatPP.exe(这个子程序,作为主要功能,用于连接源 SQL 文件以进行翻译;它还具有一些简单的预处理器功能);
$SqlTrans
命令实现在 $sqltrans.cmd 实用程序脚本中(Handicraft-SDK 的“CMD-utilities”文件夹); - **SQLAUX** 库设置用于预处理器(用于所谓的增强 T-SQL 的有用关键字和常量),可以通过
$(<VariableName>_AUX)
访问,即宏助手,参见:#SQL_extensions.AUX.sql,#Constants.AUX.sql,#Data_types.AUX.sql(SQLAUX API – 头文件,代码视图); - SQLAUX 库对象在 DB 中(
[AUX:<ObjectName>]
,[AUX::<ObjectName>]
,数据库助手),参见:存储过程,标量函数,表函数和辅助表(列表); - 模板和示例集合(SQL、CMD、TXT、$sql_order.list),这对于创建新的 SQL 文件项目(配置的文件夹和关联的文件)是必需的。
警告!
SQL-File 已在以下系统区域设置(单字节应用程序的默认代码页)下进行了测试
- **1.** 英语(美国),即 CP-1252(拉丁字母)/ OEM:CP437;
- **2.** 俄语(俄罗斯),即 CP-1251(西里尔字母)/ OEM:CP866。
对于其他系统语言(默认区域设置),SQL 翻译日期时间戳可能会出现一些错误,可能在其日期部分。抱歉!(有时可能不重要,因为一天中的时间顺序将保持不变。)对于与上述两种不同的区域设置,以下环境变量可能很有用:YYYY_START_IN_DATE
(可选),MM_START_IN_DATE
,DD_START_IN_DATE
。零基位置必须通过变量指定,根据相应的用户区域设置,相对于 DATE
环境变量(CMD)。**此外,它们还需要考虑您的系统中日期时间格式的任何非标准设置,相对于 DATE 变量。**(这个问题与用于实现 $SQLTRANS
命令的遗留 CMD 处理器的限制有关。)
我所有的实用程序(EXE)都由相应的源代码支持,以便(作为 SQL-File 的用户)能够重新构建它们。小型项目(C#、C++)位于 SDK 的“HandicraftSDK\Auxiliary programs (sources)”文件夹下。源代码附带多个构建命令(作为项目根目录中的 CMD 文件),并带有相应的操作名称。因此,如果需要进行一些更正,调整此类编译并不难。(此外,还需要官方的构建工具。)
Handicraft-SDK 中对 SQL-File 技术至关重要的文件夹
“HandicraftSDK” — 根文件夹
根目录下的主要文件夹(SQL-File 基础详细信息)
“**Auxiliary programs (sources)**” — 小型实用程序项目(C#、C++)
- “**Command line**” — C# 项目,用于“CMD-utilities”文件夹中的命令行实用程序;
- “**Far plugins**” — CmdCpAuto.dll 的微型 CPP 项目(“Utilities”文件夹中的 Far Manager 插件)。
“**CMD-utilities**” — $-命令(命令行):$sqltrans.cmd、$sqlupload.cmd、$sqltocsvexp.cmd、……
- “**Assemblies**” — $-命令的二进制子程序:SqlCatPP.exe、SqlToCsvExport.exe、ConfirmationPause.exe、TypeInColor.exe、……;
- “**Shell**” — 辅助 CMD(+说明),用于与 Far Manager 等集成。
“**SQL**” — SQLAUX 库 + 示例(SQL-File)
- “**Programming samples (SQL-file)**” — 增强 T-SQL 中的六个简单示例(SQL 项目 - 演示),附有相应的“!ReadMe.txt”;
- “**SQLAUX**” — 脚本库(SQL、CMD),通常被典型的 SQL 文件项目导入和使用;
- “Extralight-ORM test legacy sample (En+Ru)\**MyFlat app. (MVC_Razor+TS+ADO+TSQL)**” — 高级双语示例(EN/RU),使用 SQL-File:ASP 查询为英文(C#),SQL 文件为俄文(SP,使用增强 T-SQL,带西里尔字母,包含英文注释);(SQL 项目位于“SQL (DB-modelling)”子文件夹中);这是一个附加的、高级的示例。
“**Utilities**” — 关键实用程序和杂项辅助程序
- “Far plugins\**CmdCpAuto plugin, build 100 (Far v3)**” —
CmdCpAuto
,Far Manager 插件,用于在嵌入式 Far 编辑器中自动选择代码页,当编辑 CMD/BAT 文件时(通常通过 **F4** 键)。
(为了更深入地了解 SDK,请探索“HandicraftSDK\**\*”文件/文件夹树。)
SQL-翻译($SQLTRANS-命令组织)
SQL 翻译($SQLTRANS
命令)是一个复合操作。其主要阶段(内部步骤)列于下,但这是一个简要解释。为了更深入地理解细节,建议查看该实用程序的 CMD 脚本代码(“HandicraftSDK\CMD-utilities\$sqltrans.cmd”)。
SQL 翻译阶段(内部步骤)
- $sqltrans.cmd 接收 SQL 文件名(或模式)作为参数
- 如果存在,则从当前翻译文件夹调用 $sql_settings.cmd,以进行环境准备
- 调用 SqlCatPP.exe 以形成连接的、轻微预处理过的 SQL 源。结果 SQL 源放置在用户配置文件临时文件存储中的“%TEMP%\$SQLTRANS\<datetime-stamp>.sql”
- SQLCMD.EXE(SQL Server 命令行实用程序)由 $sqltrans.cmd 调用,以执行先前准备好的来自 %TEMP% 文件夹的 SQL 源。SQL 输出 TXT 文件与临时 SQL 脚本在同一文件夹中,具有相同的基名(或者,如果为“$sqltrans.cmd”调用指定了输出报告文件名,则输出到当前文件夹)。
另外,当调用方式为
call $SQLTRANS "(SettingsOnly)"
(在用户定义的复杂 SQL 翻译命令中)call $SQLTRANS "[SettingsOnly]"
(从“SSMS.cmd”调用,IDE 启动器)
除了用户定义的命令外,在仅设置模式下,它在 SSMS.cmd 中使用,这是一个官方 IDE SQL Server Management Studio 的高级启动器,因此它会以一组准备好的环境变量从 SQL 项目(用于参数化 SQL)启动。环境准备由 $sql_settings.cmd 启动(与 SSMS.cmd 在同一文件夹中),它通常会调用 @<project_name>.cmd(SQL 项目设置,UTF-8 编码,无 BOM)。
CMD 处理器的作用
CMD 处理器(命令提示符,MS Windows 中遗留的命令行解释器,与 Windows 控制台集成)在此 SQL-File 的“手工”实现中起着重要作用。批处理非常适合 SQL-File(它们配备了丰富的辅助子例程)。这个手工 IDE 在 CMD 和文本控制台中是本地的。特别应用的命令行格式充当 SQL 设置(环境变量)、SQL 脚本和命令脚本(SQL 翻译场景)之间的粘合剂。这不是一种现代方式,但它工作稳定。其他已知的命令行处理器可能在此任务中不那么成功。命令行脚本中的简单操作必须看起来简洁明了,并且不能显得臃肿和复杂;这是严格要求的,因为需要大量的用户定义命令,来管理短而中等大小的普通文件。(为了使用户体验更具吸引力,有必要发明一种特殊的脚本/配置格式,用于 SQL 项目和 SQL 命令的构建,并期望支持通用脚本功能,如浏览器外的 JS 引擎,以命令式风格处理命令指令。)
总结以上内容,SQL-File 技术是一种组织 SQL 文件项目的方法,以便在所谓的 **增强 T-SQL** 中编码数据库,使用不同级别的 SQL 设置(SQLAUX
宏关键字;SQL 项目中心设置;文件子树的修改后的 SQL 设置),并能够调用一些通用字符的附加函数和过程(数据库中的通用助手)。此技术实现(用于 MSSQL)针对开发和/或管理时间。这意味着您的项目环境不直接面向用户应用程序。当然,应用程序可以访问 SQL-File 创建的所有数据库对象(SP、函数、视图、表、触发器)。但是,应用程序查询(通过 SQL 预处理器在增强 T-SQL 中嵌入 SQL 设置)在此实现中是不可能的(我的 Handicraft-CODE 中未实现此可能性)。
$SQLTRANS
实用程序是 SQL-File 的关键子程序。它用 CMD 编写,充当 SqlCatPP.exe(具有 SQL 脚本连接器和附加预处理器功能的内部子程序)和 SQLCMD.EXE(来自 MS 的强大命令行实用程序)之间的中介,后者与 SQL Server 交互。翻译 SQL-File(在其 SQL Server 上执行其内容)的最简单方法是以下命令:$sqltrans "<Base name>.sql"
,或 $sqltrans "<Base name>.sql" "<Base name>.txt"
(将 SQL 执行报告保存到相应的 TXT 文件)。有许多调用方式。($sqltrans
命令在没有参数的情况下会打印其语法,并显示一些关于如何使用文件调用的提示。)
SqlCatPP 中的预处理器功能
除了 SQLCMD(来自 MS 的官方 PP)的功能外,SqlCatPP
子程序还有一个自己的简单预处理器(有两种不同的模式)。所谓的强预处理模式在 SQL-File 中可用,由 SqlCatPP.exe 支持(除了所谓的弱预处理模式,后者用于消除与 SQLCMD
智能删除原始源行中的 :SetVar
指令相关的错误诊断)。强预处理模式旨在能够重建预处理结果(预处理和连接的脚本),以便将此目标脚本传输(例如,通过电子邮件发送)给所谓的数据库经销商。数据库经销商(在数据库中操作的人)应用开发人员收到的 SQL 脚本,并在目标数据库上执行它们。他们无法准备开发者的环境(如 SQL 项目在开发者机器上)。他们所需要的是一个已准备好的目标 SQL 脚本(在开发者的计算机上,在 SQL 项目环境的影响下进行强预处理的结果)。例如,SQLAUX
库本身通过“sqlaux_library.sql”文件导出到外部,该文件是“HandicraftSDK\SQL\SQLAUX\Source\$OUTPUT”文件夹中的复合脚本,其中销毁-创建了 **173** 个 DB 对象(可以从 SSMS 执行,默认设置)。但是,强预处理模式应谨慎使用(仅在必要时)。它尚未充分测试,并可能存在风险。(事实上,在解释注释、文字、PP 指令等方面,SqlCatPP
很难实现与 SQLCMD
中的 MS 预处理器完全相同的行为。)
SQL 命令的 CMD 批处理组织的双重特性
大多数 SQL 命令(CMD 脚本)支持所谓的双重调用。在正常调用时,控制台通常不会在结束时关闭,直到您按下相应的键。在开始时,也可能会出现继续命令的确认请求。如果命令失败(遇到错误),它通常会打印错误消息(对于 SQL 翻译失败,它会显示为红色)并发出蜂鸣声。这是错误的正常行为。在所谓的嵌套调用时(用于调用如下的复杂批处理:call $SQLTRANS.cmd …
或其他一些股票或用户定义的命令),在这种调用中,上述措施被避免:没有确认,没有完成暂停,在出错时也没有蜂鸣声。如果您在 Windows 资源管理器中单击一个命令(正确命名的命令文件),则会出现一个独立的控制台,您可以在命令成功或失败时阅读输出(打印到控制台的文本和消息)。这是由于正常调用固有的特殊措施。在嵌套调用的情况下,根命令可能是正常调用的(所以关于确认、暂停、消息等都没有问题)。因此,调用双重性是有帮助的。不仅 SQL 命令,C# 项目构建命令(包含 MSBUILD / dotnet build 等)以及其他许多 CMD 批处理都以双重调用方式组织。
以上是我围绕 SQL Server 的生产的大致草图。其基本组成部分是在客户端的原始程序环境,尽管它更多的是与关键组件(官方实用程序:SQLCMD
、BCP(MSSQL 命令行实用程序的核心程序))的集成。另一部分是名为 SQLAUX
的 T-SQL 脚本库,这是一个面向服务器端的组件。
控制台自然环境(即伪图形指挥官)和一些 GUI
SQL-File 的主要 IDE 非常朴素。Far Manager 中的文本编辑器不提供代码自动完成功能。尽管 Intellisence for SQL 在 SSMS 中可用,如果您通过 SSMS.cmd 启动器运行 IDE 进程(SQL 项目根目录(文件夹)中的命令文件)。但是,SSMS+Environment 存在限制。来自 SQL 设置 CMD 的变量在 IDE(Ssms.exe,OS 进程)的整个会话中是冻结的。**来自 SQL 设置 CMD 的变量在 IDE(Ssms.exe,OS 进程)的整个会话中都是冻结的。**
相反,Far 编辑器对于 SQL-File 中的编程来说是快速且本地化的。它适用于创建/编辑 SQL 脚本以及编辑 CMD 和许多其他文件类型。代码着色很好(VS Code 中的深色主题看起来很相似)。编辑器中存在垂直块选择,OEM 代码页的字符显示正常,包括伪图形,Unicode 编码系列支持良好等。Far Manager 很有价值,因为它足够通用。
无论如何,SQL 命令(项目 CMD)是独立的,这样的 CMD 可以在单独的控制台窗口中启动(在 Far Manager 中通过 **<Shift+Enter>** 或从 Windows 资源管理器文件夹)。
**II.** 简单脚本(Hello)示例
简单脚本(Hello
)示例是 SQL-File 技术附带的另外六个普通示例之一。它们都收集在所谓的普通示例的 **Simple script (Hello)** 文件夹中。(其他可用的 SQL 项目,包括 SQLAUX
脚本库,被认为是高级的。)
**Simple script (Hello)** 示例由 13 个文件组成,类型(扩展名)如下:SQL、CMD、TXT,其中一个文件没有扩展名:%simple_script%;这是所谓的 SQL 微脚本,通过“**:r**
”指令包含在“simple_script.sql”中,这是主要的 SQL 脚本。这些文件相互依赖。所以实际上这个简单的脚本并不平凡,它包含了几个特性。前三个 T-SQL 批处理,指令部分持续到 GO
分隔符(但不包括它),执行以下操作:
第一个批处理在 %simple_script% 文件中,它将报告头打印为文本消息:**\*\*\* SIMPLE SCRIPT (<date and time>): \*\*\***。另外两个批处理在 simple_script.sql 中。
第二个批处理产生五个原始结果集,它们是:
- 通用问候(消息)
- 扩展(附加)问候,俄语
$(str_UnicodeString)
属性值(来自 SQL 项目设置),这是现代希腊字母(24 个大写字母)的字母SQLAUX
系统变量(执行三个名称-值的输出):is_sqlaux_imported
、sql_translation_timestamp_aux
、sql_settings_script_aux
sql_translation_dir_aux
变量视图(文件翻译文件夹路径,以反斜杠结尾)
第三个批处理打印输出终止装饰符:**— — —**(三个破折号中间夹一个空格字符)。就这些(这是一个简单的脚本)。
结果保存在“simple_script.txt”中,或者可以在控制台窗口或 SSMS 中看到翻译输出(这取决于如何调用脚本)。此 SQL 项目中没有子目录。
SQL-FILE 屏幕截图(“Hello”示例的图片)
简单脚本(Hello)/ 文件中的 T-SQL(SQL 项目目录中的 simple_script.sql 和 %simple_script%)
>> simple_script.sql | %simple_script%
简单脚本设置(SQL-File 项目定义:$sql_settings.cmd,@simple_script.cmd)
>> $sql_settings.cmd | @simple_script.cmd
简单脚本输出(simple_script.txt 中的 TXT 报告,控制台,SSMS)
>> simple_script.txt | 控制台输出 | SSMS 输出(表格视图) | SSMS 输出(纯文本)
简单脚本运行(elementary simple_script.cmd 和 complex run_simple_script.cmd)
>> simple_script.cmd | run_simple_script.cmd
(SQL 输出中的装饰标题中的日期,该输出在第 1 个批处理中生成,包含西里尔月份名称,因为连接的用户默认语言是俄语,用于 SQL Server 作者的登录名。)
简单脚本(Hello)示例的主要代码片段
简单脚本(Hello)示例的 main code snippet,simple_script.sql,放在这里
:r "%simple_script%"
/*======================================================================================
#
# SIMPLE SCRIPT (HELLO):
#
=======================================================================================*/
$(BEGIN_AUX)
-----------------------------------------------------------------------------------------
--set NOCOUNT off
select N'Hello from simple SQL-script!' as 'GREETING:'
union select '' -- empty row (for text separation)
select $(msg_Greeting_X) as $(str_GreetingCaption_X)
union select '' -- empty row (for text separation)
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - -
--raiserror ('Intentional exception (error test).',11,1)
select $(str_UnicodeString) _
as N'$(_DOLLAR_AUX)(str_UnicodeString)-property value (from SQL-project settings):'
union select '' -- empty row (for text separation)
-----------------------------------------------------------------------------------------
-- SQLAUX-LIBRARY SYSTEM PROPERTIES (LISTING):
-- Temporary table deletion attempt (to run the script repeatedly in SSMS):
begin try drop table #Properties end try begin catch end catch
create table #Properties
(
[Name] $(dt_Name_AUX) not null,-- nvarchar(100)
[Value] $(dt_String_AUX) not null -- nvarchar(max)
)
insert #Properties values
( 'is_sqlaux_imported' , '$(is_sqlaux_imported)' ),
( 'sql_translation_timestamp_aux', '$(sql_translation_timestamp_aux)' ),
( 'sql_settings_script_aux' , '$(sql_settings_script_aux)' ),
( '', '' ) -- empty row (for text separation)
declare @NameCapacity int, @ValueCapacity int
select @NameCapacity=MAX(LEN([Name])), @ValueCapacity=MAX(LEN([Value])) from #Properties
:SetVar AlterColumn "alter table #Properties alter column"
EXEC('
$(AlterColumn) [Name] nvarchar('+@NameCapacity+')
$(AlterColumn) [Value] nvarchar('+@ValueCapacity+')
')
select [Name] 'SQLAUX system variable', [Value] 'Value' from #Properties
select '$(sql_translation_dir_aux)' _
as 'sql_translation_dir_aux (folder path ended with backslash):'
/*
# Uncomment the line below ("qwertyuiop") and run the query,
# then check line number of SQL-error (from the server).
# It has to be equal to the real value if you are using $SQLTRANS+SqlCatPP+SQLCMD,
# but it is not correct in case of SSMS in SQLCMD-mode
# (because it excludes source lines with :SetVar-directive).
*/
--qwertyuiop -- Incorrect syntax near 'qwertyuiop'.
---------------------------------------------------------------------------------------
$(END_AUX)
/*=====================================================================================*/
GO
print ''
print '— — —'
GO
关联示例文件(SQL 项目)的目的
- !ReadMe.txt — 示例程序意图的简单说明
- $ide_root.sql — 供 SSMS.cmd 指定 IDE 的项目根文件夹
- $sql_settings.cmd — 预定义的设置批处理名称,由
$SQLTRANS
激活,它附加SQLAUX import
定义和来自 @simple_script.cmd 的项目定义(约定名称) - $sql_settings.sql.bak — 指定 SQL 设置的替代方法(不兼容 SSMS,因此不推荐),$sql_settings.sql 在任何 SQL 翻译的开头插入(由
$SQLTRANS
自动完成),除非被$sql_settings_script
变量(SQLAUX
中的连字符值“-
”)阻止,或者在 $sql_settings.cmd 中(通过$sql_settings_script
变量)引用。 - %simple_script% — 此微脚本包含在 simple_script.sql 的第一行(
:r "%simple_script%"
)中,其目的是打印报告的标题 - @simple_script.cmd — 项目定义,SQL 设置在项目根目录下,由 $sql_settings.cmd 导入(其中一些可能会在子文件夹中被覆盖,如果它们存在的话),这是 SQL 设置非平凡配置的约定名称,使用 UTF-8(文本内容存储无签名,即无 BOM 前缀,但 Far Manager 的
CmdCpAuto
插件“理解”特殊文件名) - exec_no_confirm.cmd — 与 simple_script.cmd(正常模式)相反,此命令(批处理文件)避免用户确认步骤(simple_script.sql 中没有不安全的内容),SQL 输出到控制台
- exec_simple_script.cmd — 正常执行,SQL 输出(结果打印)到控制台
- run_simple_script.cmd — 所谓的复杂命令的最小示例(SQL 输出到控制台)
- simple_script.cmd — 保存 SQL 输出到相应 TXT 报告的最自然命令形式,带有强制用户确认(通常 SQL 脚本可能对数据库来说是危险的)
- simple_script.sql — 生成复合报告的主要 SQL 脚本
- simple_script.txt — TXT 报告(simple_script.sql 执行的结果)
- SSMS.cmd — 所谓的 IDE 启动器,它准备 SQL 项目环境(SQL 设置作为环境变量),并启动 IDE 进程(Ssms.exe),然后 $ide_root.sql 在 SQL Server Management Studio 中打开(此时作为单个 SQL 文件选项卡)
Transact-SQL 语言中奇怪的控制流(错误检查的默认模式)
在 T-SQL 语言中,默认情况下存在一些奇怪的控制流(此处,我指的是没有异常捕获/保护的代码),它强制我们在每个指令后几乎检查 @@ERROR
变量,否则无法保证执行被正确中断(转到恐慌分支或终止),如果 SQL 指令失败。这是遗留行为(它是 T-SQL 中的默认控制流模式),继承自早期版本(当时还没有异常处理支持)。这个事实(T-SQL 默认模式下不可靠或不方便的控制流)是 SQL-File 方法被发明的主要原因之一(在其他严重情况中),然后它允许(作者)使用带有特殊宏关键字(用于重复使用的折叠指令序列)的参数化 SQL 文件。
我们在 T-SQL 中默认拥有的这种控制流(每个潜在危险指令后都检查 @@ERROR
变量)适用于,例如,打算在操作系统内核模式下执行的代码(例如,纯 C 语言的函数驱动程序)。但将此模式作为默认设置(即,与没有专门组织的异常捕获的代码相关联)对于具有事务的高级语言来说不是一个好主意。也许,对于 CMD
脚本来说,它仍然看起来正常(到处检查 errorlevel
变量),但可以肯定的是,这种默认模式对于 SQL 来说是不理想的。
用于异常捕获的主块,脚本包含宏:$(BEGIN_AUX)、$(END_AUX)
SQL-File 中的批处理内容通常包装在 $(BEGIN_AUX)
和 $(END_AUX)
宏(SQLAUX
库关键字)之间。每个 T-SQL 批处理只允许一个这样的保护代码块。下面,您可以看到主错误保护是如何展开的。如果在块内发生错误,它将被捕获为异常,在 catch
部分结束时抛出,在可能的已打开事务回滚之后(如果存在),该事务已由块中的 $(BEGIN_TRANSACTION_AUX)
宏特别启动(如果存在)。
SQL-File 中的源脚本
$(BEGIN_AUX)
-- QUERY BODY:
: : : : :
$(END_AUX)
GO
在 SQL Server 上执行的脚本
begin begin try set xact_abort off;
set ansi_nulls,ansi_null_dflt_on, quoted_identifier,arithabort,nocount on;
set implicit_transactions off;
declare @initial_tran_count_aux int, @is_local_tran_open_aux bit;
select @initial_tran_count_aux=@@trancount, @is_local_tran_open_aux=0;
end try begin catch throw; end catch; begin try
-- QUERY BODY:
: : : : :
if @is_local_tran_open_aux=1 raiserror ('Not closed local transaction was detected,
previously opened by BEGIN_TRANSACTION_AUX macro.',11,1);
end try begin catch if @is_local_tran_open_aux=1 and _
(@@trancount>@initial_tran_count_aux or xact_state()=-1) rollback transaction;
set @is_local_tran_open_aux=0; throw; end catch; end
GO
分隔符被 SQLCMD
排除。$(BEGIN_AUX)
和 $(END_AUX)
插入被 SQLCMD
展开为上述指令序列,或者如果启用了强预处理模式(在 $sql_settings.cmd 中设置为 set SqlCatPP.ProcessDirectives=1
),则可以由 SqlCatPP
处理(但应谨慎使用此可能性)。
还可以查看此 SQL 代码作为 SP 的一部分(在 SSMS 中显示):$(BEGIN_AUX) 宏在 DB 中(预处理结果)。
其他示例(普通和高级)
**Simple script (Hello)** 示例是 SQL-File(所谓的普通示例)附带的六个基本示例之一。
以下是“HandicraftSDK\SQL\Programming samples (SQL-file)”文件夹中的基本示例列表:
- “**GUID-list generation**” – 生成一个包含 50 个 GUID 的列表到“guid_list.txt”纯文本文件中
- “**Lists downloading (sys-info)**” – 演示如何使用
$SqlToCsvExp
命令 - “**Nested transaction test**” – 有趣的嵌套事务示例(SP 在文件中)
- “**Simple script (Hello)**” – 配置好的关联 SQL 文件项目(无子文件夹)
- “**Trigger test**” – 触发器的简单实验(在文件中),针对奇数表
- “**Uploading to DB (used buildings)**” –
$SqlUpload
命令的示例用法
每个基本示例(其文件夹)都附带“!ReadMe.txt”中的相应最小说明。所有示例项目(上面提到的以及其他)都列在 Handicraft Toolkit 的根文件夹中的“SQL-projects-sum.txt”中。至于 Simple script (Hello
),这个 SQL 项目没有子文件夹。对于大多数其他示例,它们有。子文件夹中的 SQL 设置由专门组织的“$sql_settings.cmd”从上一级继承(它通常附加来自上层目录的设置)。可以添加一些新变量,一些现有值可以被更正。即使在命名的用户命令(批处理)中,我们也可以指定一些特殊的内容(与实用程序相关)。通常,实用程序的行为在“$sql_settings.cmd”中配置,通过特殊的变量,如 $sqltrans.*
、SqlToCsvExport.*
(基础设置名称隐含在星号处)。例如,在 exec_simple_script.cmd 中:rem set $sqltrans.ContinueOnBatchError=1
。(如果您取消注释此行,即使可能出现批处理错误,Simple Script Hello 中的所有三个 GO
批处理也可能正常工作。)
SQL-File 中的另外两个示例(高级)
- “HandicraftSDK\SQL\Extralight-ORM test legacy sample (En+Ru)\MyFlat app. (MVC_Razor+TS+ADO+TSQL)\SQL (DB-modelling)” —
数据库中的应用程序组成部分(MyFlat 应用 API 在 SP 中 + 一个基础 SP),俄语(带有一些英文注释); - “BookRegistry\SQL (DB-modelling)”、“BookRegistry\SHARED\$ClientServer\!DB-queries (application SP)” —
两个关联的 SQL 项目,用于 **BookRegistry Sample App.**(表结构、数据填充、SP、C#/SQL 并排);这是一个额外的示例。
**III.** 使用 SQL-File 的好处是什么?
SQL-File 技术可以最大限度地应用于您的脚本,或者在很小的程度上应用。您可能只使用文件翻译或其他实用程序(如 $SqlUpload
或 $SqlToCsvExp
命令)。例如,有人可能决定依赖 SQLAUX
库中的有用宏(其可展开的关键字),但这并不意味着您需要使用其数据库助手对象(即 SQLAUX SP
、DB 函数等)。如果您有一个 SQL 文件文件夹,只需在其下放置 $sql_settings.cmd 文件,即可通过 $SQLTRANS
将其翻译,一次翻译一个或全部(然而,部分文件组的处理仅通过相应的子文件夹可用)。您甚至可能无需简单的 $sql_settings.cmd 即可翻译文件,如果您定义了一些系统或用户变量:$sql_server
、$sql_database
(或者,如果需要,$sql_user
、$sql_password_var
和相应命名的变量作为 SQL 密码容器)。临时变量可以在 Far Manager 中,在其命令提示符下或通过用户菜单为指挥官的 OS 进程指定。因此,用户 CMD 批处理在 SQL-File 中并非严格必需。
无论如何(如上所述等),建议使用 $sql_settings.cmd。另一个强烈推荐的事情是不要避免 SQLAUX
库导入,它在 $sql_settings.cmd 中执行(该文件还导入 @<project_name>.cmd,UTF-8 中的 SQL 设置)。(这类似于 C 语言或 RC 文件中的一些重要 include 文件,并非为了函数头,而是主要为了获得所需的预处理器级别 def。)
Far Manager 键盘快捷键等
下面列出了 Far Manager 的键盘快捷键,用于翻译单个扩展名为“.sql”的文件。
从 Far Manager 面板进行 SQL 翻译的键盘快捷键(在主菜单 :: 命令 :: 文件关联 :: 文件掩码或多个文件掩码:*.sql 中设置)
- **<Enter>** — 在指挥官窗口中启动 SQL 翻译(即输出到父控制台),并进行安全确认;
- **<Ctrl+PageDown>** — 在独立窗口(最大化控制台)中启动 SQL 翻译,无需安全确认。
- 在 Far Manager 嵌入式编辑器中进行 SQL 翻译的键盘快捷键(通过 LUA 宏 Editor_CtrlEnter.lua 和 Editor_CtrlF12.lua 激活)
- **<Ctrl+Enter>** — 保存 SQL 文件,在指挥官窗口中启动 SQL 翻译(即输出到父控制台),并进行安全确认;
- **<Ctrl+F12>** — 保存 SQL 文件,在独立窗口(最大化控制台)中启动 SQL 翻译,无需安全确认。
用于启动 SQL 命令的 Far Manager 键盘快捷键,用于执行“**<Command name>.cmd**”
- **<Enter>** 或 **<MouseLeft**::**DoubleClick>** — 在指挥官的父控制台窗口中执行 CMD;
- **<Shift+Enter>** 或 **<Shift + MouseLeft**::**DoubleClick>** — 在独立控制台窗口中执行 CMD。
可以通过 **<Shift+Enter>** 或 **<Shift + MouseLeft**::**DoubleClick>** 在 Far Manager 中打开 Windows Explorer 文件夹,在“**..**”符号(上层目录)上。
此外,Editor_CtrlR.lua 宏用于在嵌入式编辑器中快速注释命令行,前缀为“rem
”(不带引号)。
编辑器的一些有用参数(FAR MANAGER “CONFMN”/F9 :: 选项 :: 编辑器设置)
- **Expand tabs**: **Expand all tabs to spaces**;
- **3** – **Tab size**(这是 Handicraft-CODE 推荐的最佳制表符大小);
- **x** – **Show scrollbar**(FAR 嵌入式编辑器中的垂直滚动)。
SQL-File 使用的两个主要方向
- 用于数据库管理的实用应用程序
- 开发人员用于在数据库中创建应用程序(服务)部分:SP、标量和表函数、视图、触发器等;
这些对象在 SQL-File 术语中被称为程序(即,具有某种活动的对象,甚至视图)
**IV.** CMD 非常适合轻量级上层结构,具有用户命令和设置。
听起来很奇怪,但尽管 CMD 处理器很老旧,在某些情况下却不容易被替代。对于 SQL-File 的意图来说,CMD 自然会做的就是这些:装饰输出、调用其他批处理、令人满意的错误检查(甚至有蜂鸣信号)、简单的参数支持、子程序组织等。(在 SQL-File 中,Cmd.exe 及其相关命令的缺失基本功能已由相应的微型子程序(来自“CMD-utilities\Assemblies”子文件夹的 EXE)填补,例如 $CONFIRMPAUSE
和 $TYPEINCOLOR
命令。)
即使 UTF-8 编码也部分可用,在 SQL 设置 CMD “**@<project_name>.cmd**”(约定名称)中,它在那里使用,没有 BOM 前缀。(其他 CMD 采用 OEM 代码页,如 CP437、CP866。)特殊的 Far Manager 插件 CmdCpAuto
(带有源代码的微型子程序:“HandicraftSDK\Auxiliary programs (sources)\Far plugins\CmdCpAuto”、“HandicraftSDK\Utilities\Far plugins\CmdCpAuto plugin, build 100 (Far v3)”)与 SQL-File 一起使用,在打开嵌入式文件编辑器时(通常通过 F4 键),为某些文件扩展名和文件名自动切换代码页。
当然,CMD 并不完美,但对于 SQL-File 来说是可行的。(这是该技术的手工实现。)
**V.** 多平台设置代表了一种强大的编程方法,可用于两种或多种语言,如果您能够通过语言预处理器或源代码生成任务来访问配置值(设置)。
能够以某种通用的、面向多种语言的预处理器指定一组定义,所谓的“多语言预处理器”,那将是很好的。某些值(尤其是常量)可能同时需要:在数据库中(在存储在 DB 中的 SQL 对象中)、在服务器进程的 EXE 中(用某种 OOP 语言)、以及在用户计算机的客户端(另一种 OOP 语言)。例如,我们想知道字符串长度容量、最小值和最大值等,它们在多个地方(DB、服务器进程、用户输入字段等)都需要。想象一下,我们描述(以某种文本或二进制格式)很多值(大小和其他),它们彼此依赖,并且所有这些名称和值在上述三个语言(位置)中的每一个中都神奇地可用,作为代码自动完成功能,当然还有一些小的相应差异,具有条件编译等可能性。它可能是连接非常不同环境的静态(即,仅在编译/解释阶段之前)的魔术胶水,这样一个美妙的预处理器。但现实通常是相反的,我们没有这样的静态连接(除了 C/C++ 中的一些罕见情况)。
在“@<project_name>.cmd”中定义的 SQL 设置主要用于参数化 SQL 文件,但不仅限于此。在极端情况下,一些重要的设置可以通过相应的构建任务用于源代码生成。在 MyFlat 应用和 BookRegistry 应用中,WriteLinesToFile
MSBUILD 任务执行此类生成 — C# 类,带有有价值的常量,用于在相关项目中(类:MyFlat.DB.DBConstants
、BookRegistry.Server.DB.DBConstants
和 BookRegistry.Client.DB.DBConstants
,在 DBConstants.auto.cs 中)。脚本:generate_metadata.cmd、generate_metadata.props、generate_metadata.targets 和 DBConstants.cs.props(在“SQL (DB-modelling)”SQL 项目文件夹中)。这是两个编程语言(T-SQL/C#)的最小静态集成的一种劳动密集型组织。
**VI.** SQL-File 技术与实验性 Web 应用程序
除了 Handicraft-SDK 提供的示例外,还有一个高级 SQL 项目,由作者建议探索 — BookRegistry app.,SQL-File 使用的另一个示例。(所有代码均为英文;但是表中的数据为俄语,但这不影响对 T-SQL 代码的理解。)
有两个关联的 SQL 项目(在其他 C# 代码文件夹中),文件夹
- “BookRegistry\SQL (DB-modelling)”: SQL 项目基础(表,
app.invisible
子查询); - “BookRegistry\SHARED\$ClientServer\!DB-queries (application SP)”: 应用程序查询,C#/SQL 并排。
这些是所谓的独立 SQL 项目,两个部分相互依赖。存储过程具有统一的参数(供 ASP 服务器进程使用)。除了结果代码,还使用 @Status
(GUID
)和 @Message
(string
)参数进行错误报告,这些参数可用于直接从 SP 向 Web 客户端报告错误。(还有其他有趣的功能。)
**BookRegistry application** 在我之前的一篇文章中简要描述过,位于 C# Corner
>> Client-Server WASM-Application In C#, TypeScript And Transact-SQL(来自 2020 年 9 月 29 日,作者 Sergei Y.Kitáev)。
**VII.** 我的工作,通用构造函数,名为 SQL-File
SQL-File 技术当然是一个实验性产品。尽管如此,这种方法(作为早期产品的化身)至少在两个实际数据库中得到了证明,在一个用于计算一系列市政和其他生活服务费用的系统中(处理在房产所有者数据库中)。
SQL-File 应用,作为 SQL-File 技术的概念性转变
潜在地,可以创建另一种技术,SQL-File 应用(即提议的名称),作为一种类似的方法,用于编写应用程序查询(不仅是数据库中的 SP 和函数),使用参数化的增强 T-SQL(应用程序时间查询),同时,这也应该适用于开发时间查询(在开发者的环境中)。今天,我们(我)只有 SQL-File 技术的手工实现(用于 MSSQL)。这实际上是一种特殊的构造函数,仅用于 dev.time
,用于确定参数化 SQL 文件的设置,以及构建我们自己的 SQL 翻译命令(为命令行处理器采用的脚本)。
然而,我认为参数化 SQL 文件的方法具有潜在的有效性,并且将简单的 SQL-File 转化为更灵活的东西(如 SQL-File 应用)并非不可能。此外,我认为今天没有好的方法来全局统一 SQL 语言(这是一个矛盾的想法),但有一种方法可以部分统一 SQL 方言,我认为这应该基于(为所有支持的 SQL 方言)相同的查询头和每个方言(DBMS)的独特查询体实现。这些是相对统一的查询头的示例(近似):GetServiceUser.sql(并排文件:SQL),UpdateBook.sql(并排文件:SQL),带有结果 @Status
和 @Message
输出参数(新未发布版本的相应 DB 库中的 @RStatus
和 @RMessage
名称),可返回整数值,指定一个或多个结果集(如果提供),等等。
这样的应用程序(数据库访问程序)可以通过将每个查询分成两个异构部分来组织,这两个部分形成所谓的并排文件。例如:C# 和 SQL(来自 SQL 客户端的“<QueryName>.cs”和来自 SQL 服务器端的“<QueryName>.sql”)。只需要基本 DB 映射功能,即可传输 SQL 查询输入数据(如参数)并从 SQL 查询(可返回整数值、输出参数、结果集)获取结果数据。不需要大型 ORM,因为这个想法与经典 ORM 概念相反。这就像用 C 语言编写操作系统内核模式的代码,通过 C# 和/或 C++ 的用户模式库为应用程序提供访问驱动程序的功能。在此,我指的是 IRP(输入/输出请求包)的所谓范例(在 KMDF/WDK 中)。当然,需要特殊的辅助工具来提高这种开发(双 SQL 查询)的效率,以便自动生成访问“数据库 IRP”的源代码片段:SQL/C#/…。
此外,如果我们要为服务器端提供高效的客户端查询的流畅支持(通过提供一个有价值的临时存储过程的替代品,作为从相应 SQL 文件或客户端的 SQL 代码片段准备的客户端查询),似乎需要对 DBMS 进行一些修改。沿着这条路,我们可以(或其他人)发明很多有用和有趣的东西。
结尾
老实说,你不太可能突然对检查 SQL-File 感到钦佩。这是因为它初看起来可能很棘手,而且带来的收益也可能令人怀疑。我的观点是,它实际上并不算太复杂,而且是值得的,至少从实验的角度来看。我创建了这个构造函数,它对我帮助很大。但总体思想比具体的实现更有价值。我希望您会对了解 SQL-File 技术感到兴趣。
— — —
许可(EULA)
本文以及任何相关的源代码和文件,均根据 MIT 许可证 授权。通过作者在顶部的回链可获得的下载存档(“sql-file-plain-samples.7z”)包含与本文精确相关的相应源代码和文件。