我目前有一个存储过程,可以将其导出到DataTable(dt
)。提供的数据显示每个客户平均每个月的价值。如果数据具有要显示的值,则数据必须显示其值。
这是我的存储过程(动态数据透视表)的SQL:
ALTER Procedure [dbo].[stpMonthlyAvg]
--Parameters
AS
Begin
Begin Tran T1;
Begin Try
DECLARE @Dates NVARCHAR(MAX);
SELECT @Dates = CONCAT(@Dates + ', ', QUOTENAME(BalMonth))
FROM vAvgMonBal
GROUP BY BalMonth
ORDER BY BalMonth;
DECLARE @DynSQL NVARCHAR(MAX),
@months NVARCHAR(255);
SET @months = 'CONCAT( CONVERT(nvarchar(15), YEAR(BalDate)) , IIF(LEN(MONTH(BalDate)) > 1, CONVERT(nvarchar(15), MONTH(BalDate)), ''0'' + CONVERT(nvarchar(15), MONTH(BalDate))))'
SET @DynSQL = 'SELECT *
FROM
(SELECT
a1.IDNbr,
a2.CustName, ' + @months + ' AS BalMonth,
AVG(a1.Balance) as Balance
FROM tblID a1
INNER JOIN tblCust a2 ON (a1.IDNbr = a2.IDNbr)
WHERE a2.CustType != ''Inactive'' AND a2.CustType IS NOT NULL AND a1.Balance != 0
GROUP BY
a1.IDNbr, a2.CustName, ' + @months +') as d1
PIVOT (
AVG(Balance)
FOR BalMonth IN (' + @Dates + ')
) piv';
EXECUTE sp_executesql @DynSQL
Commit Tran T1;
End Try
Begin Catch
RollBack Tran T1;
End Catch
End
这是我当前拥有的表格的示例-带有测试数据:
+-------------------------------------------------------+
| ID | CustName | 201501 | 201502 | 201503 | 201504 | ..|
+-------------------------------------------------------+
| 32 | CustOne | 100.00 | 200.00 | 400.00 | 700.00 | ..|
| 56 | CustTwo | 350.00 | 375.00 | 400.00 | 500.00 | ..|
| 89 | CustThree| 222.22 | 333.33 | 444.44 | 555.55 | ..|
| .. | ... | .. | .. | .. | .. | ..|
+-------------------------------------------------------+
我需要找到每个客户每个月与上个月之间的百分比差异,并将其添加到其自己的DataTable(fDt
)中。
这就是我需要的(行中的值是百分比):
+-------------------------------------------------------+
| ID | CustName | PerDiff02 | PerDiff03 | PerDiff04 | ..|
+-------------------------------------------------------+
| 32 | CustOne | 0 | 100 | 200 | ..|
| 56 | CustTwo | 93.33 | 93.75 | 80.00 | ..|
| 89 | CustThree| 66.66 | 75.00 | 80.00 | ..|
| .. | ... | .... | .... | .... | ..|
+-------------------------------------------------------+
我目前正在将数据添加到fDt
中,尽管它是按列而不是按行计算的(我认为)。
意味着我的数据输出如下:
+-------------------------------------------------------+
| ID | CustName | PerDiff02 | PerDiff03 | PerDiff04 | ..|
+-------------------------------------------------------+
| 32 | CustOne | 0 | 100 | 200 | ..|
| 56 | CustTwo | 0 | 100 | 200 | ..|
| 89 | CustThree| 0 | 100 | 200 | ..|
| .. | ... | .... | .... | .... | ..|
+-------------------------------------------------------+
为整个列分配一次计算的结果。
这是我正在使用的代码:
Uni.fileExport Export = new Uni.fileExport();
string conStr = "Data Source=" + ConfigurationManager.AppSettings["DataSource"] + "Initial Catalog=" + ConfigurationManager.AppSettings["InitialCatalog"] + "Integrated Security=True;";
var dt = new DataTable();
dt = Export.sqlToDTMonthlyAvg(conStr, stp);
var fDt = new DataTable();
int i;
int fieldCount = dt.Columns.Count;
int finalSize = (fieldCount) * 2;
string[] finalCol = new string[finalSize];
string[] colHeaders = new string[fieldCount];
for (i = 0; i < fieldCount; i++)
{
colHeaders[i] = dt.Columns[i].ToString();
}
fDt.Columns.Add(colHeaders[0]);
fDt.Columns.Add(colHeaders[1]);
for (i = 1; i < dt.Rows.Count; i++)
{
fDt.Rows.Add(dt.Rows[i][0], dt.Rows[i][1]);
}
/*
* This section is meant to try and get the percent difference from dt
* to fDt. Looking into doing this from the SQL data base rather than from the code
* in order to save processing at runTime. The main concern being the stored procedure
* taking longer than a couple minutes.
*/
// Gets the column headers for dataTable fDt
for (i = 2; i <= (dt.Columns.Count - 2); i++)
{
string colName = "PerDiff" + dt.Columns[i + 1];
fDt.Columns.Add(colName, typeof(decimal));
}
for (i = 2; i <= (dt.Columns.Count - 2); i++)
{
var month1 = dt.Columns[i];
var month2 = dt.Columns[i + 1];
fDt.Columns[i].Expression = $"({month1} / {month2}) * 100";
}
问题:如何获得dt
到fDt
列的百分比差异?我需要基于上个月的百分比。
(由于PerDiff02
之前没有可比较的事实,因此PerDiff从201501
开始。)
如果不清楚,请告诉我,我将尽力澄清!我对C#还是有点陌生,尤其是datatables
。
我尝试在SQL中尝试此操作,但是我仍然还是SQL的新手,因此认为可以通过C#轻松实现。一旦开始运行,便会考虑优化。
如果有任何不赞成票,请您解释为什么要不赞成票,以便我予以纠正!
答案 0 :(得分:1)
好吧,这是我2年前做的类似事情
在内部选择中,添加占位符的差异
SELECT
a1.IDNbr,
a2.CustName, ' + @months + ' AS BalMonth,
AVG(a1.Balance) as Balance,
0 as Diff1,0 as Diff2,0 as Diff3
在执行sp_executesql @DynSQL添加之前
DECLARE @DataProcess TABLE // Table variable to hold everything
(
NewTableID INT IDENTITY(1,1)
, Id INT
, CustName NVARCHAR(256)
, Month1 NVARCHAR(260)
, Month2 NVARCHAR(260)
, Month3 NVARCHAR(260)
, Month4 NVARCHAR(260)
,Diff1 INT
,Diff2 INT
,Diff3 INT
)
INSERT INTO @DataProcess EXECUTE sp_executesql @DynSQL // fill in the data
Now declare values and loop
DECLARE @Count INT, @Counter INT, @Id INT,@Month1 NVARCHAR(260),@Month1 NVARCHAR(260),@Month3 NVARCHAR(260),@Month4 NVARCHAR(260)
SELECT @Count = COUNT(*) FROM @DataProcess d
SET @Counter = 1
BEGIN
SELECT @Id = ID,(260),@Month1 = Month1,@Month2=Month1 ,@Month3=Month3 ,@Month4 =Month3 FROM @DataProcess m WHERE NewTableID = Counter
m.Diff1 =@Month2 - @Month1;
m.Diff2 =@Month3 - @Month2
m.Diff2 =@Month4 - @Month3
SET @Counter = @Counter + 1
END
这应该为您填满所有内容,并且不要使用sp
答案 1 :(得分:1)
每个请求都是我在存储过程中要做的全部事情
Begin Tran T1;
Begin Try
DECLARE @Dates NVARCHAR(MAX);
SELECT @Dates = CONCAT(@Dates + ', ', QUOTENAME(BalMonth))
FROM vAvgMonBal
GROUP BY BalMonth
ORDER BY BalMonth;
DECLARE @DynSQL NVARCHAR(MAX),
@months NVARCHAR(255);
SET @months = 'CONCAT( CONVERT(nvarchar(15), YEAR(BalDate)) , IIF(LEN(MONTH(BalDate)) > 1, CONVERT(nvarchar(15), MONTH(BalDate)), ''0'' + CONVERT(nvarchar(15), MONTH(BalDate))))'
SET @DynSQL = 'SELECT *
FROM
(SELECT
a1.IDNbr,
a2.CustName, ' + @months + ' AS BalMonth,
AVG(a1.Balance) as Balance,
0 as Diff1,0 as Diff2,0 as Diff3
FROM tblID a1
INNER JOIN tblCust a2 ON (a1.IDNbr = a2.IDNbr)
WHERE a2.CustType != ''Inactive'' AND a2.CustType IS NOT NULL AND a1.Balance != 0
GROUP BY
a1.IDNbr, a2.CustName, ' + @month +') as d1
PIVOT (
AVG(Balance)
FOR BalMonth IN (' + @Dates + ')
) piv';
DECLARE @DataProcess TABLE // Table variable to hold everything
(
NewTableID INT IDENTITY(1,1)
, Id INT
, CustName NVARCHAR(256)
, Month1 NVARCHAR(260)
, Month2 NVARCHAR(260)
, Month3 NVARCHAR(260)
, Month4 NVARCHAR(260)
,Diff1 INT
,Diff2 INT
,Diff3 INT
)
INSERT INTO @DataProcess EXECUTE sp_executesql @DynSQL // fill in the data
Now declare values and loop
DECLARE @Count INT, @Counter INT, @Id INT,@Month1 NVARCHAR(260),@Month1 NVARCHAR(260),@Month3 NVARCHAR(260),@Month4 NVARCHAR(260)
SELECT @Count = COUNT(*) FROM @DataProcess d
SET @Counter = 1
BEGIN
SELECT @Id = ID,(260),@Month1 = Month1,@Month2=Month1 ,@Month3=Month3 ,@Month4 =Month3 FROM @DataProcess m WHERE NewTableID = Counter
m.Diff1 =@Month2 - @Month1;
m.Diff2 =@Month3 - @Month2
m.Diff2 =@Month4 - @Month3
SET @Counter = @Counter + 1
END
select * from @DataProcess // this reads all the data in the Temp Table and this is what fills your data table in .NEt
Commit Tran T1;
End Try
Begin Catch
RollBack Tran T1;
End Catch
End