1

我必须修改一些似乎无法正常工作的 SQL 代码。

SQL 代码对我来说看起来很糟糕,但它在大多数情况下都有效。

假设我们有多个名称相似的供应商:Microsoft、Microsoft Corp 和 Microsoft, Inc 等。

所有查询返回都是 Microsoft,即使现有代码包含该行PRI_VENDOR_NAME like '%' @PRI_VENDOR_NAME '%'(或者,至少看起来确实如此)。

我似乎无法检查代码是否正常工作,因为它是一大段看起来令人讨厌的代码,它将数据附加到一个长字符串以执行。

当前程序:(准备尖叫)

ALTER PROCEDURE [dbo].[GetSignalMasterByFilter]
(
@planner varchar(50),
@reorder int,
@release int,
@CMTTED varchar(50),
@partid varchar(50),
@global_short_dt int,
@PRI_VENDOR_NAME varchar(50)
)
AS
BEGIN

DECLARE @Filter nvarchar(4000)
set @Filter = ' '

if @planner <> ''
begin
set @Filter = ' and planner in('  +  @planner + ')'
end

if @reorder = 1
begin
set @Filter = rtrim(@Filter) +  ' and (REORDER_50 = ' +  char(39) + 'Y' + char(39) +  ' )  '
end

if @reorder = 2
begin
set @Filter = rtrim(@Filter) +  ' and (REORDER_30 = ' +  char(39) + 'Y' + char(39) +  ' )  '
end

if @reorder = 3
begin
set @Filter = rtrim(@Filter) +  ' and (REORDER_POINT = ' +  char(39) + 'Y' + char(39) +  ' )  '
end

--if @noaction = 1
--begin
--set @Filter = rtrim(@Filter) +  ' and reorder in (' +  char(39) + 'Excess'  + char(39) + ',' + char(39) + 'Watch'  + char(39)  + ')'
--end

if @release = 1
begin
set @Filter = rtrim(@Filter) +  ' and (RELEASE_50 = ' +  char(39) + 'Y' + char(39) +  ' )  '
end

if @release = 2
begin
set @Filter = rtrim(@Filter) +  ' and (RELEASE_30 = ' +  char(39) + 'Y' + char(39) +  ' )  '
end

if @release = 3
begin
set @Filter = rtrim(@Filter) +  ' and (RELEASE_POINT = ' +  char(39) + 'Y' + char(39) +  ' )  '
end

if @CMTTED <> 'View ALL'
begin
set @Filter = rtrim(@Filter) +  ' and CMTTED > ' +  char(39) + '0'  + char(39)  + ' and isnumeric(CMTTED) = 1 '
end

if @global_short_dt = 1
begin
set @Filter = rtrim(@Filter) +  ' and  (global_short_dt is not null or cast(CMTTED as int) >  cast(ON_HAND as int)) ' 
end

if @global_short_dt = 2 
begin
set @Filter = rtrim(@Filter) +  ' and  (global_short_dt is not null or cast(CMTTED as int) >  cast(ON_HAND as int)) AND ((cast(QTY_IN_STATUS as float) + cast(ON_ORDER as float) + cast(ON_HAND as float)) < cast(CMTTED as int)) ' 
end

if @partid <> ''
begin
set @Filter = rtrim(@Filter) +  ' and partid like(' +  char(39) + @partid + '%' +  char(39) + ')'
end

if @PRI_VENDOR_NAME <> ''
begin
set @Filter = rtrim(@Filter) +  ' and PRI_VENDOR_NAME like(' +  char(39) + @PRI_VENDOR_NAME + '%' +  char(39) + ')'
end



DECLARE @sql nvarchar(4000)
SET @sql  = '
SELECT DISTINCT PRIMARY_VENDOR,case when PRI_VENDOR_NAME is null then PRIMARY_VENDOR else  PRIMARY_VENDOR +'   +  char(39) +    ' - '  +  char(39) +  '+ PRI_VENDOR_NAME end as PRI_VENDOR_NAME 
FROM SignalReportView WHERE PRIMARY_VENDOR is not null '  + rtrim(@filter)  + ' order by PRI_VENDOR_NAME'
--print @sql
EXEC sp_executesql @sql

end

我想做的是用我在下面开始的东西替换那个讨厌的字符串变量,但是 SQL 不是我的强项,所以它还没有完全返回任何数据:

MY PROCEDURE VERSION:不返回数据,但看起来更干净,将来更容易维护。

ALTER PROCEDURE GetSignalMasterByFilter2(
  @planner varchar(50),
  @reorder int,
  @release int,
  @CMTTED varchar(50),
  @partid varchar(50),
  @global_short_dt int,
  @PRI_VENDOR_NAME varchar(50)
) as begin

  SELECT DISTINCT
    PRIMARY_VENDOR,
    case when PRI_VENDOR_NAME is null then PRIMARY_VENDOR else PRIMARY_VENDOR +' - '+ PRI_VENDOR_NAME end as PRI_VENDOR_NAME 
  FROM
    SignalReportView
  WHERE
    (PRIMARY_VENDOR is not null)
    and (
      ISNULL(@planner,0)=0 or
      planner in (@planner))
    and (
      (@reorder=1 and REORDER_50='Y') or
      (@reorder=2 and REORDER_30='Y') or 
      (@reorder=3 and REORDER_POINT='Y') or 
      (1=1)
    )
    and (
      (@release=1 and RELEASE_50='Y') or
      (@release=2 and RELEASE_30='Y') or
      (@release=3 and RELEASE_POINT='Y') or
      (1=1)
    )
    and (
      (@CMTTED='View ALL') or
      (0<CMTTED and ISNUMERIC(CMTTED)=1)
    )
    and (
      (
        (@global_short_dt=1) and
        (
          (GLOBAL_SHORT_DT is not null) or
          (CAST(ON_HAND as int) < CAST(CMTTED as int))
        )
      ) or
      (1=1)
    )
    and (
      (
        (@global_short_dt=2) and
        (
          (GLOBAL_SHORT_DT is not null) or
          (
            (CAST(ON_HAND as int) < CAST(CMTTED as int)) and 
            ((CAST(QTY_IN_STATUS as float) + CAST(ON_ORDER as float) + CAST(ON_HAND as float)) < CAST(CMTTED as int))
          )
        )
      ) or
      (1=1)
    )
    and (
      ISNULL(@partid,0)=0 or
      (PARTID like '%'+@partid+'%')
    )
    and (
      ISNULL(@PRI_VENDOR_NAME,0)=0 or
      (PRI_VENDOR_NAME like '%'+@PRI_VENDOR_NAME+'%')
    )
  ORDER BY PRI_VENDOR_NAME

