2009-09-03 43 views
10

Esto es para SS 2005.Para Nvarchar (Max) ¿Solo estoy obteniendo 4000 caracteres en TSQL?

¿Por qué solo obtengo 4000 caracteres y no 8000?

trunca la cadena @ SQL1 en 4000.

ALTER PROCEDURE sp_AlloctionReport(
    @where NVARCHAR(1000), 
    @alldate NVARCHAR(200), 
    @alldateprevweek NVARCHAR(200)) 
AS 
    DECLARE @SQL1 NVARCHAR(Max) 

    SET @SQL1 = 'SELECT DISTINCT VenueInfo.VenueID, VenueInfo.VenueName, VenuePanels.PanelID, 
    VenueInfo.CompanyName, VenuePanels.ProductCode, VenuePanels.MF, VenueInfo.Address1, 
    VenueInfo.Address2, '' As AllocationDate, '' As AbbreviationCode, VenueInfo.Suburb, VenueInfo.Route, VenueInfo.ContactFirstName, 
    VenueInfo.ContactLastName, VenueInfo.SuitableTime, VenueInfo.OldVenueName, 
    VenueCategories.Category, VenueInfo.Phone, VenuePanels.Location, VenuePanels.Comment, 
    [VenueCategories].[Category] + '' Allocations'' AS ReportHeader, 
    ljs.AbbreviationCode AS PrevWeekCampaign 
    FROM (((VenueInfo INNER JOIN VenuePanels ON VenueInfo.VenueID = VenuePanels.VenueID) 
    INNER JOIN VenueCategories ON VenueInfo.CategoryID = VenueCategories.CategoryID) 
    LEFT JOIN (SELECT CampaignProductions.AbbreviationCode, VenuePanels.PanelID, CampaignAllocations.AllocationDate 
        FROM (((VenueInfo INNER JOIN VenuePanels ON VenueInfo.VenueID=VenuePanels.VenueID) INNER JOIN CampaignAllocations ON VenuePanels.PanelID=CampaignAllocations.PanelID) INNER JOIN CampaignProductions ON CampaignAllocations.CampaignID=CampaignProductions.CampaignID) INNER JOIN VenueCategories ON VenueInfo.CategoryID=VenueCategories.CategoryID 
        WHERE ' + @alldateprevweek + ') ljs 
       ON VenuePanels.PanelID = ljs.PanelID) 
    INNER JOIN (SELECT VenueInfo.VenueID, VenuePanels.PanelID, VenueInfo.VenueName, VenueInfo.CompanyName, VenuePanels.ProductCode, 
       VenuePanels.MF, VenueInfo.Address1, VenueInfo.Address2, CampaignAllocations.AllocationDate, 
       CampaignProductions.AbbreviationCode, VenueInfo.Suburb, VenueInfo.Route, VenueInfo.ContactFirstName, 
       VenueInfo.ContactLastName, VenueInfo.SuitableTime, VenueInfo.OldVenueName, VenueCategories.Category, 
       VenueInfo.Phone, VenuePanels.Location, VenuePanels.Comment, [Category] + '' Allocations'' AS ReportHeader, 
       ljs2.AbbreviationCode AS PrevWeekCampaign 
       FROM ((((VenueInfo INNER JOIN VenuePanels ON VenueInfo.VenueID = VenuePanels.VenueID) 
       INNER JOIN CampaignAllocations ON VenuePanels.PanelID = CampaignAllocations.PanelID) 
       INNER JOIN CampaignProductions ON CampaignAllocations.CampaignID = CampaignProductions.CampaignID) 
       INNER JOIN VenueCategories ON VenueInfo.CategoryID = VenueCategories.CategoryID) 
       LEFT JOIN (SELECT CampaignProductions.AbbreviationCode, VenuePanels.PanelID, CampaignAllocations.AllocationDate 
           FROM (((VenueInfo INNER JOIN VenuePanels ON VenueInfo.VenueID=VenuePanels.VenueID) INNER JOIN CampaignAllocations ON VenuePanels.PanelID=CampaignAllocations.PanelID) INNER JOIN CampaignProductions ON CampaignAllocations.CampaignID=CampaignProductions.CampaignID) INNER JOIN VenueCategories ON VenueInfo.CategoryID=VenueCategories.CategoryID 
           WHERE ' + @alldateprevweek + ') ljs2 
          ON VenuePanels.PanelID = ljs2.PanelID 
       WHERE ' + @alldate + ' AND ' + @where + ') ljs3 
       ON VenueInfo.VenueID = ljs3.VenueID 
    WHERE (((VenuePanels.PanelID)<>ljs3.[PanelID] And 
     (VenuePanels.PanelID) Not In (SELECT PanelID FROM CampaignAllocations WHERE ' + @alldateprevweek + ')) 
     AND ' + @where + ') 
    UNION ALL 
    SELECT VenueInfo.VenueID, VenueInfo.VenueName, VenuePanels.PanelID, VenueInfo.CompanyName, VenuePanels.ProductCode, 
    VenuePanels.MF, VenueInfo.Address1, VenueInfo.Address2, CampaignAllocations.AllocationDate, 
    CampaignProductions.AbbreviationCode, VenueInfo.Suburb, VenueInfo.Route, VenueInfo.ContactFirstName, 
    VenueInfo.ContactLastName, VenueInfo.SuitableTime, VenueInfo.OldVenueName, VenueCategories.Category, 
    VenueInfo.Phone, VenuePanels.Location, VenuePanels.Comment, [Category] + '' Allocations'' AS ReportHeader, 
    ljs.AbbreviationCode AS PrevWeekCampaign 
    FROM ((((VenueInfo INNER JOIN VenuePanels ON VenueInfo.VenueID = VenuePanels.VenueID) 
    INNER JOIN CampaignAllocations ON VenuePanels.PanelID = CampaignAllocations.PanelID) 
    INNER JOIN CampaignProductions ON CampaignAllocations.CampaignID = CampaignProductions.CampaignID) 
    INNER JOIN VenueCategories ON VenueInfo.CategoryID = VenueCategories.CategoryID) 
    LEFT JOIN (SELECT CampaignProductions.AbbreviationCode, VenuePanels.PanelID, CampaignAllocations.AllocationDate 
        FROM (((VenueInfo INNER JOIN VenuePanels ON VenueInfo.VenueID=VenuePanels.VenueID) INNER JOIN CampaignAllocations ON VenuePanels.PanelID=CampaignAllocations.PanelID) INNER JOIN CampaignProductions ON CampaignAllocations.CampaignID=CampaignProductions.CampaignID) INNER JOIN VenueCategories ON VenueInfo.CategoryID=VenueCategories.CategoryID 
        WHERE ' + @alldateprevweek + ') ljs 
       ON VenuePanels.PanelID = ljs.PanelID 
    WHERE ' + @alldate + ' AND ' + @where 

    Select @SQL1 
