SQL Server 在事实表上插入查询

Posted

技术标签:

【中文标题】SQL Server 在事实表上插入查询【英文标题】:SQL Server Insert Query on Fact Table 【发布时间】:2010-07-12 07:42:32 【问题描述】:

好的,我的事实表有这个问题。当在我的事实表上有外键的数据库中的所有其他表上输入新数据时,我需要自动填充它。在我的存储过程中,我编译了我拥有的所有插入语句,最后,因为我还想更新我的事实表,所以我放置了这个查询:

INSERT INTO Fact (AccountID, ExpenseID, DateTimeID, InventoryID)
VALUES (@AccountID, 
        (SELECT ExpenseID FROM Expenses WHERE WaterBill = @WaterBill AND ElectricBill = @ElectricBill AND OfficeRent = @OfficeRent,
        SELECT DateTimeID FROM DateTime WHERE MonthNo = @MonthNo AND Date = @Date AND Year = @Year AND Time = @Time AND Day = @Day AND DayNo = @DayNo,
        SELECT InventoryID FROM Inventory WHERE ProductInID = @ProductInID AND ProductOutID = @ProductOutID)

但是,我收到以下消息的错误:

Subqueries are not allowed in this context. Only scalar expressions are allowed.

有人可以帮帮我吗?非常感谢。 :)

我的完整程序:

    ALTER PROCEDURE [dbo].[ExpenseListInsert]
    @AccountID char(6),
    @ExpenseID int,
    @DateTimeID int,
    @InventoryID int,
    @WaterBill decimal(19, 4),
    @ElectricBill decimal(19, 4),
    @OfficeRent decimal(19, 4),
    @Miscellaneous decimal(19, 4),
    @ProductsExpense decimal(19, 4),
    @Subtotal decimal(19, 4),
    @ProductInID int,
    @ProductOutID int,
    @Product30001 int,
    @Product30002 int,
    @Product30003 int,
    @MonthNo int,
    @Date int,
    @Year int,
    @Time char(11),
    @Day char(10),
    @DayNo int
AS
    INSERT INTO Expenses (WaterBill, ElectricBill, OfficeRent, Miscellaneous, ProductsExpense, Subtotal)
    VALUES(@WaterBill, @ElectricBill, @OfficeRent, @Miscellaneous, @ProductsExpense, @Subtotal)

    INSERT INTO ProductIn (ProductInID, Product30001, Product30002, Product30003)
    VALUES(@ProductInID, @Product30001, @Product30002, @Product30003)

    INSERT INTO ProductOut (ProductOutID, Product30001, Product30002, Product30003)
    VALUES(@ProductOutID, '0', '0', '0')

    INSERT INTO Inventory (ProductInID, ProductOutID)
    VALUES (@ProductInID, @ProductOutID) 

    INSERT INTO DateTime (MonthNo, Date, Year, Time, Day, DayNo)
    VALUES (@MonthNo, @Date, @Year, @Time, @Day, @DayNo)

    SELECT @ExpenseID = ExpenseID FROM Expenses WHERE WaterBill = @WaterBill AND ElectricBill = @ElectricBill AND OfficeRent = @OfficeRent

    SELECT @DateTimeID = DateTimeID FROM DateTime WHERE MonthNo = @MonthNo AND Date = @Date AND Year = @Year AND Time = @Time AND Day = @Day AND DayNo = @DayNo

    SELECT @InventoryID = InventoryID FROM Inventory WHERE ProductInID = @ProductInID AND ProductOutID = @ProductOutID

    INSERT INTO Fact (AccountID, ExpenseID, DateTimeID, InventoryID)
    VALUES (@AccountID, @ExpenseID, @DateTimeID, @InventoryID)
RETURN

【问题讨论】:

【参考方案1】:

假设每个子查询只能返回一条记录,这应该可以工作

DECLARE @ExpenseID int, @DateTimeID int, @InventoryID int


SELECT @ExpenseID= ExpenseID FROM Expenses WHERE WaterBill = @WaterBill AND ElectricBill = @ElectricBill AND OfficeRent = @OfficeRent

