2009-09-03 3 views
10

Dies ist für SS 2005.Für Nvarchar (Max) bekomme ich nur 4000 Zeichen in TSQL?

Warum bekomme ich nur 4000 Zeichen und nicht 8000?

Es kürzt die Zeichenfolge @ SQL1 bei 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, habe ich dies mit Platzhalter für die Variablen gelöst, und ersetzen Sie sie dann. – gotqn

+2

Ich denke, das ist eine bessere Antwort auf diese Frage: http://stackoverflow.com/questions/12639948/sql-nvarchar-and-varchar-limits – IHTS

+0

@IHTS Ich stimme zu - Ich denke, es ist besser, wenn ein Benutzer nur sich an die andere QA wenden. – whytheq

Antwort

43

Sie haben dies als nvarchar (max) deklariert, was 2 GB Daten ermöglicht, so dass 2 GB gespeichert werden.

Was geschieht:

  • Der Datentyp ist noch nicht nvarchar (max) bis Zuordnung zu @ sql1
  • Davor, es ist eine Sammlung von Zeichenketten, die jeweils weniger als 4000 (constants)
  • Du verketten Sie haben also kurze Konstanten mit kurzen Variablen (kurz = < 4000)
  • 4000 Zeichen in @ setzen sql1

Also, Sie haben sicherstellen, dass Sie Nvarchar (max) auf der rechten Seite haben.

Eine Idee. Die zweite Zeile verkettet nvarchar (max) mit einem konstanten = nvarchar (max)

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

Es ist nicht anders an die Integer-Division, die in jedem Langauge geschieht.

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

Operator Vorrang (folgert Vorrang Datentyp) ist immer "Zuordnung" liest ... warum Strings in SQL Server anders sein Unicode sollte?

+1

+1. Ich möchte hinzufügen, Sie können eine einzelne Zeichenfolge Konstante von mehr als 8000 varchar (max) oder 4000 nvarchar (max) haben. Aber wenn sie weniger als 8000/4000 sind, werden sie nicht von der maximalen Vielfalt sein. –

+0

+1 Aber ich gründe das sehr dumm. Sagen wir OK für MS, es hat keinen Sinn MAX zu verwenden, falls Sie es nicht brauchen, aber wenn Sie es brauchen (zum Beispiel der Fall oben, was auch mein Fall ist), ist es dumm für mich um die Schnur zu schneiden. – gotqn

4

aktualisieren: gbn's comment richtig ist, und ich war falsch. Wie MSDN hervorhebt, unterstützt nvarchar (max) bis zu 2^31-1 Bytes an Daten, die als UCS-2 gespeichert werden (2 Bytes pro Zeichen plus 2 für BOM). Ihr Problem scheint mit String-Verkettung zu sein, nicht mit Datentypgrenzen.

Das heißt, wenn Sie es verwenden, um eine SQL-Zeichenfolge zu erstellen, warum VARCHAR nicht verwenden? Haben Sie Feldnamen, die nicht vom nativen Zeichensatz der Datenbank dargestellt werden können (normalerweise Latin-1)?

Schließlich - Sie könnten Ihr gesamtes Problem vereinfachen, indem Sie einfach nicht dynamisches SQL in Ihrer gespeicherten Prozedur verwenden. Erstellen Sie einige Tabellenwertfunktionen, die Ihre Where-Klauselzeichenfolgen und Rückgabetabellen übernehmen, und verknüpfen Sie sie dann einfach in Ihrer Prozedur. Als Bonus wird es mit ziemlicher Sicherheit viel schneller sein, da zumindest die Datenbank den SP-Körper als vorbereitete Aussage zwischenspeichern kann.

+0

Dies beantwortet nicht die Frage: @ sql1 wird als nvarchar (max) deklariert, die 2 GB erlauben. – gbn

+0

@gbn: Sie haben Recht, und ich habe meine Antwort bearbeitet. Ich denke immer noch, dass die Verwendung von Tabellenwerten hier die bessere Lösung ist. –

+0

@Daniel: Ja, oder Varchar, oder echte SQL wie du erwähnt. – gbn

0

i Problem beheben sind nur Zeichen N vor jeder Zeichenfolge und Problem zum Beispiel gelöst

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

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

sein müssen, wenn Sie Zeichenfolge festgelegt auch leeren muss N gesetzt ''

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

:-) einfache Antwort