0

次のようなストアド プロシージャがあります。

ALTER PROCEDURE [dbo].[Performance] 

     @startdate NVARCHAR(100), 
     @enddate NVARCHAR(100)

AS
BEGIN
     SET NOCOUNT ON;

     SELECT
          l.LocName
         ,v.Vtype
         ,SUM(DATEDIFF(MI, t.Paydate, t.DelDate)) AS TotalDiff
         ,CONVERT(DECIMAL(10, 1), AVG(CONVERT(NUMERIC(18, 2), DATEDIFF(MI, t.Paydate, t.DelDate)))) AS Average
     FROM Transaction_tbl t
     LEFT JOIN VType_tbl v ON t.vtid = v.vtid
     LEFT JOIN Location_tbl l ON t.Locid = l.Locid
     WHERE t.Locid IN
          (
               SELECT t1.Locid
               FROM Transaction_tbl t1
          )
          AND dtime BETWEEN '' + @startdate + '' AND '' + @enddate + ''
          AND status >= 5
     GROUP BY
          v.Vtype
         ,l.LocName
         ,l.Locid
     ORDER BY l.Locid

END

LocName             Vtype       TotalDiff   Average

Fashion Avenue     VIP           84          2.1
Fashion Avenue     Normal        14007       200.1
Address Hotel    Normal          33169        1745.7

この出力では、平均は分単位で表示されます。平均を HH:MM(時間、分) で表示したいので、時間と分で平均を取得するための別のストアド プロシージャとして書きました。そのストアド プロシージャは次のようになります。

ALTER PROCEDURE [dbo].[test] @locid INT
AS
BEGIN
     DECLARE
          @Mns DECIMAL
         ,@dec DECIMAL

     SELECT @dec = AVG(CONVERT(NUMERIC(18, 2), DATEDIFF(MI, t.Paydate, t.DelDate)))
     FROM Transaction_tbl t
     WHERE Locid = @locid;

     SELECT @Mns = @dec % 60;

     SELECT Avearge = 
            CONVERT(VARCHAR(10), (CONVERT(DECIMAL(10), @dec / 60))) + ':'
          + CONVERT(VARCHAR, @Mns)

END

ここで出てきます このように: 平均 29:6. 最初のストアド プロシージャで平均値を取得する代わりに、最初のストアド プロシージャでこの平均値を表示したいので、最初のストアド プロシージャ内にこのストアド プロシージャを書き込む方法、またはこの平均値を取得する他の方法はありますか最初のストアド プロシージャで

4

2 に答える 2

0

このコード行を見ると:

CONVERT(DECIMAL(10, 1), AVG(CONVERT(NUMERIC(18, 2), DATEDIFF(MI, t.Paydate, t.DelDate)))) AS Average

...別の関数呼び出しでラップすると、さらに醜く読みにくくなると思いませんか?

これは少し違った書き方をすることができます。どれどれ。

ステップ 1 - 別の式でタイムスパン計算を抽出する

SELECT
  ...,
  CONVERT(DECIMAL(10, 1), AVG(CONVERT(NUMERIC(18, 2), datecalc.val))) AS Average
FROM 
  Transaction_tbl t
  CROSS APPLY(
    SELECT val = DATEDIFF(MI, t.Paydate, t.DelDate)
  ) datecalc
  ...

このようにして、必要に応じて残りのクエリで議事録をいつでも利用できます。

ステップ 2 - AVG() の CONVERT を削除します

次のように変換すると読みやすくなります。

SELECT
  ...,
  CONVERT(DECIMAL(10, 1), AVG(datecalc.val * 1.0)) AS Average
FROM 
  Transaction_tbl t
  CROSS APPLY(
    SELECT val = DATEDIFF(MI, t.Paydate, t.DelDate)
  ) datecalc
  ...

明らかに、AVG() は正確に計算する必要があり、このようにして精度を失うことはありません。

ステップ 3 - 手順/機能を忘れる

コード内の他の場所で HH:MM への変換が必要ない場合は、スキーマを汚染しないように関数を作成しないでください。SQL Server 2008 以降を使用している場合は、TIME 型が役立ちます。

分を HH:MM にするためのアルゴリズム:

  • を使用して、DATETIME ('1900-01-01 HH:MI:SS') までの時間を取得しますDATEADD(MI, Average, 0)
  • CAST(DATEADD(MI, Average, 0) as TIME) を使用して、この醜いものから TIME ('HH:MI:SS') を取得します
  • get LEFT(CAST(DATEADD(MI, Average, 0) as TIME), 5)

私が何を意味するかを示すために、コードは次のとおりです。

;WITH orig AS (
    SELECT id = 1, dt = CAST('2013-07-23 09:01' as datetime), dt2 = CAST('2013-07-23 09:00' as datetime)
    UNION ALL SELECT id = 1, '2013-07-24 01:00', '2013-07-23 12:00'
    UNION ALL SELECT id = 2, '2013-07-23 10:15', '2013-07-23 10:07'
    UNION ALL SELECT id = 2, '2013-07-23 09:10', '2013-07-23 08:00') -- STEP#0: data sample
,avgs AS (
    SELECT
      id,
      val = avg(val1 * 1.0) -- STEP#2: calculating average timespan in minutes
    FROM orig
    CROSS APPLY(
      SELECT val1 = DATEDIFF(MI, dt2, dt) -- STEP#1: calculating timespan in minutes
    ) spancalc
    GROUP BY id)
SELECT
  id,
  str = LEFT(val2, 5) -- STEP#4: getting 'HH:MI' string output
FROM 
  avgs
  CROSS APPLY(
    SELECT 
      val2 = CAST(DATEADD(MI, val, 0) as TIME) -- STEP#3: getting average timespan to TIME format
  ) timecalc
于 2013-07-23T08:35:50.967 に答える