执行包含SQL语句的String时出错

时间:2017-01-12 11:28:43

标签: sql sql-server database tsql

我正在编写一个运行我所有数据库的脚本,并检查其中是否有某个表。如果此表存在,则内容将按月分为其他表。

我已达到无法继续的程度。 事实是,我必须为每个月生成一个动态语句,创建一个表,并将该月的数据添加到该表。这已经完成了,但是这个动态语句是一个字符串,我想执行该字符串来执行它包含的SQL。

执行所有这些操作的代码如下:

EXEC sp_msForEachDB 'DECLARE @FECHAInicial varchar(50) 
DECLARE @FECHAFinal varchar(50) 
DECLARE @inicio varchar(50) 
DECLARE @fin varchar(50) 
DECLARE @sql varchar(200) 
DECLARE @sql2 varchar(200)  
DECLARE @inicioMes varchar(30) 
DECLARE @finMes varchar(30)

USE ?;

IF EXISTS ( SELECT 1 FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_TYPE=''BASE TABLE'' AND TABLE_NAME=''valores'')
BEGIN
    select DB_NAME() AS [Base de datos usada];

    set @FECHAInicial = (SELECT min(fecha) from valores);
    set @FECHAFinal = (SELECT max(fecha) from valores);
    set @inicio = (SELECT CONCAT("valores_", MONTH(@FECHAInicial), "_", YEAR(@FECHAInicial)));
    SET @fin = (SELECT CONCAT("valores_", MONTH(@FECHAFinal),"_", YEAR(@FECHAFinal)));

    WHILE @inicio <> @fin
    BEGIN

        SELECT @inicio;
        set @FECHAInicial =  (SELECT DATEADD(month, 1, @FECHAInicial));
        set @inicio = (SELECT CONCAT("valores_", MONTH(@FECHAInicial), "_", YEAR(@FECHAInicial)));
        set @inicioMes = (SELECT DATEADD(month, DATEDIFF(month, 0, @FECHAInicial), 0))
        set @inicioMes = (select convert(varchar(30), @inicioMes, 120))
        set @finMes = DATEADD(month, ((YEAR(@inicioMes) - 1900) * 12) + MONTH(@inicioMes), -1)
        set @finMes = DATEADD(day, 1, @finMes)

        IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES 
                   WHERE TABLE_TYPE=''BASE TABLE'' AND TABLE_NAME=@inicio) 
            BEGIN
                SELECT 1 AS res 
            END
        ELSE 
            BEGIN
             -- Here is my problem
             set @sql2 = "SELECT * into dbo.''+@inicio+'' FROM valores 
                          WHERE fecha>=FORMAT('''''' + @inicioMes + '''''',''''YYYY-MM-DD'''') 
                          and fecha<FORMAT('''''' + @finMes + '''''',''''YYYY-MM-DD'''')"
             EXECUTE  @sql2
            END
    END

    IF  @inicio = @fin
    BEGIN
        SELECT @inicio
    END
END'

当我尝试执行字符串的SQL内容时,我跳过此错误

  

名称&#39; SELECT * into dbo。&#39; + @ inicio +&#39;来自valores WHERE   fecha&gt; = FORMAT(&#39;&#39;&#39; + @inicioMes +&#39;&#39;&#39;&#39;&#39; YYYY-MM-DD&#39; &#39;)和   出生日期

我试图以某种方式改进报价,但我找不到解决方案。 我做错了什么?

4 个答案:

答案 0 :(得分:0)

您似乎从双引号开始,然后开始使用单引号....

"SELECT * into dbo.''+@inicio+'' 

^ double quote ---Single  ^ quotes

我不认为您可以在此方案中使用双引号,而是使用转义单引号。

在这些情况下,一个好主意是打印生成的sql而不是执行它,然后你可以看到实际上是错误的。即将Execute @ sql2更改为Print(@ Sql2),然后查看实际生成的查询!

答案 1 :(得分:0)

试试这个:

EXEC sp_msForEachDB 'DECLARE @FECHAInicial varchar(50) 
DECLARE @FECHAFinal varchar(50) 
DECLARE @inicio varchar(50) 
DECLARE @fin varchar(50) 
DECLARE @sql varchar(200) 
DECLARE @sql2 varchar(200)  
DECLARE @inicioMes varchar(30) 
DECLARE @finMes varchar(30)

USE ?;

IF EXISTS ( SELECT 1 FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_TYPE=''BASE TABLE'' AND TABLE_NAME=''valores'')
BEGIN
    select DB_NAME() AS [Base de datos usada];

    set @FECHAInicial = (SELECT min(fecha) from valores);
    set @FECHAFinal = (SELECT max(fecha) from valores);
    set @inicio = (SELECT CONCAT(''valores_'', MONTH(@FECHAInicial), ''_'', YEAR(@FECHAInicial)));
    SET @fin = (SELECT CONCAT(''valores_'', MONTH(@FECHAFinal),''_'', YEAR(@FECHAFinal)));

    WHILE @inicio <> @fin
    BEGIN

        SELECT @inicio;
        set @FECHAInicial =  (SELECT DATEADD(month, 1, @FECHAInicial));
        set @inicio = (SELECT CONCAT(''valores_'', MONTH(@FECHAInicial), ''_'', YEAR(@FECHAInicial)));
        set @inicioMes = (SELECT DATEADD(month, DATEDIFF(month, 0, @FECHAInicial), 0))
        set @inicioMes = (select convert(varchar(30), @inicioMes, 120))
        set @finMes = DATEADD(month, ((YEAR(@inicioMes) - 1900) * 12) + MONTH(@inicioMes), -1)
        set @finMes = DATEADD(day, 1, @finMes)

        IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES 
                   WHERE TABLE_TYPE=''BASE TABLE'' AND TABLE_NAME=@inicio) 
            BEGIN
                SELECT 1 AS res 
            END
        ELSE 
            BEGIN
             -- Here is my problem
             set @sql2 = ''SELECT * into dbo.''+@inicio+'' FROM valores 
                          WHERE fecha>=FORMAT('''''' + @inicioMes + '''''',''''YYYY-MM-DD'''') 
                          and fecha<FORMAT('''''' + @finMes + '''''',''''YYYY-MM-DD'''')''
             EXECUTE  @sql2
            END
    END

    IF  @inicio = @fin
    BEGIN
        SELECT @inicio
    END
END'

答案 2 :(得分:0)

调试动态SQL可能具有挑战性。根据上面的答案,你可能有太多的单引号。 (选择之前的第一个引用我意识到是因为整个事情都是引用)。另外,我不确定为什么你需要日期的所有格式命令。如果fecha是一个日期值,你应该能够将它与另一个日期进行比较而不经过所有的格式旋转。另外,我可能建议在sys.databases上使用游标,并且每行返回一次运行@sql2,而不是使用sp_MSforeachdb。它将摆脱额外的报价水平 无论如何,我会把问题分开。

1)不要为所有数据库运行此操作,只需运行一个数据库的代码即可启动。

2)创建格式正确的SELECT语句,而不是使用动态SQL。所以,改为设置@ sql2 ='foo'并执行@sql2,你将只有SELECT * INTO valores_Month,其中'2012/01/01'和'2012/01/31'之间的那些

3)当你有这个工作时,发布简单的Select语句。然后我认为解释所需的单引号数量会更容易。您是否需要这些格式也可能变得清晰。作为另一个提示,当您从工作简单选择转移到动态SQL时,不要试图让每个引用的部分在第一次更正。一次添加一个引用的片段。

