我必须修改一些似乎没有按预期工作的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不是我的力量所以它还没有完全返回任何数据:
我的程序版本:不会返回数据,但将来会更清晰,更易于维护。
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)
条款与我的关系并不好,但我不知道如何绕过它们。由于我的程序没有返回任何数据,我现在无法使用它。
我为没有发布表格结构而道歉,但它们都相当庞大,上面的存储过程查询了一个看起来更糟糕的视图(我甚至无法遵循)。
答案 0 :(得分:3)
我多次遇到过类似的情况。和我一起....我通常是我自己的代码,我正在努力清理。
在做这样的事情时,请不要只考虑代码可读性。您还必须考虑对服务器的影响。通常,有多种方法可以编写产生相同结果的查询。在这些情况下,您应该选择执行速度最快的版本。如果这意味着您使用的是“丑陋”版本,那就这样吧。
显然,你看了原始代码并想了想,“嗯?”。这表明应该有代码注释。
我没有花太多时间查看代码,但似乎程序有各种可选参数(空字符串中的选项表示代码应该忽略该参数)。可以在不使用动态sql的情况下编写适应这种情况的代码,但该代码几乎总是执行得更慢。请阅读此处获取解释:Do you use Column=@Param OR @Param IS NULL in your WHERE clause? Don't, it doesn't perform
答案 1 :(得分:1)
我认为G Mastros为您提供了正确答案。我只想澄清我自己看到的。
首先,如果你的程序执行得更快,那么大数据就没有其他问题了。 其次,你的版本比第一个版本更难以理解。 通过为每个参数添加注释并设置它将更容易阅读。
所以我的答案是否定的,当然由于@filter的条件,它并没有归还所有供应商。只需在执行前打印它,以查看先前由给定参数产生的条件。
答案 2 :(得分: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
我认为我已经解决了所有的逻辑错误,但由于我没有任何表格,因此未经过测试。
至于性能,您必须检查两个版本并查看。无论如何都无法保证。