2

我有一个表格示例:

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

我正在尝试创建一个报告,该报告采用以实际单词开头的列标题并计算有多少日期小于特定日期。我有一个以实际单词开头的列标题创建的临时表。这只是一个例子,实际有超过 250 个列名。所以表格看起来像这样:

MilestoneNmbr  
-------------
ACTUAL1  
ACTUAL2  
ACTUAL3  

现在我认为可行的是将行作为列标题的变量并将日期传递给函数。这是我创建的一个函数:

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   CountofDate  
--------------- ------------
ACTUAL1         200  
ACTUAL2         344  
ACTUAL3         400  
4

3 回答 3

2

你是对的,你不能在函数中使用动态 SQL。有两个答案:

首先,您的 250 列 ACTUAL 加上一个数字的表是一场噩梦。您不能使用 SQL 可以很好地提供帮助的任何内置内容。你应该有两张桌子。首先是一个包含 ID 列以及 State、Project 和 BuildType 列的项目表。然后是一个 ProjectDates 表,其中一个 ProjectID 列引用第一个表,然后是 ActualDate 列。从中报告应该很容易。

鉴于您可能无法修复结构,请尝试编写存储过程。那可以使用动态SQL。更好的是,您的存储过程可以像上面一样创建临时表,然后使用它们进行统计。

于 2013-09-05T22:27:07.437 回答
2

我 100% 同意查尔斯。如果您可以更改结构,这就是我要做的:

如果可能有一个构建类型表(ID/构建类型),不要有文本列,除非您需要它们作为某些内容的文本。任何可以编码的东西,编码它。

两张表:

  • 项目标头 (Proj_ID (long_int)/State (int or char(2)) / build_type (int)),主键 Proj_id 本身或新 ID(如果它不是唯一的)(因为 PK Proj_id & State 不会太有用作为PK)。
  • Project_date (Proj_ID (与上面的PK相同) / Date_ID (int) / Actual_Date (DateTime))

所以你的第二个例子是:

项目标题:

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;

您的查询将类似于(如果日期按递增顺序):

Select Project_id, max(Date_id)
From Project_date
Group by Project_id
having Actual_date < @date

你可以看到它非常简单。

如果你不能改变结构但你可以制作新表,我会制作一个 SP 来获取那个丑陋的表并每天生成 Project_Date x 次(或者你甚至可以将它绑定到第一个表的惰性/更新触发器) 和 Project_header 每天一次(或者如果需要更频繁)。与您尝试的相比,这将花费更少的时间和精力,而且您可以将其用于其他查询。

于 2013-09-05T23:13:39.033 回答
0

为了解决这个问题,我创建了一个包含实际日期的表格。然后,我遍历 List_ACTUAL 表中的每一行以获取名称并选择大于我传入的变量的日期名称的计数。我将把它转换为 PROC。这是如何:

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  

希望这可以帮助某人。

于 2013-09-06T22:33:39.410 回答