3

我有一个存储过程,如果表存在则删除它,然后它重新创建表并用相关数据填充它,我的一个朋友有大约相同的代码,唯一真正的区别在于表的列标题。

作为说明,这是我的外观(不是真的,只是一个表示)。

+----+-----+-----+--------+
| ID | Foo | Bar | Number |
+----+-----+-----+--------+
|  1 | x   | x   |      0 |
|  2 | x   | x   |      1 |
+----+-----+-----+--------+

这就是他的样子

+----+--------+--------+-----+--------+
| ID | BarFoo | FooBar | Num | Suffix |
+----+--------+--------+-----+--------+
|  1 | x      | x      |   0 | a      |
|  2 | x      | x      |   1 | b      |
+----+--------+--------+-----+--------+

同样,这些只是情况的代表。

由于这是一项学校作业,老师将创建和执行两个 SP,但是在使用另一个 SP 后创建 SP 时,我收到此错误:

消息 207,级别 16,状态 1,过程 XYZ,第 59 行
无效的列名称“Foo”。

消息 213,级别 16,状态 1,过程 XYZ,第 61 行
列名称或提供的值的数量与表定义不匹配。

然而,在这两个存储过程的开始,我们有这个:

CREATE PROCEDURE XYZ
AS
BEGIN
    IF EXISTS (SELECT name
               FROM   sysobjects
               WHERE  name = 'TABLENAME'
                      AND xtype = 'u')
        DROP TABLE TABLENAME;

据我了解,这应该删除整个表?包括表/列定义和数据?

到目前为止,我发现的唯一解决方法是DROP TABLE在创建存储过程之前单独执行,这对我们不起作用,因为它确实必须在存储过程中。

帮助将不胜感激:)

编辑:这是我的实际代码,除了注释,这正是它在我的脚本中的样子(不包括它后面的其他代码)。

IF EXISTS (SELECT name
           FROM   sysobjects
           WHERE  name = 'BerekenStatistiek'
                  AND xtype = 'p')
    DROP PROCEDURE BerekenStatistiek;


GO
CREATE PROCEDURE BerekenStatistiek
@jaar INT=0
AS
BEGIN
    IF EXISTS (SELECT name
               FROM   sysobjects
               WHERE  name = 'Statistiek'
                      AND xtype = 'u')
        DROP TABLE Statistiek;
    DECLARE @year AS NVARCHAR (4);
    SET @year = CONVERT (NVARCHAR (4), @jaar);
    SELECT *,
           CAST (Kost - Korting + Freight AS MONEY) AS Netto,
           '' AS Richting
    INTO   Statistiek
    FROM   (SELECT   O.Kwartaal,
                     CAST (SUM(O.Kost) AS MONEY) AS Kost,
                     CAST (SUM(O.Korting) AS MONEY) AS Korting,
                     CAST (SUM(O.Freight) AS MONEY) AS Freight
            FROM     (SELECT CASE 
WHEN CONVERT (NVARCHAR (8), OrderDate, 112) BETWEEN @year + '0101' AND @year + '0331' THEN 1 
WHEN CONVERT (NVARCHAR (8), OrderDate, 112) BETWEEN @year + '0401' AND @year + '0630' THEN 2 
WHEN CONVERT (NVARCHAR (8), OrderDate, 112) BETWEEN @year + '0701' AND @year + '0930' THEN 3 
WHEN CONVERT (NVARCHAR (8), OrderDate, 112) BETWEEN @year + '1001' AND @year + '1231' THEN 4 
END AS 'Kwartaal',
                             ROUND(UnitPrice * Quantity, 2) AS Kost,
                             Round((UnitPrice * Quantity) * Discount, 2) AS Korting,
                             Freight
                      FROM   Orders AS O
                             INNER JOIN
                             OrderDetails AS Od
                             ON O.OrderID = Od.OrderID
                      WHERE  CONVERT (NVARCHAR (4), OrderDate, 112) = @year) AS O
            GROUP BY O.Kwartaal) AS O1;
    ALTER TABLE Statistiek ALTER COLUMN Kwartaal INT NOT NULL;
    ALTER TABLE Statistiek ALTER COLUMN Richting NVARCHAR (8);
    ALTER TABLE Statistiek
        ADD PRIMARY KEY (Kwartaal);
...