end

所以,我的问题是:

将原始脚本重写为其他开发人员将来更容易维护的版本是否是个好主意?

如果,有人能发现为什么现有的 SQL 没有返回所有供应商吗?

如果,有人可以指导我设计我的版本吗?它目前不起作用 - 可能是因为我有一些逻辑错误。此外,这些(1=1)条款不适合我,但我不知道如何绕过它们。由于我的程序不返回任何数据,所以我现在不能使用它。

我很抱歉没有发布表结构,但它们都相当大,并且上面的存储过程查询了一个看起来更糟糕的视图(我什至无法遵循)。

4

3 回答 3

3

我多次遇到类似的情况。和我一起......通常我要清理的是我自己的代码。

在做这样的事情时,请不要只考虑代码的可读性。您还必须考虑对服务器的影响。通常,有多种方法可以编写产生相同结果的查询。在这些情况下,您应该选择执行速度最快的版本。如果这意味着您使用的是“更丑”的版本,那就这样吧。

显然,您查看了原始代码并想,“嗯?”。这很好地表明应该有代码注释。

我没有花太多时间查看代码,但似乎该过程有各种可选参数(该空字符串中的选项表示代码应忽略该参数)。可以编写适应这种情况的代码而不使用动态 sql,但该代码几乎总是执行得较慢。在这里阅读解释: 你在 WHERE 子句中使用 Column=@Param OR @Param IS NULL 吗?不要,它不执行

于 2013-07-19T16:29:47.020 回答
1

我认为 G Mastros 给了你这个问题的正确答案。我只想澄清我自己的看法。

首先,如果您的过程执行得更快,那么对于大数据而言,其他一切都无关紧要。其次,对我来说,你的版本比第一个更难理解。通过为每个参数添加注释并设置它会更容易阅读。

所以我的回答是否定的,当然,由于@filter 中的条件,它不会返回所有供应商。只需在执行之前打印它,以查看由给定参数先前构成的条件。

于 2013-07-19T17:04:47.757 回答
0

尝试这样的事情:

ALTER PROCEDURE GetSignalMasterByFilter2(
  @planner varchar(50),
  @reorder int,
  @release int,
  @CMTTED varchar(50),
  @partid varchar(50),
  @global_short_dt int,
  @PRI_VENDOR_NAME varchar(50)
) as 

begin

  SELECT DISTINCT
    PRIMARY_VENDOR,
    case when PRI_VENDOR_NAME is null then PRIMARY_VENDOR else PRIMARY_VENDOR +' - '+ PRI_VENDOR_NAME end as PRI_VENDOR_NAME 
  FROM
    SignalReportView
  WHERE
       PRIMARY_VENDOR is not null
    and 
       (
           @Planner IS NULL 
        OR @planner = ''
        OR planner in (@planner))
    and 
    (  @reorder NOT IN (1,2,3) OR
        (@reorder=1 and REORDER_50='Y') or
        (@reorder=2 and REORDER_30='Y') or 
        (@reorder=3 and REORDER_POINT='Y') 
    )
    and 
    (
       @release NOT IN (1,2,3) OR
      (@release=1 and RELEASE_50='Y') or
      (@release=2 and RELEASE_30='Y') or
      (@release=3 and RELEASE_POINT='Y') 
    )
    and 
    (
      @CMTTED='View ALL' or
      0<CMTTED and ISNUMERIC(CMTTED)=1
    )
    and 
    ( 
       @global_short_dt NOT IN (1,2) OR
       (global_short_dt is not NULL AND @global_short_dt=1 AND CAST(ON_HAND as int) < CAST(CMTTED as int)) OR
       (global_short_dt is not NULL AND @global_short_dt=2 AND CAST(ON_HAND as int) < CAST(CMTTED as int) 
           and (CAST(QTY_IN_STATUS as float) + CAST(ON_ORDER as float) + CAST(ON_HAND as float)) < CAST(CMTTED as int))
    )
    and 
    (
      @partid IS NULL OR 
      @partid = '' OR
      PARTID like '%'+@partid+'%'
    )
    and 
    (
      @PRI_VENDOR_NAME IS NULL OR
      @PRI_VENDOR_NAME = '' OR
      PRI_VENDOR_NAME like '%'+@PRI_VENDOR_NAME+'%'
    )
  ORDER BY PRI_VENDOR_NAME

end

我想我已经修复了你所有的逻辑错误,但是因为我没有任何表格,所以没有经过测试。

至于性能,您必须检查两个版本并查看。无论哪种方式都无法保证。

于 2013-07-19T17:05:32.073 回答