W jaki sposób można wywołać procedurę składowaną dla każdego wiersza w tabeli, w której kolumny wiersza są parametrami wejściowymi do sp bez użycia kursora?
sql
sql-server
stored-procedures
cursor
Johannes Rudolph
źródło
źródło
Odpowiedzi:
Ogólnie rzecz biorąc, zawsze szukam podejścia opartego na zbiorach (czasami kosztem zmiany schematu).
Jednak ten fragment ma swoje miejsce.
źródło
Możesz zrobić coś takiego: zamów swoją tabelę, np. CustomerID (używając
Sales.Customer
przykładowej tabeli AdventureWorks ) i iteruj po tych klientach, używając pętli WHILE:To powinno działać z każdą tabelą, o ile możesz zdefiniować jakiś rodzaj
ORDER BY
w jakiejś kolumnie.źródło
Ok, więc nigdy bym nie wprowadził takiego kodu do produkcji, ale spełnia on Twoje wymagania.
źródło
Odpowiedź Marca jest dobra (skomentowałbym ją, gdybym mógł wymyślić, jak to zrobić!)
Pomyślałem, że wskazałbym, że może lepiej zmienić pętlę, aby
SELECT
jedyna istniała raz (w prawdziwym przypadku, gdy musiałem zrobić to,SELECT
było dość skomplikowane, a dwukrotne napisanie go było ryzykownym problemem związanym z konserwacją).źródło
Jeśli możesz przekształcić procedurę składowaną w funkcję zwracającą tabelę, możesz użyć zastosowania krzyżowego.
Na przykład, załóżmy, że masz tabelę klientów i chcesz obliczyć sumę ich zamówień, utworzysz funkcję, która pobierze CustomerID i zwróci sumę.
Możesz to zrobić:
Gdzie funkcja wyglądałaby tak:
Oczywiście powyższy przykład można wykonać bez funkcji zdefiniowanej przez użytkownika w pojedynczym zapytaniu.
Wadą jest to, że funkcje są bardzo ograniczone - wiele funkcji procedury składowanej nie jest dostępnych w funkcji zdefiniowanej przez użytkownika, a konwertowanie procedury składowanej na funkcję nie zawsze działa.
źródło
Użyłbym akceptowanej odpowiedzi, ale inną możliwością jest użycie zmiennej tabeli do przechowywania ponumerowanego zestawu wartości (w tym przypadku tylko pola ID tabeli) i przechodzenie przez te według numeru wiersza z JOIN do tabeli, aby pobierz wszystko, czego potrzebujesz do działania w pętli.
źródło
W przypadku SQL Server 2005 i nowszych można to zrobić za pomocą CROSS APPLY i funkcji wycenianej w tabeli.
Dla jasności odnoszę się do tych przypadków, w których procedura składowana może zostać przekonwertowana na funkcję wartościowaną w tabeli.
źródło
To jest odmiana powyższego rozwiązania n3rds. Nie jest potrzebne sortowanie za pomocą ORDER BY, ponieważ używana jest funkcja MIN ().
Pamiętaj, że ID klienta (lub jakakolwiek inna kolumna liczbowa, której używasz do postępu) musi mieć unikalne ograniczenie. Ponadto, aby było to tak szybkie, jak to możliwe CustomerID musi być indeksowane.
Używam tego podejścia na niektórych varcharach, które muszę przejrzeć, umieszczając je najpierw w tabeli tymczasowej, aby nadać im identyfikator.
źródło
Jeśli nie wiesz, czego użyć kursora, myślę, że będziesz musiał to zrobić zewnętrznie (pobierz tabelę, a następnie uruchom dla każdej instrukcji i za każdym razem wywołaj sp) to jest to samo, co użycie kursora, ale tylko na zewnątrz SQL. Dlaczego nie użyjesz kursora?
źródło
Jest to odmiana udzielonych już odpowiedzi, ale powinna być skuteczniejsza, ponieważ nie wymaga ORDER BY, COUNT ani MIN / MAX. Jedyną wadą tego podejścia jest to, że musisz utworzyć tabelę tymczasową do przechowywania wszystkich identyfikatorów (założenie jest takie, że masz luki na liście IDklientów).
To powiedziawszy, zgadzam się z @Mark Powell, chociaż, ogólnie rzecz biorąc, podejście oparte na zestawie powinno być nadal lepsze.
źródło
Zwykle robię to w ten sposób, gdy jest kilka rzędów:
(W przypadku większych zbiorów danych użyłbym jednak jednego z wyżej wymienionych rozwiązań).
źródło
DELIMITER //
źródło
Lepszym rozwiązaniem jest
To był czysty wynik w formacie tabeli. Chociaż jeśli uruchomisz SP dla każdego wiersza, otrzymasz oddzielny wynik zapytania dla każdej iteracji, co jest brzydkie.
źródło
Na wypadek, gdyby kolejność była ważna
źródło
Miałem kod produkcyjny, który mógł obsługiwać tylko 20 pracowników jednocześnie, poniżej znajduje się struktura kodu. Właśnie skopiowałem kod produkcyjny i usunąłem rzeczy poniżej.
źródło
Lubię robić coś podobnego do tego (chociaż nadal jest to bardzo podobne do używania kursora)
[kod]
[/kod]
Zauważ, że nie potrzebujesz tożsamości ani kolumny isIterated w tabeli temp / variable, po prostu wolę to zrobić w ten sposób, aby nie musieć usuwać najwyższego rekordu z kolekcji podczas iteracji w pętli.
źródło