在SQL中的select语句中循环以基于参数进行计算

时间:2014-10-07 23:17:09

标签: sql loops

我需要参数化我的查询,以便对于每个期间(1-12),它产生期间的余额以及每个期间直到所选期间(YTD)的所有余额的总和。我的表看起来像这样(Am字段是该年度每个时期的金额)

COMPANY|ACCOUNT|SUB_ACCOUNT|FISCAL_YEAR|DB_AMOUNT_01|DB_AMOUNT_02|DB_AMOUNT_03|DB_AMOUNT_04|DB_AMOUNT_05|DB_AMOUNT_06|DB_AMOUNT_07|DB_AMOUNT_08|DB_AMOUNT_09|DB_AMOUNT_10|DB_AMOUNT_11|DB_AMOUNT_12|
1|10000|1001|2014|176511106.65|200917064.20|243331258.93|189877339.46|208405555.85|316912751.86|413405072.40|0.00|0.00|0.00|0.00|0.00
1|10020|1001|2014|7162276.27|10429413.89|12552480.96|11144442.08|8627365.16|13453884.90|12607065.52|0.00|0.00|0.00|0.00|0.00
1|10040|1001|2014|8942858.81|11088886.79|11827043.98|12549230.43|12052482.22|12511277.79|9963556.61|0.00|0.00|0.00|0.00|0.00

我需要做的是在用户选择期间时显示每个期间的数据,但是所有前几个月都加起来用于期初余额。因此,如果用户选择期间3,它应该看起来像

COMPANY|ACCOUNT|SUB_ACCOUNT|FISCAL_YEAR|DB_AMOUNT_03|YTD_AMOUNT
1|10000|1001|2014|243331258.93|176511106.65+200917064.20+243331258.93

但对于第4期,它将是

COMPANY|ACCOUNT|SUB_ACCOUNT|FISCAL_YEAR|DB_AMOUNT_04|YTD_AMOUNT
1|10000|1001|2014|189877339.46|176511106.65+200917064.20+243331258.93+189877339.46

等等

但是,当用户选择句点时,如何在YTD_AMOUNT字段中添加? 我可以编写12个不同的语句,并为每个句点做一个IF / THEN,但我宁愿使用一些可以做我需要做的逻辑。

4 个答案:

答案 0 :(得分:1)

如果我正确理解你的问题,听起来你正试图unpivot你的桌子。答案可能因您的RDBMS而异,但这是一个通用的解决方案,也可以使用。

首先需要创建一个数字/期间表。一种选择是使用带有UNION ALL的子查询来实现此目的。然后,您可以使用CASE的聚合来获得所需的结果。

以下是使用6个句点的精简版本(添加12个句点的附加语句):

select company, account, sub_account, fiscal_year, 
  max(
    case 
      when amt = 1 then db_amount_01
      when amt = 2 then db_amount_02
      when amt = 3 then db_amount_03
      when amt = 4 then db_amount_04
      when amt = 5 then db_amount_05
      when amt = 6 then db_amount_06
     end
    ) amt, 
  sum(
    case 
      when amt = 1 then db_amount_01
      when amt = 2 then db_amount_01+db_amount_02
      when amt = 3 then db_amount_01+db_amount_02+db_amount_03
      when amt = 4 then db_amount_01+db_amount_02+db_amount_03+db_amount_04
      when amt = 5 then db_amount_01+db_amount_02+db_amount_03+db_amount_04+db_amount_05
      when amt = 6 then db_amount_01+db_amount_02+db_amount_03+db_amount_04+db_amount_05+db_amount_06
     end
    ) overallamt
from YourTable t , 
  (select 1 amt union all select 2 union all select 3 union all 
   select 4 union all select 5 union all select 6) t2
group by company, account, sub_account, fiscal_year, amt

答案 1 :(得分:1)

对于一个非常大的GL表,其中交叉连接到12期日历表可能性能过高,另一种解决方案是这样的:

declare @Period INT
set @Period = 4

select company, account, sub_account, fiscal_year, 
case @Period
when 1 then db_amount_01
when 2 then db_amount_02
when 3 then db_amount_03
when 4 then db_amount_04
....
end amt,
case @Period
when 1 then db_amount_01
when 2 then db_amount_01 + db_amount_02
when 3 then db_amount_01 + db_amount_02 + db_amount_03
when 4 then db_amount_01 + db_amount_02 + db_amount_03 + db_amount_04
....
end balance
from YourTable t

