Sql server 使用动态SQL创建报表
我有这样一个表格示例:Sql server 使用动态SQL创建报表,sql-server,function,stored-procedures,dynamic-sql,Sql Server,Function,Stored Procedures,Dynamic Sql,我有这样一个表格示例: State Project Build Type ACTUAL0 ACTUAL1 ACTUAL2 ------- ------- ----------- ----------- ----------- ---------- Ohio 154214 Residential 1/5/2013 2/25/2013 7/12/12 Utah 214356 Commercial 7/08/13 6/9/13
State Project Build Type ACTUAL0 ACTUAL1 ACTUAL2
------- ------- ----------- ----------- ----------- ----------
Ohio 154214 Residential 1/5/2013 2/25/2013 7/12/12
Utah 214356 Commercial 7/08/13 6/9/13 7/1/12
我正在尝试创建一个报告,该报告采用以单词actual开头的列标题,并获得少于特定日期的日期数。我有一个临时表,我创建的列标题以单词actual开头。这只是一个例子,实际名称有250多列。因此,该表如下所示:
MilestoneNmbr
-------------
ACTUAL1
ACTUAL2
ACTUAL3
MilestoneNmbr CountofDate
--------------- ------------
ACTUAL1 200
ACTUAL2 344
ACTUAL3 400
现在我认为可行的方法是将行作为列标题的变量,并将日期传递到函数中。下面是我创建的一个函数:
CREATE FUNCTION [dbo].[GetMSActualCount]
(
@ACTUAL nvarchar(16),
@DATE nvarchar(16)
)
RETURNS int
AS
BEGIN
DECLARE @ACTUALRETURN int
DECLARE @SQL nVarchar(255) =
'SELECT COUNT(' + @ACTUAL + ') AS Expr1
FROM [CASPR_MILESTONES_000-036]
WHERE '+ @ACTUAL +' > ' + @DATE
exec sp_executesql @SQL, N''
SET @ACTUALRETURN = @SQL
-- Return the result of the function
RETURN @ACTUALRETURN
END
如果我运行以下查询:
DECLARE @DATE varchar(20)
SET @DATE = '''1/1/2013'''
SELECT MilestoneNmbr, dbo.getMSActualCount(milestonenmbr,@Date) from #List_CASPR_Milestones
所以我的错误是我不能在函数中使用动态SQL。既然如此,我该怎么办?我在这里简单的提问,我想会变成几百行。有没有其他简单的方法可以做到这一点
编辑:
我想要的结果是这样的:
MilestoneNmbr
-------------
ACTUAL1
ACTUAL2
ACTUAL3
MilestoneNmbr CountofDate
--------------- ------------
ACTUAL1 200
ACTUAL2 344
ACTUAL3 400
您是对的,您不能在函数中使用动态SQL。有两个答案: 首先,有250列的表加上一个数字是一场噩梦。您不能使用SQL能够很好地帮助您的任何内置功能。你应该有两张桌子。首先是一个projects表,该表的ID列加上State、Project和BuildType列。然后是ProjectDates表,其中ProjectID列引用第一个表,然后是ActualDate列。从这方面报告应该很容易
考虑到您可能无法修复该结构,请尝试编写一个存储过程。它可以使用动态SQL。更好的情况是,您的存储过程可以创建如上所述的临时表,然后使用它们进行统计。您是对的,您不能在函数中使用动态SQL。有两个答案: 首先,有250列的表加上一个数字是一场噩梦。您不能使用SQL能够很好地帮助您的任何内置功能。你应该有两张桌子。首先是一个projects表,该表的ID列加上State、Project和BuildType列。然后是ProjectDates表,其中ProjectID列引用第一个表,然后是ActualDate列。从这方面报告应该很容易
考虑到您可能无法修复该结构,请尝试编写一个存储过程。它可以使用动态SQL。更好的做法是,您的存储过程可以创建如上所述的临时表,然后使用它们进行统计。我100%同意Charles的观点。如果你能改变结构,我会这么做: 如果可能的话,有一个构建类型表(ID/构建类型),不要有文本列,除非您需要它们作为文本。任何可以编码的东西,都要编码 这两个表格:
- 项目标题(Proj_ID(long_int)/State(int或char(2))/build_type(int)),主键Proj_ID本身或一个新ID(如果它不是唯一的)(作为PK项目ID和State作为PK不会太有用)李>
- 项目日期(项目ID(与上述主键相同)/日期ID(内部)/实际日期(日期时间))
Select 'Actual_date'
from Project_date
where Project_id='nnn'
order by date_id DESC
Limit 1;
项目标题:
214356 / UT / 2 (being 1 Residential, 2 Commercial, 3 Industrial ...)
工程日期:
214356 / 0 / '07/08/13'
214356 / 1 / '06/09/13'
214356 / 2 / '07/01/12'
按项目划分的最新建造日期为:
Select 'Actual_date'
from Project_date
where Project_id='nnn'
order by date_id DESC
Limit 1;
您的查询类似于(如果日期是按递增顺序排列的):
选择项目id,最大值(日期id)
从项目日期开始
按项目编号分组
有实际日期<@日期
你可以看到这很直接
如果您不能更改结构,但可以创建新表,那么我将创建一个SP,该SP将接收丑陋的表,并每天生成x次项目\ u日期(或者您甚至可以将其绑定到第一个表的惰性/更新触发器)和一次项目\ u头(如果需要,可以更频繁)。这将比您正在尝试的操作花费更少的时间和精力,而且您可以将其用于其他查询。我100%同意Charles的观点。如果你能改变结构,我会这么做: 如果可能的话,有一个构建类型表(ID/构建类型),不要有文本列,除非您需要它们作为文本。任何可以编码的东西,都要编码 这两个表格:
- 项目标题(Proj_ID(long_int)/State(int或char(2))/build_type(int)),主键Proj_ID本身或一个新ID(如果它不是唯一的)(作为PK项目ID和State作为PK不会太有用)李>
- 项目日期(项目ID(与上述主键相同)/日期ID(内部)/实际日期(日期时间))
Select 'Actual_date'
from Project_date
where Project_id='nnn'
order by date_id DESC
Limit 1;
项目标题:
214356 / UT / 2 (being 1 Residential, 2 Commercial, 3 Industrial ...)
工程日期:
214356 / 0 / '07/08/13'
214356 / 1 / '06/09/13'
214356 / 2 / '07/01/12'
按项目划分的最新建造日期为:
Select 'Actual_date'
from Project_date
where Project_id='nnn'
order by date_id DESC
Limit 1;
您的查询类似于(如果日期是按递增顺序排列的):
选择项目id,最大值(日期id)
从项目日期开始
按项目编号分组
有实际日期<@日期
你可以看到这很直接
如果您不能更改结构,但可以创建新表,那么我将创建一个SP,该SP将接收丑陋的表,并每天生成x次项目\ u日期(或者您甚至可以将其绑定到第一个表的惰性/更新触发器)和一次项目\ u头(如果需要,可以更频繁)。这将比您正在尝试的花费更少的时间和精力,而且您可以将其用于其他查询。为了解决这个问题,我创建了一个包含实际日期的表。然后,我遍历了List_ACTUAL表中的每一行,以获得名称,并选择日期名称的计数大于我传入的变量。我将把它转换成一个进程。这就是为什么:
DECLARE @MS nvarchar(16)
DECLARE MSLIST CURSOR LOCAL FOR SELECT MilstoneNmbr FROM List_ACTUAL
DECLARE @SQL nvarchar(max)
DECLARE @DATE nvarchar(16)
SET @DATE = '1/1/2013'
CREATE #TEMP (Milestones nvarchar(16), Frozen int)
OPEN MSLIST
FETCH NEXT FROM MSLIST INTO @MS
WHILE @@FETCH_STATUS=0
BEGIN
SELECT @SQL = 'INSERT INTO #TEMP VALUES (''' +@MS+ ''', (Select count(' +@MS+ ') FROM PROJECTDATA WHERE ' +@MS+ ' > ''' + @Date + '''))'
EXEC sp_executesql @SQL, N''
FETCH NEXT FROM MSLIST INTO @MS
END
CLOSE MSLIST
DEALLOCATE MSLIST
希望这对某人有所帮助。为了解决这个问题,我创建了一个包含实际日期的表。然后,我遍历了List_ACTUAL表中的每一行,以获得名称,并选择日期名称的计数大于我传入的变量。我将把它转换成一个进程。这就是为什么:
DECLARE @MS nvarchar(16)
DECLARE MSLIST CURSOR LOCAL FOR SELECT MilstoneNmbr FROM List_ACTUAL
DECLARE @SQL nvarchar(max)
DECLARE @DATE nvarchar(16)
SET @DATE = '1/1/2013'
CREATE #TEMP (Milestones nvarchar(16), Frozen int)
OPEN MSLIST
FETCH NEXT FROM MSLIST INTO @MS
WHILE @@FETCH_STATUS=0
BEGIN
SELECT @SQL = 'INSERT INTO #TEMP VALUES (''' +@MS+ ''', (Select count(' +@MS+ ') FROM PROJECTDATA WHERE ' +@MS+ ' > ''' + @Date + '''))'
EXEC sp_executesql @SQL, N''
FETCH NEXT FROM MSLIST INTO @MS
END
CLOSE MSLIST
DEALLOCATE MSLIST
希望这对某人有所帮助。表格逻辑实际上是按照您提到的方式设置的。一个项目中的项目信息和另一个项目中的日期。我正在处理逻辑,尝试循环遍历列并将它们插入临时表。可能不是最好的十二月