+0

+1, he resuelto esto usando marcadores de posición para las variables, y luego las reemplazo. – gotqn

+2

Creo que esta es una mejor respuesta a esta pregunta: http://stackoverflow.com/questions/12639948/sql-nvarchar-and-varchar-limits – IHTS

+0

@IHTS Estoy de acuerdo, creo que es mejor si un usuario simplemente get's dirigido a la otra QA. – whytheq

Respuesta

43

Usted ha declarado esto como nvarchar (max) que permite 2 GB de datos por lo que almacenará 2 GB.

Lo que está ocurriendo:

  • El tipo de datos aún no es de tipo nvarchar (max) hasta asignación a @ SQL1
  • Antes de eso, es una colección de cadenas, cada una de menos de 4000 (constants)
  • usted está concatenando constantes cortos con variables cortas (cortas = < 4000)
  • por lo que tiene 4.000 caracteres poner en @ SQL1

Por lo tanto, debe asegurarse de tener nvarchar (max) en el lado derecho.

Una idea. La segunda línea de concatena nvarchar (max) con una constante = nvarchar (max)

SET @SQL1 = '' 
SET @SQL1 = @SQL1 + 'SELECT DISTINCT Venue... 
    .... 

No es diferente a la división de número entero que sucede en cada langauge.

declare @myvar float 
set @myvar = 1/2 --gives zero because it's integer on the right 

La precedencia de operadores (precedencia infiere tipo de datos) es siempre la "asignación" última ... ¿por qué debería Unicode cadenas en SQL Server debe ser diferente?

+1

+1. Me gustaría agregar que puede tener una sola cadena constante de más de 8000 varchar (max) o 4000 nvarchar (max). Pero si son menos de 8000/4000 no serán de la variedad máxima. –

+0

+1 Pero estoy fundando esto muy tonto. Digamos OK para MS, no tiene sentido usar/asignar (MAX) tamaño, en caso de que no lo necesite, pero cuando lo necesite (por ejemplo, el caso anterior, que es mi caso también) es estúpido para mí cortar la cuerda. – gotqn

4

actualización: gbn's comment es correcto, y yo estaba equivocado. Como señala MSDN, nvarchar (max) admite hasta 2^31-1 bytes de datos, almacenados como UCS-2 (2 bytes por carácter, más 2 para la lista de materiales). Su problema parece ser la concatenación de cadenas, no los límites de tipo de datos.

Dicho esto, si lo está utilizando para construir una cadena de SQL, ¿por qué no utilizar VARCHAR? ¿Tiene nombres de campo que no son representables por el conjunto de caracteres nativos de la base de datos (generalmente Latin-1)?

Finalmente, podría simplificar todo su problema simplemente sin usar SQL dinámico en su procedimiento almacenado. Cree algunas funciones con valores de tabla que tomen sus cadenas where-clause y tablas de retorno, y luego ÚNASE a ellas en su procedimiento. Como beneficio adicional, es casi seguro que será mucho más rápido, ya que al menos la base de datos podrá almacenar en caché el cuerpo del SP como una declaración preparada.

+0

Esto no responde a la pregunta: @ sql1 se declara como nvarchar (max) que permite 2 GB. – gbn

+0

@gbn: tienes razón, y he editado mi respuesta. Sin embargo, todavía creo que usar las funciones con valores de tabla es la mejor solución. –

+0

@Daniel: sí, o varchar, o SQL real como mencionaste. – gbn

0

resuelvo un problema basta con incluir el carácter N antes de cada cuerda y problema resuelto por ejemplo

declare @sql nvarchar(max) = '' + @Where + 'SomeThing'; 

debe haber

declare @sql nvarchar(max) = N'' + @Where + N'SomeThing'; 

si se establece la cadena de vaciar también debe establecer N ''

if @where is null 
set @where = N'' 

:-) simple respuesta

Cuestiones relacionadas