2009-09-03 10 views
10

To jest dla SS 2005.Dla Nvarchar (Max) Mam tylko 4000 znaków w TSQL?

Dlaczego mam tylko 4000 znaków, a nie 8000?

To obcina ciąg @ SQL1 w 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, Rozwiązałem to przy użyciu uchwytów dla zmiennych, a następnie je zastępuję. – gotqn

+2

Myślę, że jest to lepsza odpowiedź na to pytanie: http://stackoverflow.com/questions/12639948/sql-nvarchar-and-varchar-limits – IHTS

+0

@IHTS Zgadzam się - myślę, że lepiej jest, jeśli użytkownik po prostu przejdź do drugiej QA. – whytheq

Odpowiedz

43

Użytkownik zadeklarował to jako nvarchar (max), który pozwala na 2 GB danych, więc będzie przechowywać 2 GB.

Co się dzieje:

  • Typ danych nie jest jeszcze nvarchar (max) aż przypisania do @ sql1
  • wcześniej, jest to zbiór ciągów, każda mniej niż 4000 (constants)
  • Jesteś złączenie krótkich stałe z krótkimi zmiennych (krótkie = < 4000)
  • więc trzeba wkładać do 4000 znaków @ sql1

Upewnij się, że masz nvarchar (max) po prawej stronie.

Jedna idea. 2. Linia skleja nvarchar (max) ze stałą = nvarchar (max)

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

to nie różni się od podziału liczby całkowitej, która zachodzi w każdym biuletynie.

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

Operator pierwszeństwo (wnioskuje typ danych pierwszeństwo) jest zawsze "przypisanie" last ... dlaczego Unicode ciągi w SQL Server być inaczej?

+1

+1. Chciałbym dodać, że możesz mieć stałą pojedynczą strunę ponad 8000 varchar (max) lub 4000 nvarchar (max). Ale jeśli są mniejsze niż 8000/4000, nie będą miały maksymalnej różnorodności. –

+0

+1 Ale ja założyłem to bardzo głupio. Powiedzmy, że jest OK dla MS, nie ma sensu używać/alokować (MAX), na wypadek, gdybyś go nie potrzebował, ale kiedy go potrzebujesz (na przykład powyższy przypadek, który jest także moim przypadkiem), to jest głupie dla mnie przeciąć strunę. – gotqn

4

Aktualizacja: gbn's comment ma rację, a ja się myliłem. Jak wskazuje MSDN, nvarchar (max) obsługuje do 2^31-1 bajtów danych, przechowywanych jako UCS-2 (2 bajty na znak, plus 2 dla BOM). Twój problem wydaje się być związany z łączeniem ciągów, a nie ograniczeniami typu danych.

To powiedziawszy, jeśli używasz go do budowania łańcucha SQL, dlaczego nie używać VARCHAR? Czy masz nazwy pól, których nie można przedstawić za pomocą natywnego zestawu znaków bazy danych (zwykle Latin-1)?

Wreszcie - można uprościć cały problem, po prostu nie używając dynamicznego SQL w swojej procedurze przechowywanej. Utwórz funkcje o wartościach tabelarycznych, które przejmują ciągi klauzul where i zwracają tabele, a następnie po prostu JOINuj je w swojej procedurze. Jako bonus prawie na pewno będzie znacznie szybciej, ponieważ przynajmniej baza danych będzie w stanie buforować treść SP jako gotowe oświadczenie.

+0

To nie odpowiada na pytanie: @ sql1 jest zadeklarowane jako nvarchar (max), które pozwalają na 2 GB. – gbn

+0

@ gbn: Masz rację, a ja zredagowałem swoją odpowiedź. Nadal uważam, że używanie funkcji o wartościach tabelarycznych jest tu lepszym rozwiązaniem. –

+0

@Daniel: tak, lub varchar, lub prawdziwy SQL, o którym wspomniałeś. – gbn

0

rozwiązać problemu tylko obejmują N znak przed każdy łańcuch i problem rozwiązany np

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

musi być

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

jeśli ustawić ciąg do opróżnienia również musi ustawić N ''

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

:-) prosta odpowiedź