这是他的代码(在变量中插入值只是为了便于阅读(他的代码有点笨重):

IF EXISTS (SELECT name
           FROM   sysobjects
           WHERE  name = 'BerekenStatistiek'
                  AND xtype = 'p')
    BEGIN
        DROP PROCEDURE BerekenStatistiek;
    END


GO
CREATE PROCEDURE BerekenStatistiek
@jaartal INT
AS
BEGIN
    DECLARE @huidigkwartaal AS INT = 1;
    DECLARE @beginmaand AS INT;
    DECLARE @eindmaand AS INT;
    DECLARE @vorige_netto_ontvangsten AS MONEY;
    IF EXISTS (SELECT *
               FROM   sysobjects
               WHERE  name = 'Statistiek'
                      AND xtype = 'U')
        BEGIN
            DROP TABLE Statistiek;
        END
    CREATE TABLE Statistiek
    (
        kwartaalnummer         INT          ,
        beginmaand             INT          ,
        eindmaand              INT          ,
        orderbedrag            MONEY        ,
        korting                MONEY        ,
        vervoerskost           MONEY        ,
        netto_ontvangsten      MONEY        ,
        stijgend_dalend_gelijk NVARCHAR (10)
    );

    --Variables get their data here.

    INSERT  INTO Statistiek (kwartaalnummer, beginmaand, eindmaand, orderbedrag, korting, vervoerskost, netto_ontvangsten, stijgend_dalend_gelijk)
    VALUES                 (@huidigkwartaal, @beginmaand, @eindmaand, @orderbedrag, @korting, @vervoerskost, @netto_ontvangsten, @stijgend_dalend_gelijk);
4

4 回答 4

2

“但是在使用另一个 SP 之后创建SP 时,我得到了这个错误”(添加了重点。)SQL Server 将坚持存储过程与创建存储过程时存在的表的定义相匹配。如果在创建存储过程时该表不存在,SQL Server 将假定在运行时会出现一个匹配的表。

create table t (c int)
go
create procedure p as begin
    drop table t 
    select 1 as diff_column_name into t
    select diff_colun_name from t
end

结果是:

Msg 207, Level 16, State 1, Procedure p, Line 6
Invalid column name 'diff_colun_name'.

现在, drop table t,然后创建过程:

drop table t 
go
create procedure p as begin
    drop table t 
    select 1 as diff_column_name into t
    select diff_colun_name from t
end

Command(s) completed successfully.
于 2015-01-12T17:47:19.817 回答
0

如果您可以使用不同的表名,请从该名称开始。并且,如果表必须在proc 执行后仅存在片刻以便可以从中选择,则创建一个全局临时表(即表名以##in开头##MyTable)。

但是,如果要求使用与您的同学相同的表名,那么老师可能会试图让您了解延迟对象解析(即@Shannon 的答案)以及如何解决它,因为在学习之外,这种情况毫无意义,因为在现实中永远不会做这样的事情。

子流程(即EXECsp_executesql)不会立即解析,因为它们在创建存储过程时不会被执行。因此,简单地说,只需声明一个新的 NVARCHAR(MAX) 变量来保存一些动态 SQL 并将您的SELECT语句放在那里。用于sp_executesql传入@year变量。您正在创建一个真实的表,因此它将在子流程结束后继续存在,然后该ALTER TABLE语句将起作用。

补充说明:

  • 您实际上并不需要该ALTER语句来设置 [Richting] 字段的数据类型。只需告诉 SQL Server SELECT 语句中的类型是什么:

    CONVERT(NVARCHAR(8), '') AS [Richting]
    
  • 您真的不想与CONVERT(NVARCHAR(8), OrderDate, 112)一个值进行比较,因为它会使任何可能在 on 的索引的使用无效[OrderDate]。相反,从字符串构造一个日期值并将其转换为 DATETIME 或 DATE(即CONVERT(DATETIME, @year + '0101'))。

    为了更好地理解这个问题,请阅读Sargability: Why %string% Is Slow,以及至少底部的第一个链接,即:What makes a SQL statement sargable?

  • 您真的不想将 OrderDate 字段转换为 NVARCHAR(4) 只是为了比较年份,原因与上面提到的相同。至少使用该YEAR()功能会更直接。但是如果要确保可以使用索引,则不能在字段上放置函数。但你只想要年份。那么年份不一样BETWEEN @Year + '0101' AND @Year + '1231'吗?;-)

    有趣的是,在“什么使 SQL 语句可搜索?”中接受的答案中的第一个示例。上一个项目符号中链接的 SO 问题正是我在这里推荐的:)。

于 2015-01-12T18:09:27.033 回答
0

在最后一段代码中,你有

AND xtype = 'U'

如果您的排序规则区分大小写,则不会发生丢弃,因此会出现错误。

于 2015-01-12T17:38:38.540 回答
0

据我所知,错误的查询是插入,因为引擎找不到正确的表结构,请检查插入是否与您的第二个表示例具有相同的结构。不要忘记在脚本开头检查 USE,也许您使用的是不同的数据库,这可能会发生:)。

于 2015-01-12T17:24:21.280 回答