答案 3 :(得分:0)

我解决了我的问题。这是一个非常简单的解决方案

EXEC sp_msForEachDB 'DECLARE @FECHAInicial varchar(50) DECLARE @FECHAFinal varchar(50) DECLARE @inicio varchar(50) DECLARE @fin varchar(50) DECLARE @sql varchar(200) DECLARE @sql2 varchar(800)  DECLARE @inicioMes varchar(30) DECLARE @finMes varchar(30)
USE ?; 
IF EXISTS (SELECT 1  FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE=''BASE TABLE'' AND TABLE_NAME=''valores'')
BEGIN
select DB_NAME() AS [Base de datos usada];
    set @FECHAInicial = (SELECT min(fecha) from valores);
    set @FECHAFinal = (SELECT max(fecha) from valores);
    set @inicio = (SELECT CONCAT("valores_", MONTH(@FECHAInicial), "_", YEAR(@FECHAInicial)));
    SET @fin = (SELECT CONCAT("valores_", MONTH(@FECHAFinal),"_", YEAR(@FECHAFinal)));
    WHILE @inicio <> @fin
    BEGIN
        set @FECHAInicial =  (SELECT DATEADD(month, 1, @FECHAInicial));
        set @inicio = (SELECT CONCAT("valores_", MONTH(@FECHAInicial), "_", YEAR(@FECHAInicial)));
        set @inicioMes = (SELECT convert(char(10), DATEADD(month, DATEDIFF(month, 0, @FECHAInicial), 0), 126))
        set @finMes = DATEADD(month, ((YEAR(@inicioMes) - 1900) * 12) + MONTH(@inicioMes), -1)
        set @finMes = (SELECT(convert(char(10), DATEADD(day, 1, @finMes), 126)))
        IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE=''BASE TABLE'' AND TABLE_NAME=@inicio) 
            BEGIN
            select 0
            END
        ELSE 
            BEGIN
             set @sql2 = ''SELECT * into dbo.''+@inicio+'' FROM valores WHERE fecha>= ''''''+@inicioMes +''''''  and fecha< ''''''+ @finMes+''''''''
             select @sql2
            exec(@sql2)

            END
    END
    IF  @inicio = @fin
    BEGIN
        SELECT @inicio
    END
END'

是报价问题。谢谢大家。