SQL 脚本 - 是不是存在与 #define 等效的内容?

Posted

技术标签:

【中文标题】SQL 脚本 - 是不是存在与 #define 等效的内容?【英文标题】:SQL Scripts - Does the equivalent of a #define exist?SQL 脚本 - 是否存在与 #define 等效的内容? 【发布时间】:2012-03-03 13:59:56 【问题描述】:

我有一个用于构建表和存储过程的脚本。例如,我有一列类型为varcharvarchar 需要一个大小参数,我也将这个大小用作存储过程和这些过程中的参数。

它的大小是否可以与 #define 等效,因此我可以轻松调整大小而无需更改整个脚本?

我正在使用 mysql 工作台。

编辑

我试过SETDECLARE

我有一个脚本 - 这是(删节的)

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/…,你可以用SETdev.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与SQL哪个比较难?哪个比较高效?

VBA脚本检查MS ACCESS上是不是存在表,如果存在则删除

如何检查 SQL 脚本是不是在 MS SQL Server 中成功执行?

const与define的区别

此 PHP 代码中是不是存在任何安全漏洞? [关闭]