我有一个表格示例:
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
现在我认为可行的方法是将行作为列标题的变量,并将日期传递给函数。这是我创建的一个函数:
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
答案 0 :(得分:2)
你是对的,你不能在函数中使用动态SQL。有两个答案:
首先你的250列ACTUAL和一个数字的表是一场噩梦。您不能使用SQL可以提供帮助的任何内置函数。你应该有两张桌子。首先是一个项目表,它具有一个ID列以及State,Project和BuildType的列。然后是ProjectDates表,其中ProjectID列引用第一个表,然后是ActualDate列。报告应该很容易。
鉴于您可能无法修复结构,请尝试编写存储过程。那可以使用动态SQL。事件更好的是,您的存储过程可以创建如上所述的临时表,然后使用它们进行统计。
答案 1 :(得分:2)
我同意查尔斯100%的同意。如果你可以改变结构,这就是我要做的事情:
如果可能的话,有一个构建类型表(ID / Build Type),除非你需要它们作为文本的东西,否则不要有文本列。任何可以编码的东西都可以编码。
两个表:
所以你的第二个例子是:
Project_Header:
214356 / UT / 2 (being 1 Residential, 2 Commercial, 3 Industrial ...)
Project_Date:
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每天一次(如果需要,可以更频繁)。这比您尝试的时间和精力要少得多,而且您可以将其用于其他查询。
答案 2 :(得分:0)
为了解决这个问题,我创建了一个包含ACTUAL日期的表格。然后我循环遍历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
希望这有助于某人。