【问题标题】:Sum Over SQL without grouping or orderingSum Over SQL 没有分组或排序
【发布时间】:2016-01-14 11:22:27
【问题描述】:

我有一个这样的 SQL Server 查询:

CREATE TABLE ##Temp(
    OrderID NVARCHAR(100), 
    ID INT,
    Prices INT,
    Total INT
);

INSERT INTO ##Temp (ID, Prices, OrderID, Total)
SELECT  fc.ID, f.Prices, f.OrderID, 
        (SUM(f.Prices) OVER()) AS Total 
FROM FruitCrates fc
LEFT JOIN Fruits f ON fc.ID = f.FruitCrateID
WHERE  fc.OrderID LIKE '18_1635' 
  AND fc.Rights = 1 
  AND fc.Cancelled = 0 
  AND f.OrderID IS NOT NULL;

SELECT * FROM ##Temp;

但我不断收到错误消息:

消息 207,第 16 级,状态 1,第 12 行
列名“总计”无效。

我认为这是因为我没有正确使用OVER()但是我不知道如何解决它。

请注意

SELECT 语句在INSERT 之后没有放入时会继续运行。

没有 INSERT 的结果

╔═════╦════════╦══════════╦═══════╗
║ ID  ║ Prices ║ OrderID  ║ Total ║
╠═════╬════════╬══════════╬═══════╣
║  77 ║      1 ║ 1_370    ║   104 ║
║  19 ║    101 ║ 1811_171 ║   104 ║
║  77 ║      2 ║ 1811_171 ║   104 ║
╚═════╩════════╩══════════╩═══════╝   

【问题讨论】:

  • 全局临时表。我敢打赌它有不同的架构。请在插入之前发布SELECT * FROM ##temp的结果
  • 你不明白这一点。我猜你有名字 colsion(存储过程调用另一个存储过程)并且你对临时表使用相同的名称。如果不发布更多代码,您的案例将无法复制,应该关闭。答案是不要到处使用相同的名称。
  • 我同意@lad2025 - 尝试在顶部执行DROP TABLE ##Temp(尽管您可能会删除您想要的内容...)或用另一个名称替换##Temp#Temp1 可能会这样做)。如果其中任何一个有效,那就是你的问题。
  • @PleaseTeach 所以我是对的。
  • 我不明白为什么CREATE TABLE 语句没有抛出错误?

标签: sql sql-server tsql global-temp-tables


【解决方案1】:

插入Invalid column name 'Total'. 的错误消息清楚地表明##Temp 表与INSERT INTO (...) 语句中的列列表具有不同的架构。

要解决它,您应该始终在插入之前检查元数据(列名):

SELECT *
FROM ##Temp
WHERE 1=2;

然后你可以很容易地发现它与你假设的不同。

现在您正在使用全局临时表,只要最后一个引用它的连接处于活动状态,它就会一直存在。您应该考虑使用本地临时表。

要解决您的问题,您可以:

  1. 使用不同的名称以避免冲突
  2. 就在你可以之前(如果不用于嵌套过程):

    如果 OBJECT_ID('tempdb..##temp') 不为空 删除表##temp 创建表##temp...

当存储过程调用另一个存储过程并且两者(外部和内部)都创建具有相同名称的临时表时,还有一个令人讨厌的情况。你应该避免它。

CREATE PROCEDURE #outer
AS
BEGIN
   CREATE TABLE ##temp (id INT, guid UNIQUEIDENTIFIER, col2 VARCHAR(100));
   INSERT INTO ##temp VALUES(1,NEWID(), 'a');
   SELECT * FROM ##temp;
   EXEC [#inner];
END
GO

CREATE PROCEDURE #inner
AS
BEGIN
    CREATE TABLE ##temp (id INT, total INT);  -- no error during creation

    INSERT INTO ##temp(id, total)
    SELECT 2, 10;

    SELECT * FROM ##temp;
END
GO

EXEC #outer
-- Invalid column name 'total'.

LiveDemo

最有趣的是,当您使用具有相同列数(或默认值)的本地临时表并且可以进行隐式转换时,它会通过:

CREATE PROCEDURE #outer
AS
BEGIN
CREATE TABLE #temp (id INT, col2 varchar(10));
   INSERT INTO #temp VALUES(1, 'a');
   SELECT * FROM #temp;
   EXEC [#inner];
END
GO

CREATE PROCEDURE #inner
AS
BEGIN
    CREATE TABLE #temp (id INT, total INT);
    INSERT INTO #temp
    SELECT 2, 10;

    SELECT * FROM #temp;
END
GO

EXEC #outer

LiveDemo2

以及类型不兼容的示例:

CREATE PROCEDURE #outer
AS
BEGIN
CREATE TABLE #temp (id INT, col2 UNIQUEIDENTIFIER);
INSERT INTO #temp VALUES(1, NEWID());
   SELECT * FROM #temp;
   EXEC [#inner];
END
GO

CREATE PROCEDURE #inner
AS
BEGIN
    CREATE TABLE #temp (id INT, total INT);
    INSERT INTO #temp
    SELECT 2, 10;

    SELECT * FROM #temp;
END
GO

EXEC #outer

操作数类型冲突:int 与 uniqueidentifier 不兼容

【讨论】:

  • @aucuparia What I don't understand is why the CREATE TABLE statement didn't throw an error? 请看我的演示
  • @lad2015,我最终将我的查询设置为嵌套选择查询,这消除了创建临时表的需要,我将在视图中使用这些选择语句,我可能会在将来的代码审查中发布它们完成后,感谢您的详细回答+1
  • @PleaseTeach 很高兴听到它。完成后,请使用codereview.stackexchange.com 发布链接以进行审核,并使用sqlfiddle.com 准备现场演示:)
猜你喜欢
  • 2020-10-10
  • 2022-01-08
  • 2020-08-16
  • 1970-01-01
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-07
  • 1970-01-01
相关资源
最近更新 更多