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  

希望这对某人有所帮助。

表格逻辑实际上是按照您提到的方式设置的。一个项目中的项目信息和另一个项目中的日期。我正在处理逻辑,尝试循环遍历列并将它们插入临时表。可能不是最好的十二月