2013-02-28 139 views
2

运行SQL Server的2005/2008,我重写我的查询是更清洁,更符合不包括坏习惯。我曾经有很多IF陈述和PIVOT这样做,但找到了一个更好的方式来实现它,只需要最后一点,使其几乎完美。INSERT INTO动态添加列

DECLARE @startdate DATETIME; 
DECLARE @enddate DATETIME; 
DECLARE @showstore INT; 
DECLARE @showcashier INT; 
DECLARE @showregister INT; 
DECLARE @showdate INT; 
DECLARE @sql NVARCHAR(MAX); 
DECLARE @result0 NVARCHAR(MAX); 

SET @startdate = '1/1/2012'; 
SET @enddate = '2/28/2013'; 
SET @showdate = 1; 
SET @showstore = 0; 
SET @showcashier = 1; 
SET @showregister = 0; 
SET @startdate = DATEADD(DAY, DATEDIFF(DAY, 0, @startdate), 0); 
SET @enddate = DATEADD(DAY, DATEDIFF(DAY, 0, @enddate), 0); 

SET @sql = N'CREATE TABLE ##a13 (' + SUBSTRING(
CASE WHEN @showdate = 1 THEN ',[Transaction Date] DATETIME' ELSE '' END + 
CASE WHEN @showstore = 1 THEN ',[Store ID] VARCHAR(10)' ELSE '' END + 
CASE WHEN @showcashier = 1 THEN ',[Cashier] VARCHAR(100)' ELSE '' END + 
CASE WHEN @showregister = 1 THEN ',[Register] VARCHAR(20)' ELSE '' END, 2, 2000); 

DECLARE myCursor CURSOR FOR 
    SELECT DISTINCT c.CurrencyDesc 
    FROM dbo.Currencies AS c INNER JOIN dbo.rpPay AS p ON c.POSCurrency = p.PayType 
     INNER JOIN dbo.RPTrs AS r ON r.ReceiptNO = p.ReceiptNo 
    WHERE 
     c.CurrencyDesc <> 'Testing' AND c.CurrencyDesc <> 'Cash Change' AND 
     r.TRSDate >= @startdate AND r.TRSDate <= @enddate 
OPEN myCursor 
FETCH NEXT FROM myCursor INTO @result0 
WHILE @@FETCH_STATUS = 0 
    BEGIN 
     SET @sql = @sql + ',[' + @result0 + '] INT' 
     FETCH NEXT FROM myCursor INTO @result0 
    END 
CLOSE myCursor 
DEALLOCATE myCursor 

SET @sql = @sql + ')' 
EXECUTE sp_executesql @sql, N'@startdate DATETIME, 
    @enddate DATETIME',@startdate, @enddate; 

SET @sql = 'SELECT * FROM ##a13; DROP TABLE ##a13' 
EXECUTE sp_executesql @sql 

返回一个空行的表。 (知道货币表有更多CurrencyDesc然后在这里显示,因为这些都只是在提供的日期范围内所使用的那些)

enter image description here

这正是我从它的期望。迄今为止非常棒。现在我需要根据日期范围(@startdate >= and <= @enddate)向其添加数据行,并取决于他们从4种可能的选项中检查了什么(@showstore, @showcashier, @showdate, @showregister

示例:日期从2013年1月1日到2 /只有(如被看见在图片)二千零十三分之二十八并显示注册应该有这样的数据:

| Register | Cash | House Acct | MasterCard | Visa/MC 
-------------------------------------------------------- 
1 | 01  | 20.00 | 235.25  | 1235.32 | 135.23 
2 | 02  | 30.00 | 3542.42 | 323.52  | 523.64 
3 | 03  | 23.35 | 100.32  | 3267.24 | 235.25 

原因2005/2008是因为一些,这是对执行的客户,仍然使用2005年才能使用PIVOT我将不得不更改为2005年

PS每个数据库的兼容级别。在我得到的又喊道,如果我用#A13,而不是全球## A13的它给了我

Msg 208, Level 16, State 0, Line 1 
Invalid object name '#a13'. 

我可以做的,所以我不使用全局临时表?

+0

“原因2005/2008是因为一些,这是对执行的客户,仍然使用2005年为了使用PIVOT我将不得不更改为2005年每个数据库的兼容级别”咦? – swasheck 2013-02-28 19:42:38

+0

那么你问如何不使用'## GLOBAL'临时表? – JNK 2013-02-28 19:42:45

+1

我对你有关'pivot'的评论感到困惑,两个sql server 2005/2008都有这个功能。 – Taryn 2013-02-28 19:43:42

回答

6

如果我在这里不正确,请澄清。

我相信你是问如何填充根据用户输入动态列的表。 这里的答案是,不这样做!

这种事情的最佳实践是在输出表中包含所有字段,然后在应用程序/显示层中只显示用户请求的字段。

自定义内TSQL表布局只是为了让一个干净的演示介绍了很多不必要的复杂性。这种复杂性也伴随着性能成本的增加。

如果你有一个静态输出表,则是微不足道的返回使用给出的参数数据。

+0

谢谢,我会这样做。这样做更有意义。 – JohnZ 2013-02-28 19:54:39

+0

@JohnZ乐于帮忙。请始终记住,数据层不必与用户看到的内容相匹配,并且在数据库之外执行此类事情要容易得多。 – JNK 2013-02-28 19:56:40

+0

现在怎么样全球临时表的事情?我如何使用动态SQL临时表而不使用全局变量? – JohnZ 2013-02-28 20:03:24