什么是存储过程

时间:2010-02-23 13:30:43

标签: sql-server stored-procedures

这是一个存储过程(至少我必须假设),它将Sql查询构造为String,然后使用exec调用它。由于某种原因,自称为程序员的家伙,使用“〜”字符连接一些值,然后将它们分解回应用程序层。当某个复选框被“选中”时,此SP会中断。问题是如何调试此噩梦。我发现当选中CheckBox时,它会在某些TypeCode的开头添加一个不必要的“~1”并且它会中断。如果没有选择,它按预期工作。 (顺便说一下,我真的很想知道这个叫做什么样的编码练习)。

  ALTER  PROC [dbo].[BUTCEREP] @SirketKod varchar(10), @IlkTarih varchar(10), @SonTarih varchar(10), @Tip int, @Tur int, @MasrafMrk varchar(100), @DovizKod varchar(5), @MaliTKod varchar(10)
    -- Tip 0-TarihAraligi; 1-2AylikButce; 2-YTDButce; 3-YTDCompPrev
    -- Tur 0-Muhasebe 1-Gider 2-Butce 3-ButceMuhasebe 4-ButceGider
    AS
      declare
        @SqlText nvarchar(4000),
        @SqlBud varchar(4000),
        @SqlMuh varchar(4000),
        @SqlGid varchar(4000),
        @xIlkT datetime,
        @xSonT datetime,
        @ThisMonth varchar(10),
        @NextMonth varchar(10),
        @ThisYear varchar(10),
        @PrevYear varchar(10)


      if (not @IlkTarih is null) set @xIlkT = CONVERT(datetime,@IlkTarih,103)
      if (not @SonTarih is null) set @xSonT = CONVERT(datetime,@SonTarih,103)
      set @DovizKod=IsNull(@DovizKod, '')
      if @Tip=1 and MONTH(@xIlkT)=12 set @xIlkT = dateadd(month,-1,@xIlkT)

      set @ThisMonth = CONVERT(varchar,MONTH(@xIlkT))
      set @NextMonth = CONVERT(varchar,MONTH(@xIlkT)+1)
      set @ThisYear  = CONVERT(varchar,YEAR(@xIlkT))
      set @PrevYear  = CONVERT(varchar,YEAR(@xIlkT)-1)

      set @SqlMuh='select X.MuhHesapKod,X.Tarih,SUM(CAST(X.Borc   AS FLOAT)) Borc,'+
                                               'SUM(CAST(X.Alacak AS FLOAT)) Alacak' +
                   ' from (select CASE S.N WHEN 1 THEN LEFT(D.MuhHesapKod,3)' +
                                         ' WHEN 2 THEN LEFT(D.MuhHesapKod,7)' +
                                         ' ELSE D.MuhHesapKod END MuhHesapKod,' +
                                 'D.Tarih,Borc,Alacak' +
                  ' from '+@DovizKod+'MUH_D D inner join '+@DovizKod+'MUH_H H on (H.SirketKod=D.SirketKod) and (H.KontrolNo=D.KontrolNo)'+
                 ' CROSS JOIN dbo.SeriTable(3) S' +
                 ' where D.SirketKod=' + QuoteName(@SirketKod,'''') +
                  case when IsNull(@MasrafMrk,'')<>'' then ' and D.MasrafMrkKod in (select Kod from GetArray('+QuoteName(@MasrafMrk,'''')+'))' else '' end +
                  case @Tip
                    when 0 then ' and D.Tarih BETWEEN ' + IsNull(QuoteName(CONVERT(varchar,@xIlkT,103),''''),'D.Tarih') + ' and ' + IsNull(QuoteName(CONVERT(varchar,@xSonT,103),''''),'D.Tarih')
                    when 1 then ' and YEAR(D.Tarih)=' +@ThisYear+' and MONTH(D.Tarih) in ('+@ThisMonth+','+@NextMonth+')'
                    when 2 then ' and YEAR(D.Tarih)=' +@ThisYear+' and MONTH(D.Tarih)<='+@ThisMonth
                    when 3 then ' and (YEAR(D.Tarih)='+@PrevYear+' or (YEAR(D.Tarih)='+@ThisYear+' and MONTH(D.Tarih)<='+@ThisMonth+'))'
                  end +
                  ' and IsNull(H.FisTip,'''')<>''KAPANIS'''+
                           ') X' +
                 ' where X.MuhHesapKod in (select Kod from MALIT_M where SirketKod=' + QuoteName(@SirketKod,'''') +
                                                                   ' and MaliTKod='  + QuoteName(@MaliTKod,'''') + ')' +
                 ' group by X.MuhHesapKod,X.Tarih'

      set @SqlMuh = ' select 1 Tip,CAST(4 AS char(1))+''~0~''+M.MuhHesapKod Kod,' +
                    case @Tip
                      when 0 then 'SUM((M.Borc-M.Alacak)) TopBak'
                      when 1 then 'SUM(CASE WHEN MONTH(M.Tarih)=' +@ThisMonth+' THEN 1 ELSE 0 END*(M.Borc-M.Alacak)) A1Bak,' +
                                  'SUM(CASE WHEN MONTH(M.Tarih)=' +@NextMonth+' THEN 1 ELSE 0 END*(M.Borc-M.Alacak)) A2Bak'
                      when 2 then 'SUM(CASE WHEN MONTH(M.Tarih)=' +@ThisMonth+' THEN 1 ELSE 0 END*(M.Borc-M.Alacak)) A1Bak,' +
                                  'SUM(CASE WHEN MONTH(M.Tarih)<='+@ThisMonth+' THEN 1 ELSE 0 END*(M.Borc-M.Alacak)) A2Bak'
                      when 3 then 'SUM(CASE WHEN YEAR(M.Tarih)=' +@ThisYear+' AND MONTH(M.Tarih)=' +@ThisMonth+' THEN 1 ELSE 0 END*(M.Borc-M.Alacak)) A1Bak,' +
                                  'SUM(CASE WHEN YEAR(M.Tarih)=' +@ThisYear+' AND MONTH(M.Tarih)<='+@ThisMonth+' THEN 1 ELSE 0 END*(M.Borc-M.Alacak)) A2Bak,' +
                                  'SUM(CASE WHEN YEAR(M.Tarih)=' +@PrevYear+' THEN 1 ELSE 0 END*(M.Borc-M.Alacak)) A3Bak'
                    end +
                    ' from (' + @SqlMuh + ') M' +
                    ' where M.MuhHesapKod in (select Kod from MALIT_M where SirketKod=' + QuoteName(@SirketKod,'''') +
                                                                       ' and MaliTKod=' + QuoteName(@MaliTKod,'''') + ')'+
                    ' group by M.MuhHesapKod'

      set @SqlGid = ' select 1 Tip,CAST(2 AS char(1))+''~0~''+C.GiderKod Kod,' +
                    case @Tip
                      when 0 then 'SUM((2*C.IslemTuru-1)*'+CASE WHEN @DovizKod='' THEN '(TutarTL+GVergiTutar)' ELSE 'GEURO' END+') TopBak'
                      when 1 then 'SUM(CASE WHEN MONTH(C.Tarih)='+@ThisMonth+' THEN 1 ELSE 0 END*(2*C.IslemTuru-1)*'+CASE WHEN @DovizKod='' THEN '(TutarTL+GVergiTutar)' ELSE 'GEURO' END+') A1Bak,' +
                                  'SUM(CASE WHEN MONTH(C.Tarih)='+@NextMonth+' THEN 1 ELSE 0 END*(2*C.IslemTuru-1)*'+CASE WHEN @DovizKod='' THEN '(TutarTL+GVergiTutar)' ELSE 'GEURO' END+') A2Bak'
                      when 2 then 'SUM(CAST(CASE WHEN MONTH(C.Tarih)=' +@ThisMonth+ ' THEN 1 ELSE 0 END*(2*C.IslemTuru-1)*'+CASE WHEN @DovizKod='' THEN '(TutarTL+GVergiTutar)' ELSE 'GEURO' END+' AS FLOAT)) A1Bak,' +
                                  'SUM(CAST(CASE WHEN MONTH(C.Tarih)<='+@ThisMonth+ ' THEN 1 ELSE 0 END*(2*C.IslemTuru-1)*'+CASE WHEN @DovizKod='' THEN '(TutarTL+GVergiTutar)' ELSE 'GEURO' END+' AS FLOAT)) A2Bak'
                      when 3 then 'SUM(CAST(CASE WHEN YEAR(C.Tarih)=' +@ThisYear+' AND MONTH(C.Tarih)=' +@ThisMonth+ ' THEN 1 ELSE 0 END*(2*C.IslemTuru-1)*'+CASE WHEN @DovizKod='' THEN '(TutarTL+GVergiTutar)' ELSE 'GEURO' END+' AS FLOAT)) A1Bak,' +
                                  'SUM(CAST(CASE WHEN YEAR(C.Tarih)=' +@ThisYear+' AND MONTH(C.Tarih)<='+@ThisMonth+ ' THEN 1 ELSE 0 END*(2*C.IslemTuru-1)*'+CASE WHEN @DovizKod='' THEN '(TutarTL+GVergiTutar)' ELSE 'GEURO' END+' AS FLOAT)) A2Bak,' +
                                  'SUM(CAST(CASE WHEN YEAR(C.Tarih)=' +@PrevYear+' THEN 1 ELSE 0 END*(2*C.IslemTuru-1)*'+CASE WHEN @DovizKod='' THEN '(TutarTL+GVergiTutar)' ELSE 'GEURO' END+' AS FLOAT)) A3Bak'
                    end +
                    ' from CHI_D C'+
                    ' where C.GiderKod in (select Kod from MALIT_M where SirketKod=' + QuoteName(@SirketKod,'''') +
                                                                   ' and MaliTKod='  + QuoteName(@MaliTKod ,'''') + ')'+
                    case when IsNull(@MasrafMrk,'')<>'' then ' and C.MasrafMrkKod in (select Kod from GetArray('+QuoteName(@MasrafMrk,'''')+'))' else '' end +

                    case @Tip
                      when 0 then ' and C.Tarih BETWEEN ' + IsNull(QuoteName(CONVERT(varchar,@xIlkT,103),''''),'C.Tarih') + ' and ' + IsNull(QuoteName(CONVERT(varchar,@xSonT,103),''''),'C.Tarih') + ')'
                      when 1 then ' and YEAR(C.Tarih)='+@ThisYear+' and MONTH(C.Tarih) in (' +@ThisMonth+','+@NextMonth+')'
                      when 2 then ' and YEAR(C.Tarih)='+@ThisYear+' and MONTH(C.Tarih)<='+@ThisMonth
                      when 3 then ' and (YEAR(C.Tarih)='+@PrevYear+' or (YEAR(C.Tarih)='+@ThisYear+' and MONTH(C.Tarih)<='+@ThisMonth+'))'
                    end +
                    ' group by C.GiderKod'

      set @SqlBud='select 0 Tip,CAST(D.IslemTipi AS char(1))+''~0~''+D.KalemKod Kod,' +
                  case @Tip
                    when 0 then 'sum((2*D.IslemTuru-1)*IsNull(D.Tutar,0)) TopBak'
                    when 1 then 'sum(CASE WHEN MONTH(D.BasTarih)='+@ThisMonth+' THEN 1 ELSE 0 END*(2*D.IslemTuru-1)*IsNull(D.Tutar,0)) A1Bak,' +
                                'sum(CASE WHEN MONTH(D.BasTarih)='+@NextMonth+' THEN 1 ELSE 0 END*(2*D.IslemTuru-1)*IsNull(D.Tutar,0)) A2Bak'
                    when 2 then 'sum(CASE WHEN MONTH(D.BasTarih)='+@ThisMonth+' THEN 1 ELSE 0 END*(2*D.IslemTuru-1)*IsNull(D.Tutar,0)) A1Bak,' +
                                'sum((2*D.IslemTuru-1)*IsNull(D.Tutar,0)) A2Bak'
                    when 3 then 'sum(CASE WHEN MONTH(D.BasTarih)=' +@ThisMonth+' THEN 1 ELSE 0 END*(2*D.IslemTuru-1)*IsNull(D.Tutar,0)) A1Bak,' +
                                'sum(CASE WHEN MONTH(D.BasTarih)<='+@ThisMonth+' THEN 1 ELSE 0 END*(2*D.IslemTuru-1)*IsNull(D.Tutar,0)) A2Bak,' +
                                'sum((2*D.IslemTuru-1)*IsNull(D.Tutar,0)) A3Bak'
                  end +
                  ' from dbo.GetButceList('+ QuoteName(@SirketKod,'''') +','+ IsNull(QuoteName(@MasrafMrk,''''),'null')+','+QuoteName(@DovizKod,'''')+',0) D' +
                  ' where D.KalemKod in (select Kod from MALIT_M where SirketKod=' + QuoteName(@SirketKod,'''') +
                                                                 ' and MaliTKod='  + QuoteName(@MaliTKod,'''') + ')'+
                  case @Tip
                    when 0 then ' and D.BasTarih>=' + IsNull(QuoteName(CONVERT(varchar,@xIlkT,103),''''),'D.BasTarih') + ' and D.BitTarih<=' + IsNull(QuoteName(CONVERT(varchar,@xSonT,103),''''),'D.BitTarih')
                    when 1 then ' and YEAR(D.BasTarih)='+@ThisYear+' and MONTH(D.BasTarih) in (' +@ThisMonth+','+@NextMonth+')'
                    when 2 then ' and YEAR(D.BasTarih)='+@ThisYear+' and MONTH(D.BasTarih)<='+@ThisMonth
                    when 3 then ' and YEAR(D.BasTarih)='+@ThisYear
                  end +
                  ' group by D.KalemKod,D.IslemTipi'

    -- Tur 0-Muhasebe 1-Gider 2-Butce 3-ButceMuhasebe 4-ButceGider
      set @SqlText = case @Tur
                       when 0 then @SqlMuh
                       when 1 then @SqlGid
                       when 2 then @SqlBud
                       when 3 then @SqlBud + ' union all ' + @SqlMuh
                       when 4 then @SqlBud + ' union all ' + @SqlGid
                     end

      if @Tip in (1,2)
        set @SqlText='select Kod,' +
                            'SUM(CASE Tip WHEN 0 THEN IsNull(A1Bak,0) ELSE 0 END) A10Bak,' +  --budget first
                            'SUM(CASE Tip WHEN 0 THEN IsNull(A2Bak,0) ELSE 0 END) A20Bak,' +  --budget second
                            'SUM(CASE Tip WHEN 1 THEN IsNull(A1Bak,0) ELSE 0 END) A11Bak,' +  --actual first
                            'SUM(CASE Tip WHEN 1 THEN IsNull(A2Bak,0) ELSE 0 END) A21Bak ' +  --actual second
                      'from (' + @SqlText + ') X' +
                      ' group by Kod'
      else if @Tip = 3
        set @SqlText='select Kod,' +
                            'SUM(CASE Tip WHEN 1 THEN IsNull(A3Bak,0) ELSE 0 END) A00Bak,' +  --actual prev
                            'SUM(CASE Tip WHEN 0 THEN IsNull(A1Bak,0) ELSE 0 END) A10Bak,' +  --budget first
                            'SUM(CASE Tip WHEN 0 THEN IsNull(A2Bak,0) ELSE 0 END) A20Bak,' +  --budget second
                            'SUM(CASE Tip WHEN 1 THEN IsNull(A1Bak,0) ELSE 0 END) A11Bak,' +  --actual first
                            'SUM(CASE Tip WHEN 1 THEN IsNull(A2Bak,0) ELSE 0 END) A21Bak,' +  --actual second
                            'SUM(CASE Tip WHEN 0 THEN IsNull(A3Bak,0) ELSE 0 END) A01Bak ' +  --budget yearly
                      'from (' + @SqlText + ') X' +
                      ' group by Kod'

      PRINT @SqlText
      exec sp_executesql @SqlText

6 个答案:

答案 0 :(得分:2)

你应该尝试使用CLR存储过程重写它

答案 1 :(得分:1)

重写将是最好的解决方案。但是,要尝试调试它,请使用SQL Profiler(SQL Server附带的SQL Server性能工具之一)将存储过程跟踪放在数据库上,并捕获执行此存储过程的确切命令。这将允许您捕获传入的确切参数值,并允许您在SQL Management Studio窗口中重复运行它。

然后,您可以修改存储过程以打印出您希望在整个存储过程中的各个点检查的各种值,以确定在任何给定点发生的事情。

或者,您可以使用visual studio启用SQL调试并实际执行存储过程。

答案 2 :(得分:0)

1)在过程的顶部,添加一个INSERT语句,将输入参数记录到表中,如下所示:

INSERT INTO YourLog (TextValue) VALUES ('EXEC BUTCEREP @SirketKod='''+COALESCE(@SirketKod,'NULL')+''', @IlkTarih='''+COALESCE(@IlkTarih,'NULL')+''', ...)

2)从应用程序中多次运行此过程以捕获输入参数,包括几个良好运行以及已知问题。

3)在代码中添加许多PRINT语句。甚至将长分配分解为更小但更多的分配(其中不同的部分连接起来,“+”)并在它们之间放置打印:

...
PRINT @SqlMuh
...
PRINT @SqlMuh
...
PRINT @SqlGid
...

4)从日志中获取'EXEC ...'字符串,并从SSMS运行命令,查看打印输出和代码,并确定发生了什么。

答案 3 :(得分:0)

因为你问过如何调试这个:

从这开始改变:

  ALTER  PROC [dbo].[BUTCEREP] @SirketKod varchar(10), @IlkTarih varchar(10), @SonTarih varchar(10), @Tip int, @Tur int, @MasrafMrk varchar(100), @DovizKod varchar(5), @MaliTKod varchar(10)
    -- Tip 0-TarihAraligi; 1-2AylikButce; 2-YTDButce; 3-YTDCompPrev
    -- Tur 0-Muhasebe 1-Gider 2-Butce 3-ButceMuhasebe 4-ButceGider
    AS
      declare
        @SqlText nvarchar(4000),
        @SqlBud varchar(4000),
        @SqlMuh varchar(4000),
        @SqlGid varchar(4000),
        @xIlkT datetime,
        @xSonT datetime,
        @ThisMonth varchar(10),
        @NextMonth varchar(10),
        @ThisYear varchar(10),
        @PrevYear varchar(10)

进入这个:

  declare @SqlText as nvarchar(4000)
  declare @SqlBud as varchar(4000)
  declare @SqlMuh as varchar(4000)
  declare @SqlGid as varchar(4000)
  declare @xIlkT as datetime
  declare @xSonT as datetime
  declare @ThisMonth as varchar(10)
  declare @NextMonth as varchar(10)
  declare @ThisYear as varchar(10)
  declare @PrevYear as varchar(10)

  set @ThisYear = 'your test value'
  set @NextMonth = 'your test value'
  set @ThisMonth = 'your test value'
  set @SqlText = 'your test value'
  set @SqlBud = 'your test value'
  set @SqlMuh = 'your test value'
  set @SqlGid = 'your test value'
  set @xIlkT = 'your test value'
  set @xSonT = 'your test value'
  set @PrevYear = 'your test value'

随意调试。在以下部分之间附加选择语句,如:

select @SqlMuh 

了解他们在特定地点的价值观。

如果您对所做的更改感到满意,请返回并更改SP。每次你想要检查一些东西时,这将减少ALTERING-EXECUTING的重复任务。

答案 4 :(得分:0)

我去年有一个这样的项目,我发现最好的办法是创建一个带有标识字段和varchar字段的表,并在EXEC之前将@SqlText变量写入它。这样,当您测试并查看结果时,您可以获得已执行的最新SQL。

长期来看,我同意大多数人的意见,你应该重新写一下(虽然这可能不是一个好的短期解决方案,除非这是唯一一个这样的SP)。

答案 5 :(得分:0)

这是动态SQL,您确实需要查看以前所述的配置文件,但使用底部的PRINT命令将显示实际发送的内容,以便您可以进行调试。如果您不是SQL程序员,那么通过查看此代码,您将不会尝试调试它。您需要将其打印出来,然后将Printed SQL复制到新窗口并调试该代码。

要明确我说的是程序的倒数第二行     PRINT @SqlText

这里的其他提示很好,此时你只需要提供不同的值(我想从应用层或使用提到的声明语句)并找到所有的情况。我发现在调试业务逻辑以将流程图或不同参数的图表作为视觉助手时,它会很有用。通过注释联接的行来理解关键关系,从而完成该过程。我会说最困难的部分是所有的日期转换 - 还有很多重复的代码应放在函数中以提高可读性。

使用分隔符(&#39;〜&#39;)稍后可能会以某种方式解析数据,因此我也可能会查看应用程序的其他层,可能是bug甚至不存在这里是在加载时在页面级别进行的更改。

在您完成工作时,请务必发表评论,以便有人在您之后不必从头开始!