这些表通常还有一个期间期初余额栏 - 如有必要,您必须包括该栏目。

这和@sgeddes答案之间的差异是每个帐户每年返回一行(即只是第4期),而@sgeddes返回多行直到指定的时间段(即1-4期)

你的问题不是100%明确你想要的。随便挑选。

答案 2 :(得分:0)

如果我理解你的问题,我认为你可以使用动态的SQL。我写了以下针对Sql Server的目标。 @periodNum是您要查找的期间号的参数;在这个例子中,我要求前6个时期。

DECLARE @periodNum INT;
SET @periodNum = 6;

DECLARE @firstPeriodColNum INT;
DECLARE @periodCol NVARCHAR(50), @columnNm NVARCHAR(50), @prevColumnNm NVARCHAR(50);
DECLARE @queryTxt NVARCHAR(1000);
DECLARE @Columns TABLE (column_name NVARCHAR(50));

--Retrieve ordinal position for first period column
SELECT @firstPeriodColNum = ORDINAL_POSITION
                    FROM INFORMATION_SCHEMA.COLUMNS
                    WHERE COLUMN_NAME = 'DB_AMOUNT_01';

--Retrieve column name for period of interest
SELECT @periodCol = COLUMN_NAME
                    FROM INFORMATION_SCHEMA.COLUMNS
                    WHERE TABLE_NAME = 'YourTableName' --just table name, no schema
                        AND ORDINAL_POSITION = (@periodNum + @firstPeriodColNum - 1);

--Retrieve column names for all periods up to and including the period of interest
INSERT INTO @Columns
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'YourTableName'
    AND ORDINAL_POSITION >= @firstPeriodColNum 
       AND ORDINAL_POSITION < (@periodNum + @firstPeriodColNum);

--declare cursor over table variable of period-column names 
--run through cursor and dynamically add the column names to the query string @queryTxt
DECLARE COL_CURSOR CURSOR FOR
SELECT * FROM @Columns;
OPEN COL_CURSOR;

FETCH NEXT FROM COL_CURSOR INTO @columnNm;
SET @queryTxt = 'SELECT COMPANY, ACCOUNT, SUB_ACCOUNT, FISCAL_YEAR, ' 
                + @periodCol + ', (' + @columnNm;
SET @prevColumnNm = @columnNm;
WHILE @@FETCH_STATUS = 0 
BEGIN 
   FETCH NEXT FROM COL_CURSOR INTO @columnNm;
   IF @prevColumnNm <> @columnNm
   BEGIN
      SET @queryTxt = @queryTxt + ' + ' + @columnNm;
      SET @prevColumnNm = @columnNm;
   END
   ELSE CONTINUE
END
CLOSE COL_CURSOR;
DEALLOCATE COL_CURSOR;

SET @queryTxt = @queryTxt + ') AS YTD FROM YourTableName';

EXEC (@queryTxt); --Executes the query

答案 3 :(得分:0)

