3

我正在研究一个存储过程,它将接受一个字符串并返回一个新的文本字符串。输入参数是@OrderId并且@OrderText是一个带有美元符号封闭变量的字符串,就像这样......$Order Name$ sent to $Customer$

有效变量在一个Variables表中(订单名称、客户等值,总共 25 个应该保持相当静态)。变量在字符串中只能使用一次。

存储过程需要返回字符串,但将变量替换为各自的值。

示例 1

输入:123, $Order Name$ sent to $Customer$

回报:Toolkit sent to StackCustomer Inc.

示例 2

输入:456, $Customer$ requests $delivery method$ for $order type$

回报:ABC Inc requests fast shipping for pallet orders.

可以使用函数检索每个变量。

    DECLARE @OrderId int = 123
    DECLARE @InputText VARCHAR(500) = '$Order Name$ sent to $Customer$'
    select 
     @InputText = case when @InputText like '%$order name$%' 
             then replace(@InputText, '$Order Name$', getOrderName(id) else '' end,
     @InputText = case when @InputText like '%$customer$' 
             then replace(@InputText, '$Customer$', getCustomer(id) else '' end
      -- repeat 25 times

有没有更好的办法?我主要关心的是可维护性 - 如果添加、重命名或删除变量,则需要更改此存储过程(尽管我被告知每年只会发生几次,如果那样的话)。在这种情况下,动态 sql 可以提供帮助吗?

4

2 回答 2

3

就个人而言,我会创建一个关键字表来维护它。像这样的东西

CREATE TABLE [keywords] (
  key_value VARCHAR(100) NOT NULL,
  function_value VARCHAR(100) NOT NULL
  )
INSERT INTO [keywords]
VALUES
('$Customer$','getCustomer(id)'),
('$Order Name$' ,'getOrderName(id)'),
('$order type$','getOrderType(id)')

然后使用动态sql创建REPLACE SQL

DECLARE @OrderId int = 123
DECLARE @InputText VARCHAR(500) = '$Order Name$ sent to $Customer$'

DECLARE @sql VARCHAR(8000) = 'SELECT '

SELECT 
  @sql = @sql + 
  ' @InputText = replace(@InputText, ''' + key_value + ''', ' + function_value + ')'
    + ' ,'
FROM keywords
WHERE  @InputText LIKE '%' + key_value + '%'


SELECT @sql = LEFT(@sql, LEN(@sql) -1)
PRINT @sql

EXEC(@sql)

SQLFiddle

于 2013-04-05T18:21:45.817 回答
0

如果要在过程中使用输入变量,我真的不明白为什么需要进行标记化。

SQL Management Studio 已经有以下形式的令牌模板可用:

<(tokenName),(datatype),(defaultvalue)>

您可以使用 CTRL + SHIFT + M 或在 2012 年使用 ALT > Q > S 直接使用 SQL Managment Studio 填充他们的数据,或者通过文本在环境中查找它们的值。

如果您尝试输入一个输入以供外部开发平台访问,该平台会更改 ADO.NET 或 C#/VB.NET 中的实体框架等字符串,我仍然不明白为什么您不只是制作更多输入变量。

你可以很容易地做到这一点:

Declare @OrderPlace varchar(128), @Customer varchar(64), @StringCombine varchar(512);

Select 
   @OrderPlace = 'Place I am at'
,  @Customer = 'Mr Customer';

Select @StringCombine = @Customer + ' order at ' + @OrderPlace

然后,如果另一种语言访问您的 SQL 服务器过程,则只需输入两个参数 @Customer 和 @OrderPlace。您甚至可以将 @StringCombine 设置为输出变量。这比文本替换字符然后运行字符串更可取。这可能会导致 SQL 注入攻击,因此清理输入是返回数据的重要组成部分,特别是如果您要在 SQL 运行之前更改某些内容以使其运行。

您提到了可维护性,这更加健壮,因为如果我将逻辑更改为 proc 但不更改变量名称,我不必更改任何其他内容。如果我必须更改 ADO.NET 或其他库以获取引用,然后更改 SQL 代码,那就需要做更多的工作。通常,在使用令牌时,我会努力重用代码,其中一部分可能会下降,只会损害它的那一部分,而不是把整个事情都搞砸。

于 2013-04-05T18:21:47.860 回答