SQL 脚本 - 是不是存在与 #define 等效的内容?
Posted
技术标签:
【中文标题】SQL 脚本 - 是不是存在与 #define 等效的内容?【英文标题】:SQL Scripts - Does the equivalent of a #define exist?SQL 脚本 - 是否存在与 #define 等效的内容? 【发布时间】:2012-03-03 13:59:56 【问题描述】:我有一个用于构建表和存储过程的脚本。例如,我有一列类型为varchar
。 varchar
需要一个大小参数,我也将这个大小用作存储过程和这些过程中的参数。
它的大小是否可以与 #define
等效,因此我可以轻松调整大小而无需更改整个脚本?
我正在使用 mysql 工作台。
编辑
我试过SET
和DECLARE
我有一个脚本 - 这是(删节的)
CREATE TABLE `locations`
(
`location` VARCHAR(25) NOT NULL
);
...
CREATE PROCEDURE AddLocation (IN location VARCHAR(25)
BEGIN
...
END$$
我想要实现的是用 constant 替换脚本中的值 25 - 类似于创建表和存储过程的脚本顶部的 #define
,所以我能够轻松地将 25 更改为另一个数字。
有人找到解决这个问题的方法了吗?
【问题讨论】:
声明? dev.mysql.com/doc/refman/5.0/en/declare-local-variable.html 我写了一些软件来做这样的事情——它是免费的,它在这里mysql-pre-processor.batcave.net。只需将一些东西放入您选择的慈善机构的桶中 【参考方案1】:C 预处理器 (cpp) 在历史上与 C 相关联(因此得名),但它确实是一个通用的文本处理器,可以用于(或滥用)其他用途。
考虑这个名为 location.src 的文件(稍后会详细介绍)。
// C++ style comments works here
/* C style works also */
-- plain old SQL comments also work,
-- but you should avoid using '#' style of comments,
-- this will confuse the C pre-processor ...
#define LOCATION_LEN 25
/* Debug helper macro */
#include "debug.src"
DROP TABLE IF EXISTS test.locations;
CREATE TABLE test.locations
(
`location` VARCHAR(LOCATION_LEN) NOT NULL
);
DROP PROCEDURE IF EXISTS test.AddLocation;
delimiter $$
CREATE PROCEDURE test.AddLocation (IN location VARCHAR(LOCATION_LEN))
BEGIN
-- example of macro
ASSERT(length(location) > 0, "lost or something ?");
-- do something
select "Hi there.";
END
$$
delimiter ;
和文件debug.src,其中包含:
#ifdef HAVE_DEBUG
#define ASSERT(C, T) \
begin \
if (not (C)) then \
begin \
declare my_msg varchar(1000); \
set my_msg = concat("Assert failed, file:", __FILE__, \
", line: ", __LINE__, \
", condition ", #C, \
", text: ", T); \
signal sqlstate "HY000" set message_text = my_msg; \
end; \
end if; \
end
#else
#define ASSERT(C, T) begin end
#endif
编译时:
cpp -E location.src -o location.sql
你会得到你正在寻找的代码,用 cpp 扩展#define 值。
编译时:
cpp -E -DHAVE_DEBUG location.src -o location.sql
你得到了同样的结果,加上 ASSERT 宏(作为奖励发布,以显示 可以做什么)。
假设在测试环境中部署了具有 HAVE_DEBUG 的构建(在 5.5 或更高版本中,因为使用了 SIGNAL),结果如下所示:
mysql> call AddLocation("Here");
+-----------+
| Hi there. |
+-----------+
| Hi there. |
+-----------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
mysql> call AddLocation("");
ERROR 1644 (HY000): Assert failed, file:location.src, line: 24, condition length(location) > 0, text: lost or something ?
请注意文件名、行号和条件如何指向源代码中 location.src 中引发断言的位置,再次感谢 C 预处理器。
现在,关于“.src”文件扩展名:
你可以使用任何东西。 具有不同的文件扩展名有助于生成文件等,并防止混淆。编辑:最初发布为 .xql,为清楚起见重命名为 .src。这里没有与 xml 查询相关的内容。
与任何工具一样,使用 cpp 可以带来好处,并且以可移植方式维护 LOCATION_LEN 的用例看起来非常合理。 它也可能导致不好的事情,有太多的#include、嵌套的#ifdef hell、宏等,最终混淆了代码,所以你的里程可能会有所不同。
有了这个答案,你就得到了全部内容(#define
、#include
、#ifdef
、__FILE__
、__LINE__
、#C
,要构建的命令行选项),所以我希望它应该涵盖这一切。
【讨论】:
巧妙。我从没想过对 SQL 文件使用预处理器。 我希望有一个不需要使用预处理器的解决方案。但我会探索这个选项。【参考方案2】:你试过 SET 吗?
这是一个例子:
SET @var_name = expr
这里有更多例子: http://dev.mysql.com/doc/refman/5.0/en/user-variables.html
【讨论】:
我已经尝试过声明和设置。只想将各个字段的大小放在脚本的顶部。脚本的其余部分基于这些值创建表/视图/存储过程/函数。只是为了更容易重建具有不同大小的各个字段的数据库。 啊...也许你想读这个***.com/questions/1009954/…,你可以用SET
dev.mysql.com/doc/refman/5.1/en/set-option.html分配一个全局变量【参考方案3】:
听起来您正在寻找用户定义的数据类型。不幸的是,对于我们来说,mySQL 还不支持用户定义的数据类型,如 SQL Server、Oracle 和其他。
以下是支持的数据类型列表: http://dev.mysql.com/doc/refman/5.0/en/data-types.html
【讨论】:
【参考方案4】:对于那些感兴趣的人:
我最终写了一个 php 脚本,因为:
a) 可以访问数据库的机器不属于我,我无法访问C 预处理器 b)其他两个答案不起作用。 c) 似乎是最简单的解决方案
这是为那些可能觉得有用的人准备的脚本。我用它来定义表格列 宽度,然后在存储过程中使用这些相同的值。这是由于列 宽度尚未完全确定用于生产。
我还内置了您可以定义持续几行的字符串。这样做的好处是我可以遵守 80 列宽(因此打印看起来可读)。
这是脚本
<?php
if (1==count($argv))
?>
Processing #defines from stdin and send to SQL server:
This script will remove
1. #define <name> <integer>
2. #define <name> '<string>'
3. #define <name> '<string>' \
'<continuation of string>'
and replace the occurances of name with the #define value as specified
<name> is upper case alpha numberics or underscores, not starting with a
digit.
The arguments of this script is passed to the mysql executable.
<?php
exit(1);
function replace(&$newValues, $a, $b, $c)
return $a . (array_key_exists($b, $newValues) ? $newValues[$b] : $b) . $c;
// The patterns to be used
$numberPattern='/^#define[ \t]+([A-Z_][A-Z0-9_]*)[ \t]+(0|([1-9][0-9]*))'.
'[ \t]*[\r\n]+$/';
$stringPattern= '/^#define[ \t]+([A-Z_][A-Z0-9_]*)[ \t]+\''.
'((\\\'|[^\'\r\n])*)\'[ \t]*(\\\\0,1)[\n\r]+$/';
$continuationPattern='/^[ \t]*\'((\\\'|[^\'\r\n])*)\'[ \t]*'.
'(\\\\0,1)[\n\r]+$/';
// String to be evaluated to replace define values with a new value
$evalStr='replace($newValues, \'\1\', \'\2\', \'\3\');';
array_splice($argv, 0, 1);
// Open up the process
$mysql=popen("mysql ".implode(' ', $argv), 'w');
$newValues=array(); // Stores the defines new values
// Variables to control the replacement process
$define=false;
$continuation=false;
$name='';
$value='';
while ($line=fgets(STDIN))
$matches=array();
// #define numbers
if (!$define &&
1 == preg_match($numberPattern, $line, $matches))
$define = true;
$continuation = false;
$name = $matches[1];
$value = $matches[2];
// #define strings
if (!$define &&
1 == preg_match($stringPattern,
$line, $matches))
$define = true;
$continuation = ('\\' == $matches[4]);
$name = $matches[1];
$value = $matches[2];
// For #define strings that continue over more than one line
if ($continuation &&
1 == preg_match($continuationPattern,
$line, $matches))
$value .= $matches[1];
$continuation = ('\\' == $matches[3]);
// Have a complete #define, add to the array
if ($define && !$continuation)
$define = $continuation = false;
$newValues[$name]=$value;
elseif (!$define)
// Do any replacements
$line = preg_replace('/(^| |\()([A-Z_][A-Z0-9_]*)(\)| |$)/e',
$evalStr, $line);
echo $line; // In case we need to have pure SQL.
// Send it to be processed.
fwrite($mysql, $line) or die("MySql has failed!");
pclose($mysql);
?>
【讨论】:
以上是关于SQL 脚本 - 是不是存在与 #define 等效的内容?的主要内容,如果未能解决你的问题,请参考以下文章
如何确定 SQL Server 2012 中是不是存在序列?
VBA脚本检查MS ACCESS上是不是存在表,如果存在则删除