SQL无法从选择语句中识别表名

时间:2019-08-28 15:40:00

标签: sql sql-server

如果我在“ FROM”之后写上tablename,则查询有效。如果我使用select语句的结果,查询将无法解决。有解决方法吗?

我已经尝试将tablename解析为存储过程的输出,但是在没有收到错误的情况下,我似乎无法在存储过程或函数中使用exec

ALTER PROCEDURE [dbo].[EDOFA_TABLE]
(
@DTCODE nvarchar(max) = null
,@DTAMPO nvarchar(max) = null
,@DTNDOS float = null
,@DTTFAC nvarchar(max) = null
,@DTCDEB nvarchar(max) = null
,@DTNDEB float = null
,@DTDAPP float = null
)
AS

BEGIN

INSERT INTO EDOFA (DTCODE
      ,DTAMPO
      ,DTNDOS
      ,DTTFAC
      ,DTCDEB
      ,DTNDEB
      ,DTDAPP)
SELECT DTCODE
      ,DTAMPO
      ,DTNDOS
      ,DTTFAC
      ,DTCDEB
      ,DTNDEB
      ,DTDAPP
FROM (SELECT max(name) FROM sys.tables WHERE name like 'EDOFA%')
WHERE DTCODE = @DTCODE
      OR DTAMPO = @DTAMPO
      OR DTNDOS = @DTNDOS
      OR DTTFAC = @DTTFAC
      OR DTCDEB = @DTCDEB
      OR DTNDEB = @DTNDEB
      OR DTDAPP = @DTDAPP
END

关键字where附近的语法不正确

3 个答案:

答案 0 :(得分:2)

正如我在评论中所述,“这不是SQL的工作方式。您不能用表达式,变量名等替换对象。它必须是基本的;您需要使用参数化的动态SQL。” 。我相信这就是你所追求的。

ALTER PROCEDURE [dbo].[EDOFA_TABLE] (@DTCODE nvarchar(MAX) = NULL,
                                     @DTAMPO nvarchar(MAX) = NULL,
                                     @DTNDOS float = NULL,
                                     @DTTFAC nvarchar(MAX) = NULL,
                                     @DTCDEB nvarchar(MAX) = NULL,
                                     @DTNDEB float = NULL,
                                     @DTDAPP float = NULL)
AS
BEGIN

    DECLARE @SQL nvarchar(MAX);

    SET @SQL = N'INSERT INTO dbo.EDOFA (DTCODE,' + NCHAR(13) + NCHAR(10) +
               N'                       DTAMPO,' + NCHAR(13) + NCHAR(10) +
               N'                       DTNDOS,' + NCHAR(13) + NCHAR(10) +
               N'                       DTTFAC,' + NCHAR(13) + NCHAR(10) +
               N'                       DTCDEB,' + NCHAR(13) + NCHAR(10) +
               N'                       DTNDEB,' + NCHAR(13) + NCHAR(10) +
               N'                       DTDAPP)' + NCHAR(13) + NCHAR(10) +
               N'SELECT DTCODE,' + NCHAR(13) + NCHAR(10) +
               N'       DTAMPO,' + NCHAR(13) + NCHAR(10) +
               N'       DTNDOS,' + NCHAR(13) + NCHAR(10) +
               N'       DTTFAC,' + NCHAR(13) + NCHAR(10) +
               N'       DTCDEB,' + NCHAR(13) + NCHAR(10) +
               N'       DTNDEB,' + NCHAR(13) + NCHAR(10) +
               N'       DTDAPP' + NCHAR(13) + NCHAR(10) +
               N'FROM dbo.' + QUOTENAME((SELECT MAX([name]) FROM sys.tables WHERE name LIKE 'EDOFA%')) + NCHAR(13) + NCHAR(10) +
               N'WHERE DTCODE = @DTCODE' + NCHAR(13) + NCHAR(10) +
               N'   OR DTAMPO = @DTAMPO' + NCHAR(13) + NCHAR(10) +
               N'   OR DTNDOS = @DTNDOS' + NCHAR(13) + NCHAR(10) +
               N'   OR DTTFAC = @DTTFAC' + NCHAR(13) + NCHAR(10) +
               N'   OR DTCDEB = @DTCDEB' + NCHAR(13) + NCHAR(10) +
               N'   OR DTNDEB = @DTNDEB' + NCHAR(13) + NCHAR(10) +
               N'   OR DTDAPP = @DTDAPP;';

    DECLARE @Params nvarchar(MAX) = N'@DTCODE nvarchar(MAX),' +
                                    N'@DTAMPO nvarchar(MAX),' +
                                    N'@DTNDOS float,' +
                                    N'@DTTFAC nvarchar(MAX),' +
                                    N'@DTCDEB nvarchar(MAX),' +
                                    N'@DTNDEB float,' +
                                    N'@DTDAPP float';

    --PRINT @SQL; --Your best friend

    EXEC sp_executesql @SQL, @Params, @DTCODE, @DTAMPO, @DTNDOS, @DTTFAC, @DTCDEB, @DTNDEB, @DTDAPP;

END;

我构建了一个动态语句,并将其放入@SQL中;并确保我使用QUOTENAME 正确引用动态对象名称。然后,我构建参数并将它们全部传递给我们sp_executesql的动态语句。

如果遇到问题,请取消注释最好的朋友(并注释掉EXEC)并调试打印的SQL。

答案 1 :(得分:0)

您的from子句返回标量,但未命名。同样,from子句中的子查询也需要别名。这就是导致您得到错误的原因。

添加别名后,还会收到其他错误。例如DTAMPO不是FROM子句返回的列

答案 2 :(得分:0)

您不能在SQL中动态包含标识符,但可以包含常量值。为此,请像这样使用sp_executesql

BEGIN
    DECLARE @sql NVARCHAR(MAX);

    SET @sql = '
    INSERT INTO EDOFA (DTCODE, DTAMPO, DTNDOS, DTTFAC, DTCDEB, DTNDEB, DTDAPP)
    SELECT DTCODE, DTAMPO, DTNDOS, DTTFAC, DTCDEB, DTNDEB, DTDAPP
    FROM [table]
    WHERE DTCODE = @DTCODE OR
          DTAMPO = @DTAMPO OR
          DTNDOS = @DTNDOS OR
          DTTFAC = @DTTFAC OR
          DTCDEB = @DTCDEB OR
          DTNDEB = @DTNDEB OR
          DTDAPP = @DTDAPP';

    -- Replace the table name because, alas, we cannot parameterize that
    SET @SQL = REPLACE(@SQL,
                      '[table]',
                       (SELECT max(name) FROM sys.tables WHERE name like 'EDOFA%')
                      );

    -- Pass everything else as parameters
    EXEC sp_executesql @SQL,
                       N'
@DTCODE nvarchar(max),
@DTAMPO nvarchar(max),
@DTNDOS float,
@DTTFAC nvarchar(max),
@DTCDEB nvarchar(max),
@DTNDEB float,
@DTDAPP float',
                      @DTCODE=@DTCODE, @DTAMPO=@DTAMPO, @DTNDOS=@DTNDOS, @DTTFAC=@DTTFAC,
                      @DTCDEB=@DTCDEB, @DTNDEB=@DTNDEB, @DTDAPP=@DTDAPP;
END;

编写代码可能会比较麻烦,但是在将值传递到SQL查询中时,使用参数无疑是最佳实践。