SELECT @DateTimeID = DateTimeID FROM DateTime WHERE MonthNo = @MonthNo AND Date = @Date AND Year = @Year AND Time = @Time AND Day = @Day AND DayNo = @DayNo

SELECT @InventoryID = InventoryID FROM Inventory WHERE ProductInID = @ProductInID AND ProductOutID = @ProductOutID

INSERT INTO Fact (AccountID, ExpenseID, DateTimeID, InventoryID)
VALUES (@AccountID, @ExpenseID, @DateTimeID, @InventoryID)

【讨论】:

先生,谢谢。但我尝试运行这个存储过程。但是每次我运行我的应用程序时,它都会给我一个错误,说我的程序需要一个未提供的@ExpenseID 参数。我现在将编辑我的问题以放置我的存储过程。谢谢。【参考方案2】:

您不能使用普通 INSERT 执行子查询,您需要执行 INSERT...SELECT:

INSERT INTO [Fact] (AccountID, ExpenseID, DateTimeID, InventoryID)
SELECT @AccountID, 
       (SELECT ExpenseID FROM [Expenses] WHERE WaterBill = @WaterBill AND ElectricBill = @ElectricBill AND OfficeRent = @OfficeRent),
       (SELECT DateTimeID FROM [DateTime] WHERE MonthNo = @MonthNo AND [Date] = @Date AND [Year] = @Year AND [Time] = @Time AND [Day] = @Day AND DayNo = @DayNo),
       (SELECT InventoryID FROM Inventory WHERE ProductInID = @ProductInID AND ProductOutID = @ProductOutID)

我还会查看可能的性能瓶颈的执行计划,并查看 Expense、DateTime 和 Inventory 表上的索引。

【讨论】:

我不明白这个查询的作用。你能给我解释一下吗?谢谢。 :) 当你使用 VALUES 和 INSERT 时,你需要传入 SCALAR 值。当您将 SELECT 与 INSERT 一起使用时,您可以传入一个表格结果集,在这种情况下,是您的三个子查询的结果。 这听起来可能很愚蠢,但我还是不明白。我真正想做的是: INSERT INTO Fact (A, B, C, D) VALUES (A, B 应该来自另一个表,C 应该来自另一个表,D 应该来自另一个表) 这是 SELECT INSERT 适用于这种情况吗?非常感谢。 嗯,这就是你正在做的,当你做 INSERT INTO [Fact] (A, B, C, D) SELECT , , 、B、C 和 D 的值是您对费用、日期时间和库存的子查询的结果字段...【参考方案3】:

将您的查询更改为:

INSERT INTO Fact (AccountID, ExpenseID, DateTimeID, InventoryID) 
SELECT @AccountID,  
    (SELECT ExpenseID FROM Expenses WHERE WaterBill = @WaterBill AND ElectricBill = @ElectricBill AND OfficeRent = @OfficeRent), 
    (SELECT DateTimeID FROM DateTime WHERE MonthNo = @MonthNo AND Date = @Date AND Year = @Year AND Time = @Time AND Day = @Day AND DayNo = @DayNo), 
    (SELECT InventoryID FROM Inventory WHERE ProductInID = @ProductInID AND ProductOutID = @ProductOutID)

【讨论】:

这个查询给了我以下错误信息:Msg 102, Level 15, State 1, Procedure ExpenseListInsert, Line 38 ',' 附近的语法不正确。消息 102,级别 15,状态 1,过程 ExpenseListInsert,第 39 行 ',' 附近的语法不正确。 @Kim Rivera - 已修复。我以为你把每个SELECT括起来了

以上是关于SQL Server 在事实表上插入查询的主要内容,如果未能解决你的问题,请参考以下文章

插入和提交后行从 SQL Server 表中消失

SQL Server:在左连接查询的执行计划中插入隐藏的“排序”

sql server 2005 中的分区问题?

使用带有R的odbc库将SQL Server插入单个值

提高 SQL Server 中最新记录的选择和插入性能

创建触发器后的 SQL Server