2016-04-13 40 views
5

Mam podchwytliwe, płaskie źródło danych pliku. Dane są pogrupowane w następujący sposób:
Jak załadować zgrupowane dane za pomocą SSIS

Country City 
U.S.  New York 
      Washington 
      Baltimore 
Canada  Toronto 
      Vancouver 

Ale chcę go mieć ten format, gdy jest załadowany do bazy danych:

Country City 
U.S.  New York 
U.S.  Washington 
U.S.  Baltimore 
Canada  Toronto 
Canada  Vancouver 

ktoś spotkał taki problem wcześniej? Masz pomysł, żeby sobie z tym poradzić?
Jedyny pomysł, jaki mam teraz, to użycie kursora, ale jest zbyt wolny.
Dziękujemy!

+0

jeśli nie masz innej kolumny, np. Id, aby pomóc w ustaleniu, do którego kraju należą te miasta, niemożliwe jest, aby DBMS dostał to, czego potrzebujesz. ponieważ nie są w porządku. –

Odpowiedz

3

odpowiedź przez cha będzie działać, ale tu jest inny w przypadku trzeba zrób to w SSIS wit tabele tymczasowe/pomostowe:

Przepływ danych można uruchomić za pomocą transformacji skryptu, która używa zmiennej poziomu DataFlow. Gdy każdy wiersz pojawia się w skrypcie, sprawdza wartość kolumny Kraj.

Jeśli ma niepustą wartość, należy wypełnić zmienną tą wartością i przekazać ją w przepływie danych.

Jeśli kraj ma pustą wartość, należy nadpisać ją wartością zmiennej, która będzie ostatnią niewypełnioną wartością krajową, którą otrzymałeś.

EDIT: Spojrzałem w górę swój komunikat o błędzie i dowiedział się czegoś nowego o Script Components (narzędzie przepływ danych, w przeciwieństwie do zadań skrypcie Narzędzie Kontrola przepływu):

Zbiór ReadWriteVariables jest dostępna tylko w metodzie PostExecute , aby zmaksymalizować wydajność i zminimalizować ryzyko konfliktów blokujących. Dlatego nie można bezpośrednio zwiększać wartości zmiennej pakietowej o wartość podczas przetwarzania każdego wiersza danych.Zamiast tego należy zwiększyć wartość zmiennej lokalnej o wartość i ustawić wartość zmiennej pakietu na wartość zmiennej lokalnej w metodzie PostExecute po przetworzeniu wszystkich danych. Można również użyć właściwości VariableDispenser zmiennej , aby obejść to ograniczenie, jako opisanej w dalszej części tego tematu. Jednak pisanie bezpośrednio do zmiennej pakietu podczas przetwarzania każdego wiersza będzie miało negatywny wpływ na wydajność i zwiększy ryzyko konfliktów blokujących.

który pochodzi z this MSDN article, który ma również więcej informacji o zmiennej Dozowniki obejście, jeśli chcesz iść tą drogą, ale widocznie ja cię zwodzić powyżej, kiedy powiedział, że można ustawić wartość zmiennej pakiet w skrypcie. Musisz użyć zmiennej, która jest lokalna dla skryptu, a następnie zmienić ją w module obsługi zdarzeń Post-Execute. Nie mogę stwierdzić na podstawie artykułu, czy oznacza to, że nie będziesz w stanie odczytać zmiennej w skrypcie, a jeśli tak jest, to Dozownik Zmienny będzie jedyną opcją. Lub przypuszczam, że można utworzyć inną zmienną, do której skrypt będzie miał dostęp tylko do odczytu, i ustawić jej wartość na wyrażenie, tak aby zawsze miała wartość zmiennej do odczytu i zapisu. To może zadziałać.

+0

Dziękuję kolego. Próbowałem używać Cursora, który moim zdaniem jest podobny do twojego pomysłu. Ale tak naprawdę mam 20k + wiersze, więc uruchamianie rząd po rzędzie jest po prostu zbyt wolne ...... –

+0

OK, próbowałem twojej metody, ale zawsze otrzymałem komunikat o błędzie "Zbiór zmiennych zablokowany do odczytu i zapisu nie jest dostępny poza PostExecute ". Ale umieszczam zmiennej przypisania w PostExecute ....... znak, nie wiem, co poszło nie tak. Dzięki –

+0

Może nie wolno ci czytać zmiennej ReadWrite w skrypcie. Poprawiłem moją odpowiedź kilkoma nowymi informacjami, których się nauczyłem. –

3

Tak, jest to możliwe. Najpierw trzeba załadować dane do tabeli z kolumną Tożsamość:

-- drop table #t 
CREATE TABLE #t (id INTEGER IDENTITY PRIMARY KEY, 
Country VARCHAR(20), 
City VARCHAR(20)) 

INSERT INTO #t(Country, City) 
SELECT a.Country, a.City 
FROM OPENROWSET(BULK 'c:\import.txt', 
    FORMATFILE = 'c:\format.fmt', 
    FIRSTROW = 2) AS a; 

select * from #t 

Rezultatem będzie:

id   Country    City 
----------- -------------------- -------------------- 
1   U.S.     New York 
2        Washington 
3        Baltimore 
4   Canada    Toronto 
5        Vancouver 

A teraz z odrobiną rekurencyjnej CTE magii można wypełnić brakujące dane:

;WITH a as(
    SELECT Country 
      ,City 
      ,ID 
    FROM #t WHERE ID = 1 
    UNION ALL 
    SELECT COALESCE(NULLIF(LTrim(#t.Country), ''),a.Country) 
      ,#t.City 
      ,#t.ID 
    FROM a INNER JOIN #t ON a.ID+1 = #t.ID 
    ) 
SELECT * FROM a 
OPTION (MAXRECURSION 0) 

Wynik:

Country    City     ID 
-------------------- -------------------- ----------- 
U.S.     New York    1 
U.S.     Washington   2 
U.S.     Baltimore   3 
Canada    Toronto    4 
Canada    Vancouver   5 

Aktualizacja:

Jak Tab Alleman sugerowane poniżej ten sam rezultat można osiągnąć bez zapytania rekurencyjnego:

SELECT ID 
    , COALESCE(NULLIF(LTrim(a.Country), ''), (SELECT TOP 1 Country FROM #t t WHERE t.ID < a.ID AND LTrim(t.Country) <> '' ORDER BY t.ID DESC)) 
    , City 
FROM #t a 

BTW, format pliku dla danych wejściowych jest to (jeśli chcesz spróbować skrypty zapisać dane wejściowe jako C: \ import.txt i plik formatu poniżej jako c: \ format.fmt):

9.0 
    2 
    1  SQLCHAR  0  11  ""  1  Country  SQL_Latin1_General_CP1_CI_AS 
    2  SQLCHAR  0  100  "\r\n" 2  City   SQL_Latin1_General_CP1_CI_AS 
+0

Dzięki cha. Wypróbowałem twój pomysł, ale nie zadziałało to w moim przypadku. Ponieważ w rzeczywistości mam 20k + wiersze w moim stole. Pojawił się błąd, mówiąc coś w stylu "CTE powtarza się ponad 100 razy". –

+0

Możesz użyć samołączenia zamiast rekurencyjnego CTE, aby uniknąć ograniczenia rekursji. –

+0

Dzięki @TabAlleman. Zaktualizowałem swoją odpowiedź, aby dołączyć wersję bez rekurencji – cha