动态创建表格的好方法是什么,然后将我创建的所有表格连接在一起?
背景
我正在尝试编写一个存储过程,该过程从数据库的各个部分收集数据并提供它以供使用。例如,如果我想向Alice和Bob发送发票,则此存储过程将查找发票的所有信息。诀窍在于Alice和Bob并不总是需要我拥有的所有信息。如果鲍勃是免税但是用simoleons进行交易,我需要包含有关货币汇率的信息,但不提供税务信息。我想给存储过程一个订单号,并将结果格式化回给客户。
到目前为止,我的解决方案是创建一个包含客户需求的表。然后我的存储过程检查表格:如果需要货币数据,我创建并填充@Currency
,或@Taxes
保存税务数据,依此类推。我检查需求,然后根据需要创建表。最后,我需要将数据加入一个记录集。
我的问题是我说错误
关键字'table'附近的语法不正确
错误说
必须声明表变量@Summary
在第1行我定义@Summary
这些错误仅在我使用动态SQL加入表时出现。当我注释掉动态SQL并将语句复制粘贴到它应该创建的语句时,我得到了我想要的结果。
代码
我尝试在Microsoft SQL Server Management Studio中使用以下动态SQL
create procedure <procedure> (@OrderNumber varchar(20)) AS
DECLARE @CustomerName varchar(35) -- retrieved based on @OrderNumber
DECLARE @SQLQuery nvarchar(500)
DECLARE @ParamDef nvarchar(500)
DECLARE @SummaryTable table
(
ID varchar(20) --=@OrderNumber
, <Stuff>
)
SET @SQLQuery = 'Select * From @SummaryTable'
SET @ParamDef = '@SummaryTable table'
IF EXISTS(Select <TableName> from CustRequirements where <TableName> = 1 AND Customer = @CustomerName)
BEGIN
--Create table
DECLARE @<TableName> table
(
ID varchar(20)
, <Stuff>
)
--Populate
Insert into <TableName> Select <RelevantData> From <DataSource> where <Condition based on @OrderNumber or @CustomerName>
--Pepare Dynamic SQL
Set @SQLQuery = @SQLQuery + ' FULL OUTER JOIN @<TableName> ON <TableName>.ID = SummaryTable.ID'
SET @ParamDef = ', @<TableName> table'
END
<repeat for other tables>
EXECUTE sp_executesql @SQLQuery, @ParamDef, @Summary, @LineItems, @Taxes, @Currency
问题
我的代码有问题吗?有一个更好的方法吗?我的另一个选择是在每个分支的底部都有IF Exists
树和整个 JOIN
语句(因为我似乎无法中断JOIN子句IF的)。问题是我需要2 ^ n JOIN
个语句才能加入n个可能的表。在这种情况下,n可能高达20或30。
答案 0 :(得分:1)
我想我发现代码中存在问题(可能有3个问题 - 请参阅下面的“可疑”1&amp; 2) -
1)[改变于10月21日,在OP的评论之后]最大的问题:在最终的“EXECUTE sp_executesql @SQLQuery ...”中传递的表参数有时不会被声明。
1a)@Summary实际上从未被声明...你声明并设置@SummaryTable,然后使用@Summary。 只需将其更改为@SummaryTable(我在下面的(4)中做了),我认为这将阻止您的第二条错误消息(“必须声明表变量@Summary”)。
1b)所有其他表格有时声明:它们的每个DECLARE语句都在“IF EXISTS”中。我建议(I)使声明无条件(outide IF EXISTS),但仍然有条件地INSERT ......或(II)使EXECUTE命令的格式随可用内容而变化。 (我怀疑未使用的表变量需要什么......) 在下面的第4点(添加10/21)中,我举了一个例子,我没有用我自己的数据库测试(测试会花费更多时间)...所以请让我知道如何它去......
2)[有问题1]混合案例的简单案例;)注意行......
Set @SQLQuery = @SqlQuery + ' FULL OUTER JOIN @<TableName> ON <TableName>.ID = SummaryTable.ID'
...首先有一个大写的“SQL”,然后是混合大小写的“Sql”。
为什么我说这是“有问题的” - 如果您的服务器的COLLATION不区分大小写,那么您在上面输入的内容就可以了。
3)[有问题2]你有'@TableName'和'@Table Name'(带空格)。我发现你的问题可能只是你输入它的方式。
点(4),在更新中添加回答 - 可能代码
create procedure <procedure> (@OrderNumber varchar(20)) AS
DECLARE @CustomerName varchar(35) -- retrieved based on @OrderNumber
DECLARE @SQLQuery nvarchar(500)
DECLARE @ParamDef nvarchar(500)
DECLARE @SummaryTable table
(
ID varchar(20) --=@OrderNumber
, <Stuff>
)
SET @SQLQuery = 'Select * From @SummaryTable'
SET @ParamDef = '@SummaryTable table'
--Create table variables, though they may not be populated
DECLARE @LineItems
(
ID varchar(20)
, <Stuff>
)
DECLARE @Taxes
(
ID varchar(20)
, <Stuff>
)
DECLARE @Currencytable
(
ID varchar(20)
, <Stuff>
)
IF EXISTS(Select <TableName> from CustRequirements where <TableName> = 1 AND Customer = @CustomerName)
BEGIN
--Populate
Insert into <TableName> Select <RelevantData> From <DataSource> where <Condition based on @OrderNumber or @CustomerName>
--Prepare Dynamic SQL
Set @SQLQuery = @SQLQuery + ' FULL OUTER JOIN @<TableName> ON <TableName>.ID = SummaryTable.ID'
SET @ParamDef = ', @<TableName> table'
END
<repeat for other tables>
EXECUTE sp_executesql @SQLQuery, @ParamDef, @SummaryTable, @LineItems, @Taxes, @Currency
答案 1 :(得分:0)
我决定使用的解决方案是创建一个表,然后使用ALTER TABLE
根据需要添加列。
CREATE Table #Output
(
InvoiceNumber varchar(20)
, <stuff>
)
IF EXISTS(Select <ThisSegment> FROM CustRequirements WHERE <ThisSegment> = 1 AND Customer = @CustomerName)
BEGIN
ALTER TABLE #Output ADD <ThisSegment> <dataType>
UPDATE #Output
SET <ThisSegment> = <data> from <DataSource>
WHERE <InvoiceNumber = DataSource.invoice> AND <Other conditions>
END
<Repeat as needed>