所以我使用了很多你的输入(谢谢!!)并最终以这种方式做到了:

  SELECT  distinct 
    d.ACCOUNT_DESC,
    a.COMPANY, 
    a.ACCOUNT, 
    a.SUB_ACCOUNT, 
    a.FISCAL_YEAR,
    CASE @period
    WHEN 1 THEN a.DB_AMOUNT_01+a.CR_AMOUNT_01
    WHEN 2 THEN a.DB_AMOUNT_02+a.CR_AMOUNT_02
    WHEN 3 THEN a.DB_AMOUNT_03+a.CR_AMOUNT_03
    WHEN 4 THEN a.DB_AMOUNT_04+a.CR_AMOUNT_04
    WHEN 5 THEN a.DB_AMOUNT_05+a.CR_AMOUNT_05
    WHEN 6 THEN a.DB_AMOUNT_06+a.CR_AMOUNT_06
    WHEN 7 THEN a.DB_AMOUNT_07+a.CR_AMOUNT_07
    WHEN 8 THEN a.DB_AMOUNT_08+a.CR_AMOUNT_08
    WHEN 9 THEN a.DB_AMOUNT_09+a.CR_AMOUNT_09
    WHEN 10 THEN a.DB_AMOUNT_10+a.CR_AMOUNT_10
    WHEN 11 THEN a.DB_AMOUNT_11+a.CR_AMOUNT_11
    WHEN 12 THEN a.DB_AMOUNT_12+a.CR_AMOUNT_12
    WHEN 13 THEN a.DB_AMOUNT_13+a.CR_AMOUNT_13

    END CHANGE ,
    CASE @period
    WHEN 2 THEN a.DB_AMOUNT_01+a.CR_AMOUNT_01 
    WHEN 3 THEN a.DB_AMOUNT_01+a.CR_AMOUNT_01+a.DB_AMOUNT_02+a.CR_AMOUNT_02
    WHEN 4 THEN a.DB_AMOUNT_01+a.CR_AMOUNT_01+a.DB_AMOUNT_02+a.CR_AMOUNT_02+a.DB_AMOUNT_03+a.CR_AMOUNT_03
    WHEN 5 THEN a.DB_AMOUNT_01+a.CR_AMOUNT_01+a.DB_AMOUNT_02+a.CR_AMOUNT_02+a.DB_AMOUNT_03+a.CR_AMOUNT_03+a.DB_AMOUNT_04+a.CR_AMOUNT_04
    WHEN 6 THEN a.DB_AMOUNT_01+a.CR_AMOUNT_01+a.DB_AMOUNT_02+a.CR_AMOUNT_02+a.DB_AMOUNT_03+a.CR_AMOUNT_03+a.DB_AMOUNT_04+a.CR_AMOUNT_04+a.DB_AMOUNT_05+a.CR_AMOUNT_05
    WHEN 7 THEN a.DB_AMOUNT_01+a.CR_AMOUNT_01+a.DB_AMOUNT_02+a.CR_AMOUNT_02+a.DB_AMOUNT_03+a.CR_AMOUNT_03+a.DB_AMOUNT_04+a.CR_AMOUNT_04+a.DB_AMOUNT_05+a.CR_AMOUNT_05+a.DB_AMOUNT_06+a.CR_AMOUNT_06
    WHEN 8 THEN a.DB_AMOUNT_01+a.CR_AMOUNT_01+a.DB_AMOUNT_02+a.CR_AMOUNT_02+a.DB_AMOUNT_03+a.CR_AMOUNT_03+a.DB_AMOUNT_04+a.CR_AMOUNT_04+a.DB_AMOUNT_05+a.CR_AMOUNT_05+a.DB_AMOUNT_06+a.CR_AMOUNT_06+a.DB_AMOUNT_07+a.CR_AMOUNT_07
    WHEN 9 THEN a.DB_AMOUNT_01+a.CR_AMOUNT_01+a.DB_AMOUNT_02+a.CR_AMOUNT_02+a.DB_AMOUNT_03+a.CR_AMOUNT_03+a.DB_AMOUNT_04+a.CR_AMOUNT_04+a.DB_AMOUNT_05+a.CR_AMOUNT_05+a.DB_AMOUNT_06+a.CR_AMOUNT_06+a.DB_AMOUNT_07+a.CR_AMOUNT_07+a.DB_AMOUNT_08+a.CR_AMOUNT_08
    WHEN 10 THEN a.DB_AMOUNT_01+a.CR_AMOUNT_01+a.DB_AMOUNT_02+a.CR_AMOUNT_02+a.DB_AMOUNT_03+a.CR_AMOUNT_03+a.DB_AMOUNT_04+a.CR_AMOUNT_04+a.DB_AMOUNT_05+a.CR_AMOUNT_05+a.DB_AMOUNT_06+a.CR_AMOUNT_06+a.DB_AMOUNT_07+a.CR_AMOUNT_07+a.DB_AMOUNT_08+a.CR_AMOUNT_08+a.DB_AMOUNT_09+a.CR_AMOUNT_09
    WHEN 11 THEN a.DB_AMOUNT_01+a.CR_AMOUNT_01+a.DB_AMOUNT_02+a.CR_AMOUNT_02+a.DB_AMOUNT_03+a.CR_AMOUNT_03+a.DB_AMOUNT_04+a.CR_AMOUNT_04+a.DB_AMOUNT_05+a.CR_AMOUNT_05+a.DB_AMOUNT_06+a.CR_AMOUNT_06+a.DB_AMOUNT_07+a.CR_AMOUNT_07+a.DB_AMOUNT_08+a.CR_AMOUNT_08+a.DB_AMOUNT_09+a.CR_AMOUNT_09+a.DB_AMOUNT_10+a.CR_AMOUNT_10
    WHEN 12 THEN a.DB_AMOUNT_01+a.CR_AMOUNT_01+a.DB_AMOUNT_02+a.CR_AMOUNT_02+a.DB_AMOUNT_03+a.CR_AMOUNT_03+a.DB_AMOUNT_04+a.CR_AMOUNT_04+a.DB_AMOUNT_05+a.CR_AMOUNT_05+a.DB_AMOUNT_06+a.CR_AMOUNT_06+a.DB_AMOUNT_07+a.CR_AMOUNT_07+a.DB_AMOUNT_08+a.CR_AMOUNT_08+a.DB_AMOUNT_09+a.CR_AMOUNT_09+a.DB_AMOUNT_10+a.CR_AMOUNT_10+a.DB_AMOUNT_11+a.CR_AMOUNT_11
    WHEN 13 THEN a.DB_AMOUNT_01+a.CR_AMOUNT_01+a.DB_AMOUNT_02+a.CR_AMOUNT_02+a.DB_AMOUNT_03+a.CR_AMOUNT_03+a.DB_AMOUNT_04+a.CR_AMOUNT_04+a.DB_AMOUNT_05+a.CR_AMOUNT_05+a.DB_AMOUNT_06+a.CR_AMOUNT_06+a.DB_AMOUNT_07+a.CR_AMOUNT_07+a.DB_AMOUNT_08+a.CR_AMOUNT_08+a.DB_AMOUNT_09+a.CR_AMOUNT_09+a.DB_AMOUNT_10+a.CR_AMOUNT_10+a.DB_AMOUNT_11+a.CR_AMOUNT_11+a.DB_AMOUNT_12+a.CR_AMOUNT_12
    END +a.DB_BEG_BAL + a.CR_BEG_BAL LAST_MONTH,
    a.DB_BEG_BAL + a.CR_BEG_BAL AS BEGINBAL,

    CASE @period
    WHEN 1 THEN z.DB_AMOUNT_01+z.CR_AMOUNT_01 
    WHEN 2 THEN z.DB_AMOUNT_01+z.CR_AMOUNT_01+z.DB_AMOUNT_02+z.CR_AMOUNT_02
    WHEN 3 THEN z.DB_AMOUNT_01+z.CR_AMOUNT_01+z.DB_AMOUNT_02+z.CR_AMOUNT_02+z.DB_AMOUNT_03+z.CR_AMOUNT_03
    WHEN 4 THEN z.DB_AMOUNT_01+z.CR_AMOUNT_01+z.DB_AMOUNT_02+z.CR_AMOUNT_02+z.DB_AMOUNT_03+z.CR_AMOUNT_03+z.DB_AMOUNT_04+z.CR_AMOUNT_04
    WHEN 5 THEN z.DB_AMOUNT_01+z.CR_AMOUNT_01+z.DB_AMOUNT_02+z.CR_AMOUNT_02+z.DB_AMOUNT_03+z.CR_AMOUNT_03+z.DB_AMOUNT_04+z.CR_AMOUNT_04+z.DB_AMOUNT_05+z.CR_AMOUNT_05
    WHEN 6 THEN z.DB_AMOUNT_01+z.CR_AMOUNT_01+z.DB_AMOUNT_02+z.CR_AMOUNT_02+z.DB_AMOUNT_03+z.CR_AMOUNT_03+z.DB_AMOUNT_04+z.CR_AMOUNT_04+z.DB_AMOUNT_05+z.CR_AMOUNT_05+z.DB_AMOUNT_06+z.CR_AMOUNT_06
    WHEN 7 THEN z.DB_AMOUNT_01+z.CR_AMOUNT_01+z.DB_AMOUNT_02+z.CR_AMOUNT_02+z.DB_AMOUNT_03+z.CR_AMOUNT_03+z.DB_AMOUNT_04+z.CR_AMOUNT_04+z.DB_AMOUNT_05+z.CR_AMOUNT_05+z.DB_AMOUNT_06+z.CR_AMOUNT_06+z.DB_AMOUNT_07+z.CR_AMOUNT_07
    WHEN 8 THEN z.DB_AMOUNT_01+z.CR_AMOUNT_01+z.DB_AMOUNT_02+z.CR_AMOUNT_02+z.DB_AMOUNT_03+z.CR_AMOUNT_03+z.DB_AMOUNT_04+z.CR_AMOUNT_04+z.DB_AMOUNT_05+z.CR_AMOUNT_05+z.DB_AMOUNT_06+z.CR_AMOUNT_06+z.DB_AMOUNT_07+z.CR_AMOUNT_07+z.DB_AMOUNT_08+z.CR_AMOUNT_08
    WHEN 9 THEN z.DB_AMOUNT_01+z.CR_AMOUNT_01+z.DB_AMOUNT_02+z.CR_AMOUNT_02+z.DB_AMOUNT_03+z.CR_AMOUNT_03+z.DB_AMOUNT_04+z.CR_AMOUNT_04+z.DB_AMOUNT_05+z.CR_AMOUNT_05+z.DB_AMOUNT_06+z.CR_AMOUNT_06+z.DB_AMOUNT_07+z.CR_AMOUNT_07+z.DB_AMOUNT_08+z.CR_AMOUNT_08+z.DB_AMOUNT_09+z.CR_AMOUNT_09
    WHEN 10 THEN z.DB_AMOUNT_01+z.CR_AMOUNT_01+z.DB_AMOUNT_02+z.CR_AMOUNT_02+z.DB_AMOUNT_03+z.CR_AMOUNT_03+z.DB_AMOUNT_04+z.CR_AMOUNT_04+z.DB_AMOUNT_05+z.CR_AMOUNT_05+z.DB_AMOUNT_06+z.CR_AMOUNT_06+z.DB_AMOUNT_07+z.CR_AMOUNT_07+z.DB_AMOUNT_08+z.CR_AMOUNT_08+z.DB_AMOUNT_09+z.CR_AMOUNT_09+z.DB_AMOUNT_10+z.CR_AMOUNT_10
    WHEN 11 THEN z.DB_AMOUNT_01+z.CR_AMOUNT_01+z.DB_AMOUNT_02+z.CR_AMOUNT_02+z.DB_AMOUNT_03+z.CR_AMOUNT_03+z.DB_AMOUNT_04+z.CR_AMOUNT_04+z.DB_AMOUNT_05+z.CR_AMOUNT_05+z.DB_AMOUNT_06+z.CR_AMOUNT_06+z.DB_AMOUNT_07+z.CR_AMOUNT_07+z.DB_AMOUNT_08+z.CR_AMOUNT_08+z.DB_AMOUNT_09+z.CR_AMOUNT_09+z.DB_AMOUNT_10+z.CR_AMOUNT_10+z.DB_AMOUNT_11+z.CR_AMOUNT_11
    WHEN 12 THEN z.DB_AMOUNT_01+z.CR_AMOUNT_01+z.DB_AMOUNT_02+z.CR_AMOUNT_02+z.DB_AMOUNT_03+z.CR_AMOUNT_03+z.DB_AMOUNT_04+z.CR_AMOUNT_04+z.DB_AMOUNT_05+z.CR_AMOUNT_05+z.DB_AMOUNT_06+z.CR_AMOUNT_06+z.DB_AMOUNT_07+z.CR_AMOUNT_07+z.DB_AMOUNT_08+z.CR_AMOUNT_08+z.DB_AMOUNT_09+z.CR_AMOUNT_09+z.DB_AMOUNT_10+z.CR_AMOUNT_10+z.DB_AMOUNT_11+z.CR_AMOUNT_11+z.DB_AMOUNT_12+z.CR_AMOUNT_12
    WHEN 13 THEN z.DB_AMOUNT_01+z.CR_AMOUNT_01+z.DB_AMOUNT_02+z.CR_AMOUNT_02+z.DB_AMOUNT_03+z.CR_AMOUNT_03+z.DB_AMOUNT_04+z.CR_AMOUNT_04+z.DB_AMOUNT_05+z.CR_AMOUNT_05+z.DB_AMOUNT_06+z.CR_AMOUNT_06+z.DB_AMOUNT_07+z.CR_AMOUNT_07+z.DB_AMOUNT_08+z.CR_AMOUNT_08+z.DB_AMOUNT_09+z.CR_AMOUNT_09+z.DB_AMOUNT_10+z.CR_AMOUNT_10+z.DB_AMOUNT_11+z.CR_AMOUNT_11+z.DB_AMOUNT_12+z.CR_AMOUNT_12+z.DB_AMOUNT_13+z.CR_AMOUNT_13
    END PYP
    from GLCONSOL a , GLCONSOL z, GLCHARTDTL d, GLMASTER m
    where ...