Jak sparametryzować zapytanie zawierające IN
klauzulę o zmiennej liczbie argumentów, na przykład ten?
SELECT * FROM Tags
WHERE Name IN ('ruby','rails','scruffy','rubyonrails')
ORDER BY Count DESC
W tym zapytaniu liczba argumentów może wynosić od 1 do 5.
Wolałbym nie używać dedykowanej procedury składowanej do tego (lub XML), ale jeśli istnieje jakiś elegancki sposób specyficzny dla SQL Server 2008 , jestem na to otwarty.
sql
sql-server
parameters
Jeff Atwood
źródło
źródło
Odpowiedzi:
Oto szybka i brudna technika, której użyłem:
Oto kod C #:
Dwa zastrzeżenia:
LIKE "%...%"
zapytania nie są indeksowane.|
pustych lub pustych tagów , bo to nie zadziałaIstnieją inne sposoby osiągnięcia tego celu, które niektórzy mogą uznać za czystsze, więc czytaj dalej.
źródło
Możesz sparametryzować każdą wartość, więc coś takiego:
Co da ci:
Nie, to nie jest otwarte na iniekcję SQL . Jedyny wstrzyknięty tekst do CommandText nie jest oparty na danych wprowadzonych przez użytkownika. Opiera się wyłącznie na zapisanym na stałe prefiksie „@tag” i indeksie tablicy. Indeks zawsze będzie liczbą całkowitą, nie będzie generowany przez użytkownika i jest bezpieczny.
Wprowadzane przez użytkownika wartości są nadal upakowane w parametry, więc nie ma tam żadnej luki w zabezpieczeniach.
Edytować:
Nie jest tak, że buforowane plany zapytań nie są cenne, ale IMO to zapytanie nie jest wystarczająco skomplikowane, aby zobaczyć z niego wiele korzyści. Podczas gdy koszty kompilacji mogą zbliżać się (a nawet przekraczać) koszty wykonania, wciąż mówisz o milisekundach.
Jeśli masz wystarczającą ilość pamięci RAM, spodziewałbym się, że SQL Server prawdopodobnie buforuje również plan dla wspólnej liczby parametrów. Przypuszczam, że zawsze można dodać pięć parametrów i pozwolić, aby nieokreślone tagi miały wartość NULL - plan zapytań powinien być taki sam, ale wydaje mi się to dość brzydkie i nie jestem pewien, czy warto mikrooptymalizacji (chociaż na przepełnieniu stosu - może być tego warte).
Ponadto SQL Server 7 i nowsze wersje automatycznie parametryzują zapytania , więc używanie parametrów nie jest tak naprawdę konieczne z punktu widzenia wydajności - jest to jednak krytyczne z punktu widzenia bezpieczeństwa - szczególnie w przypadku danych wprowadzanych przez użytkownika w ten sposób.
źródło
W przypadku SQL Server 2008 można użyć parametru o wartości tabeli . To trochę pracy, ale jest prawdopodobnie czystsze niż moja inna metoda .
Najpierw musisz utworzyć typ
Następnie kod ADO.NET wygląda następująco:
źródło
SELECT * FROM tags WHERE tags.name IN (SELECT name from @tvp);
? Teoretycznie powinno to być najszybsze podejście. Możesz użyć odpowiednich indeksów (np. Indeks nazwy znacznika, któryINCLUDE
byłby idealny), a SQL Server powinien robić kilka prób, aby pobrać wszystkie znaczniki i ich liczbę. Jak wygląda plan?Pierwotne pytanie brzmiało: „Jak sparametryzować zapytanie ...”
Pozwolę sobie stwierdzić, że nie jest to odpowiedź na pierwotne pytanie. Istnieją już pewne tego dowody w innych dobrych odpowiedziach.
Mając to na uwadze, śmiało zaznaczaj tę odpowiedź, głosuj na nią, oznacz ją jako brak odpowiedzi ... rób wszystko, co uważasz za słuszne.
Zobacz odpowiedź Marka Bracketta na preferowaną odpowiedź, którą głosowałem (i 231 innych osób). Podane w jego odpowiedzi podejście pozwala 1) na efektywne wykorzystanie zmiennych wiązania i 2) na predykaty, które są podatne na kalkulację.
Wybrana odpowiedź
Chciałbym się tutaj zająć podejściem podanym w odpowiedzi Joela Spolsky'ego, odpowiedź „wybrana” jako właściwa odpowiedź.
Podejście Joela Spolsky'ego jest sprytne. I działa rozsądnie, będzie wykazywać przewidywalne zachowanie i przewidywalną wydajność, biorąc pod uwagę „normalne” wartości, a także z normatywnymi przypadkami krawędzi, takimi jak NULL i pusty ciąg. I może być wystarczające dla konkretnego zastosowania.
Ale jeśli chodzi o uogólnienie tego podejścia, rozważmy również bardziej niejasne przypadki narożników, na przykład gdy
Name
kolumna zawiera znak wieloznaczny (rozpoznawany przez predykat LIKE). Najczęściej stosowanym znakiem wieloznacznym jest%
znakiem (znak procentu.). Zajmijmy się tym teraz, a później przejdźmy do innych spraw.Niektóre problemy ze znakiem%
Rozważ wartość nazwy
'pe%ter'
. (W podanych tu przykładach zamiast nazwy kolumny używam literału). Wiersz o wartości nazwy `` pe% ter '' zostanie zwrócony przez zapytanie o formę:Ale ten sam wiersz nie zostanie zwrócony, jeśli kolejność wyszukiwanych haseł zostanie odwrócona:
Zachowanie, które obserwujemy, jest dość dziwne. Zmiana kolejności wyszukiwanych haseł na liście zmienia zestaw wyników.
To prawie oczywiste, że możemy nie chcieć
pe%ter
dopasowywać masła orzechowego, bez względu na to, jak bardzo to lubi.Niewyraźna obudowa narożna
(Tak, zgodzę się, że jest to niejasny przypadek. Prawdopodobnie taki, który prawdopodobnie nie zostanie przetestowany. Nie spodziewalibyśmy się znaku wieloznacznego w wartości kolumny. Możemy założyć, że aplikacja zapobiega przechowywaniu takiej wartości. Ale z mojego doświadczenia rzadko widziałem ograniczenie bazy danych, które wyraźnie zabraniało znaków lub wzorców, które byłyby uważane za symbole wieloznaczne po prawej stronie
LIKE
operatora porównania.Łatanie dziury
Jednym ze sposobów na załatanie tej dziury jest uniknięcie
%
znaku wieloznacznego. (Dla każdego, kto nie zna klauzuli Escape na operatorze, oto link do dokumentacji SQL Server .Teraz możemy dopasować dosłowny%. Oczywiście, kiedy będziemy mieli nazwę kolumny, będziemy musieli dynamicznie uciec od znaku wieloznacznego. Możemy użyć tej
REPLACE
funkcji, aby znaleźć wystąpienia%
znaku i wstawić przed każdym odwrotnym ukośnikiem:To rozwiązuje problem z% wildcard. Prawie.
Uciec ucieczki
Zdajemy sobie sprawę, że nasze rozwiązanie wprowadziło kolejny problem. Postać ucieczki. Widzimy, że będziemy również musieli uciec przed wszelkimi przypadkami samej postaci ucieczki. Tym razem korzystamy z! jako postać ucieczki:
Podkreślenie też
Teraz, gdy jesteśmy na rzucie, możemy dodać kolejny
REPLACE
uchwyt znaku wieloznacznego podkreślenia. I dla zabawy, tym razem użyjemy $ jako postaci ucieczki.Wolę to podejście od ucieczki, ponieważ działa w Oracle i MySQL oraz SQL Server. (Zazwyczaj używam ukośnika odwrotnego \ jako znaku ucieczki, ponieważ jest to znak, którego używamy w wyrażeniach regularnych. Ale po co ograniczać się konwencją!
Te nieznośne nawiasy
SQL Server pozwala również traktować znaki wieloznaczne jako literały, umieszczając je w nawiasach
[]
. Więc nie skończyliśmy jeszcze naprawiania, przynajmniej dla SQL Server. Ponieważ pary nawiasów mają specjalne znaczenie, musimy również uciec przed nimi. Jeśli uda nam się odpowiednio uciec od nawiasów, to przynajmniej nie będziemy musieli zawracać sobie głowy łącznikiem-
i karatem^
w nawiasach. I możemy zostawić każdego%
i_
znaków wewnątrz nawiasów uciekł, ponieważ będziemy mieli w zasadzie wyłączone specjalnego znaczenia nawiasów.Znalezienie pasujących par nawiasów nie powinno być takie trudne. Jest to trochę trudniejsze niż radzenie sobie z wystąpieniem singletonu% i _. (Zauważ, że nie wystarczy po prostu uciec od wszystkich wystąpień nawiasów, ponieważ nawias singletonowy jest uważany za dosłowny i nie trzeba go uciekać. Logika staje się nieco bardziej niewyraźna niż mogę obsłużyć więcej testów .)
Wyrażenie wbudowane staje się nieporządne
To wyrażenie wbudowane w SQL staje się dłuższe i brzydsze. Prawdopodobnie możemy sprawić, by działało, ale niebo pomoże biednej duszy, która za nią stoi i musi ją rozszyfrować. Ponieważ jestem fanem wyrażeń wbudowanych, nie jestem skłonny do używania go tutaj, głównie dlatego, że nie chcę zostawiać komentarza wyjaśniającego przyczynę bałaganu i przepraszającego za to.
Funkcja gdzie?
Ok, więc jeśli nie będziemy traktować tego jako wyrażenia wbudowanego w SQL, najbliższą alternatywą, jaką mamy, jest funkcja zdefiniowana przez użytkownika. I wiemy, że to niczego nie przyspieszy (chyba że możemy zdefiniować na nim indeks, tak jak moglibyśmy to zrobić z Oracle.) Jeśli musimy stworzyć funkcję, lepiej to zrobić w kodzie wywołującym SQL komunikat.
Ta funkcja może mieć pewne różnice w zachowaniu, zależne od DBMS i wersji. (Pozdrawiam wszystkich programistów Java, którzy tak chętnie korzystają z dowolnego silnika bazy danych zamiennie).
Znajomość domen
Możemy mieć specjalistyczną wiedzę na temat domeny dla kolumny (tj. Zestawu dopuszczalnych wartości wymuszonych dla kolumny. Możemy z góry wiedzieć, że wartości przechowywane w kolumnie nigdy nie będą zawierały znaku procentu, podkreślenia lub nawiasu pary. W takim przypadku zamieszczamy tylko krótki komentarz, że te przypadki są objęte gwarancją.
Wartości przechowywane w kolumnie mogą zezwalać na znaki% lub _, ale ograniczenie może wymagać zmiany tych wartości, być może przy użyciu określonego znaku, tak aby wartości LIKE były „bezpieczne”. Ponownie, szybki komentarz na temat dozwolonego zestawu wartości, a zwłaszcza tego, która postać jest używana jako postać ucieczki, i podejdź do podejścia Joela Spolsky'ego.
Ale bez specjalistycznej wiedzy i gwarancji ważne jest, abyśmy przynajmniej rozważyli obsługę tych niejasnych narożnych spraw i zastanowili się, czy zachowanie jest rozsądne i „zgodne ze specyfikacją”.
Inne problemy podsumowano
Uważam, że inni już w wystarczającym stopniu wskazali niektóre z innych powszechnie rozważanych obszarów zainteresowania:
Wstrzykiwanie SQL (przyjmowanie informacji, które wydają się być informacjami dostarczonymi przez użytkownika, i uwzględnianie ich w tekście SQL zamiast dostarczania ich przez zmienne powiązania. Używanie zmiennych powiązania nie jest wymagane, jest to tylko jedno wygodne podejście do udaremnienia za pomocą wstrzykiwania SQL. Istnieją inne sposoby radzenia sobie z tym:
plan optymalizacyjny wykorzystujący skanowanie indeksów zamiast przeszukiwania indeksów, możliwa potrzeba wyrażenia lub funkcji do ucieczki symboli wieloznacznych (możliwy indeks wyrażenia lub funkcji)
użycie wartości literalnych zamiast zmiennych powiązań wpływa na skalowalność
Wniosek
Lubię podejście Joela Spolsky'ego. To sprytne. I to działa.
Ale gdy tylko to zobaczyłem, natychmiast zobaczyłem potencjalny problem z tym i nie jest moją naturą pozwolić mu się ześlizgnąć. Nie chcę krytykować wysiłków innych. Wiem, że wielu programistów traktuje swoją pracę bardzo osobiście, ponieważ tyle w nią inwestują i tak bardzo się o nią troszczą. Proszę więc zrozumieć, że to nie jest osobisty atak. To, co tu identyfikuję, to rodzaj problemu, który pojawia się w produkcji, a nie podczas testowania.
Tak, odszedłem daleko od pierwotnego pytania. Ale gdzie jeszcze zostawić tę notatkę dotyczącą tego, co uważam za ważny problem z „wybraną” odpowiedzią na pytanie?
źródło
Możesz przekazać parametr jako ciąg
Więc masz ciąg
Następnie wystarczy przekazać ciąg jako 1 parametr.
Oto funkcja podziału, której używam.
źródło
Słyszałem, jak Jeff / Joel rozmawia o tym dzisiaj w podcastie ( odcinek 34 , 2008-12-16 (MP3, 31 MB), 1 godz. 03 min 38 sek. - 1 godz. 06 min 45 sek.) I pomyślałem, że przypomniałem sobie przepełnienie stosu używał LINQ do SQL , ale może został porzucony. To samo dotyczy LINQ to SQL.
Otóż to. I tak, LINQ spogląda już wystarczająco wstecz, ale
Contains
klauzula wydaje mi się dodatkowa wstecz. Kiedy musiałem wykonać podobne zapytanie dla projektu w pracy, naturalnie próbowałem zrobić to w niewłaściwy sposób, łącząc tablicę lokalną z tabelą SQL Server, stwierdzając, że translator LINQ na SQL byłby wystarczająco inteligentny, aby obsłużyć tłumaczenie jakoś. Nie zrobił tego, ale dostarczył opisowy komunikat o błędzie i skierował mnie do korzystania z Contains .W każdym razie, jeśli uruchomisz to w wysoce zalecanym LINQPad i uruchomisz tę kwerendę, możesz wyświetlić rzeczywisty kod SQL wygenerowany przez dostawcę SQL LINQ. Pokaże ci każdą wartość sparametryzowaną w
IN
klauzulę.źródło
Jeśli dzwonisz z .NET, możesz użyć Dapper dot net :
Tutaj Dapper myśli, więc nie musisz. Oczywiście w LINQ-SQL możliwe jest coś podobnego :
źródło
Jest to prawdopodobnie w połowie paskudny sposób, użyłem go raz, był raczej skuteczny.
W zależności od celów może się przydać.
INSERT
każda wartość wyszukiwania w tej kolumnie.IN
, możesz po prostu użyć standardowychJOIN
reguł. (Elastyczność ++)Daje to dodatkową elastyczność w zakresie tego, co możesz zrobić, ale bardziej nadaje się do sytuacji, w których masz dużą tabelę do zapytania, z dobrym indeksowaniem i chcesz użyć sparametryzowanej listy więcej niż jeden raz. Oszczędza to konieczności wykonywania go dwa razy i ręcznego wykonywania wszystkich warunków sanitarnych.
Nigdy nie zajmowałem się profilowaniem dokładnie tego, jak szybko było, ale w mojej sytuacji było to potrzebne.
źródło
W
SQL Server 2016+
można użyćSTRING_SPLIT
funkcji:lub:
LiveDemo
Akceptowane odpowiedź wola oczywiście pracy i jest to jeden do zrobienia, ale to jest anty-wzór.
Dodatek :
Aby poprawić
STRING_SPLIT
oszacowanie wiersza funkcji tabeli, dobrym pomysłem jest zmaterializowanie podzielonych wartości jako tymczasowych zmiennych tabeli / tabeli:SEDE - Live Demo
Powiązane: Jak przekazać listę wartości do procedury przechowywanej
Oryginalne pytanie ma wymóg
SQL Server 2008
. Ponieważ to pytanie jest często używane jako duplikat, dodałem tę odpowiedź jako odniesienie.źródło
Mamy funkcję, która tworzy zmienną tabelową, do której możesz dołączyć:
Więc:
źródło
Jest to obrzydliwe, ale jeśli masz gwarancję co najmniej jednego, możesz:
Posiadanie IN („tag1”, „tag2”, „tag1”, „tag1”, „tag1”) będzie łatwo zoptymalizowane przez SQL Server. Dodatkowo otrzymujesz bezpośrednie wyszukiwanie indeksu
źródło
Moim zdaniem najlepszym źródłem rozwiązania tego problemu jest to, co zostało opublikowane na tej stronie:
Syscomments. Dinakar Nethi
Posługiwać się:
KREDYTY DLA: Dinakar Nethi
źródło
Przekazałbym parametr typu tabeli (ponieważ jest to SQL Server 2008 ) i
where exists
wykonałbym połączenie wewnętrzne. Możesz także użyć XML, używającsp_xml_preparedocument
, a następnie nawet zindeksować tę tabelę tymczasową.źródło
Prawidłowym sposobem IMHO jest przechowywanie listy w ciągu znaków (ograniczona długością przez obsługę DBMS); jedyną sztuczką jest to, że (w celu uproszczenia przetwarzania) mam separator (w moim przykładzie przecinek) na początku i na końcu łańcucha. Chodzi o „normalizację w locie”, przekształcenie listy w tabelę z jedną kolumną zawierającą jeden wiersz na wartość. To pozwala ci skręcić
w
lub (rozwiązanie, które prawdopodobnie wolałbym) zwykłe łączenie, jeśli dodasz „odrębny”, aby uniknąć problemów ze zduplikowanymi wartościami na liście.
Niestety techniki cięcia sznurka są dość specyficzne dla produktu. Oto wersja SQL Server:
Wersja Oracle:
oraz wersja MySQL:
(Oczywiście „pivot” musi zwrócić tyle wierszy, ile maksymalna liczba elementów, jakie możemy znaleźć na liście)
źródło
Jeśli masz program SQL Server 2008 lub nowszy, użyłbym parametru wycenionego w tabeli .
Jeśli masz pecha, aby utknąć w programie SQL Server 2005, możesz dodać taką funkcję CLR ,
Którego możesz użyć w ten sposób,
źródło
Myślę, że jest to przypadek, gdy zapytanie statyczne po prostu nie jest dobrym rozwiązaniem. Dynamicznie twórz listę klauzul in, unikaj pojedynczych cudzysłowów i dynamicznie buduj SQL. W tym przypadku prawdopodobnie nie zobaczysz żadnej różnicy z żadną metodą ze względu na małą listę, ale najbardziej wydajną metodą jest naprawdę wysłanie SQL dokładnie tak, jak jest napisany w poście. Myślę, że dobrym zwyczajem jest pisanie go w najbardziej efektywny sposób, zamiast robić to, co czyni najładniejszy kod, lub uważać za złą praktykę dynamiczne budowanie SQL.
Widziałem, że wykonywanie funkcji podziału trwa dłużej niż samo zapytanie w wielu przypadkach, gdy parametry stają się duże. Procedura przechowywana z parametrami o wartościach przechowywanych w tabeli w SQL 2008 to jedyna inna opcja, którą bym rozważył, chociaż prawdopodobnie będzie ona wolniejsza w twoim przypadku. TVP będzie prawdopodobnie szybsze tylko dla dużych list, jeśli szukasz klucza podstawowego TVP, ponieważ SQL i tak zbuduje tymczasową tabelę dla listy (jeśli lista jest duża). Nie będziesz tego pewien, chyba że go przetestujesz.
Widziałem również procedury składowane, które miały 500 parametrów z domyślnymi wartościami null i posiadały GDZIE Kolumna1 IN (@ Param1, @ Param2, @ Param3, ..., @ Param500). Spowodowało to, że SQL zbudował tabelę tymczasową, wykonał sortowanie / odrębne, a następnie wykonał skanowanie tabeli zamiast przeszukiwania indeksu. Zasadniczo to robiłbyś, parametryzując to zapytanie, chociaż na tyle małą skalę, że nie zrobi to zauważalnej różnicy. Zdecydowanie odradzam wpisywanie NULL na twoich listach IN, ponieważ jeśli zostanie to zmienione na NOT IN, nie będzie działać zgodnie z przeznaczeniem. Możesz dynamicznie budować listę parametrów, ale jedyną oczywistą rzeczą, którą zyskasz, jest to, że obiekty unikną za ciebie pojedynczych cudzysłowów. Takie podejście jest również nieco wolniejsze po stronie aplikacji, ponieważ obiekty muszą przeanalizować zapytanie, aby znaleźć parametry.
Ponowne użycie planów wykonania dla procedur przechowywanych lub sparametryzowanych zapytań może dać ci wzrost wydajności, ale zablokuje cię w jednym planie wykonania określonym przez pierwsze wykonywane zapytanie. W wielu przypadkach może to być mniej niż idealne dla kolejnych zapytań. W twoim przypadku ponowne użycie planów wykonania będzie prawdopodobnie plusem, ale może nie mieć żadnej różnicy, ponieważ przykład jest naprawdę prostym zapytaniem.
Fiszki:
W twoim przypadku cokolwiek robisz, czy to parametryzacja ze stałą liczbą elementów na liście (null, jeśli nie jest używana), dynamiczne budowanie zapytania z parametrami lub bez parametrów, lub stosowanie procedur przechowywanych z parametrami o wartościach przechowywanych w tabeli nie zrobi dużej różnicy . Jednak moje ogólne zalecenia są następujące:
Twoja sprawa / proste zapytania z kilkoma parametrami:
Dynamiczny SQL, może z parametrami, jeśli testy wykazują lepszą wydajność.
Zapytania z planami wykonania wielokrotnego użytku, wywoływane wielokrotnie po prostu przez zmianę parametrów lub jeśli zapytanie jest skomplikowane:
SQL z parametrami dynamicznymi.
Zapytania z dużymi listami:
Procedura składowana z parametrami wycenionymi w tabeli. Jeśli lista może się różnić o wiele, użyj Z RECOMPILE procedury składowanej lub po prostu użyj dynamicznego SQL bez parametrów, aby wygenerować nowy plan wykonania dla każdego zapytania.
źródło
Być może możemy użyć XML tutaj:
źródło
CTE
i@x
można je wyeliminować / wstawić do podselekcji, jeśli zostanie to wykonane bardzo ostrożnie, jak pokazano w tym artykule .Podchodzę do tego domyślnie, przekazując funkcję o wartości tabeli (która zwraca tabelę z ciągu) do warunku IN.
Oto kod dla UDF (mam go gdzieś z Stack Overflow, nie mogę teraz znaleźć źródła)
Po uzyskaniu tego kod będzie tak prosty:
Jeśli nie masz absurdalnie długiego łańcucha, powinno to dobrze działać z indeksem tabeli.
W razie potrzeby możesz wstawić go do tabeli tymczasowej, zindeksować, a następnie uruchomić łączenie ...
źródło
Innym możliwym rozwiązaniem jest zamiast przekazywania zmiennej liczby argumentów do procedury składowanej, przekazanie pojedynczego ciągu zawierającego nazwy, których szukasz, ale uczynienie ich unikalnymi poprzez otoczenie ich znakiem „<>”. Następnie użyj PATINDEX, aby znaleźć nazwy:
źródło
Skorzystaj z następującej procedury składowanej. Wykorzystuje niestandardową funkcję podziału, którą można znaleźć tutaj .
źródło
Jeśli w łańcuchu IN mamy zapisane łańcuchy z przecinkami (,), możemy użyć funkcji charindex, aby uzyskać wartości. Jeśli używasz platformy .NET, możesz mapować za pomocą SqlParameters.
Skrypt DDL:
T-SQL:
Możesz użyć powyższej instrukcji w kodzie .NET i zamapować parametr za pomocą SqlParameter.
Demo skrzypka
EDYCJA: Utwórz tabelę o nazwie SelectedTags, używając następującego skryptu.
Skrypt DDL:
T-SQL:
źródło
W przypadku zmiennej liczby takich argumentów jedyny znany mi sposób to albo jawne wygenerowanie kodu SQL, albo zrobienie czegoś, co wymaga zapełnienia tabeli tymczasowej wybranymi elementami i połączenia jej z tabelą tymczasową.
źródło
W ColdFusion po prostu wykonujemy:
źródło
Oto technika, która odtwarza tabelę lokalną do użycia w ciągu zapytania. Wykonanie tego w ten sposób eliminuje wszystkie problemy z analizą.
Ciąg może być zbudowany w dowolnym języku. W tym przykładzie użyłem SQL, ponieważ był to oryginalny problem, który próbowałem rozwiązać. Potrzebowałem czystego sposobu na przekazywanie danych tabeli w locie w ciągu, który zostanie wykonany później.
Korzystanie z typu zdefiniowanego przez użytkownika jest opcjonalne. Tworzenie typu jest tworzone tylko raz i może być wykonane z wyprzedzeniem. W przeciwnym razie po prostu dodaj pełny typ tabeli do deklaracji w ciągu.
Ogólny wzorzec jest łatwy do rozszerzenia i może być używany do przekazywania bardziej złożonych tabel.
źródło
W SQL Server 2016+ inną możliwością jest użycie tej
OPENJSON
funkcji.Takie podejście jest blogowane w OPENJSON - jednym z najlepszych sposobów wybierania wierszy według listy identyfikatorów .
W pełni działający przykład poniżej
źródło
Oto kolejna alternatywa. Po prostu przekaż listę rozdzielaną przecinkami jako parametr ciągu do procedury składowanej i:
I funkcja:
źródło
Mam odpowiedź, która nie wymaga UDF, XML, ponieważ IN akceptuje instrukcję select, np. SELECT * FROM Test gdzie Data IN (SELECT Value FROM TABLE)
Naprawdę potrzebujesz tylko sposobu, aby przekonwertować ciąg znaków na tabelę.
Można to zrobić za pomocą rekurencyjnego CTE lub zapytania z tabelą liczb (lub Master..spt_value)
Oto wersja CTE.
źródło
Używam bardziej zwięzłej wersji najczęściej głosowanej odpowiedzi :
Dwukrotnie przechodzi przez parametry znacznika; ale to nie ma znaczenia przez większość czasu (to nie będzie twoje wąskie gardło; jeśli tak, to rozwiń pętlę).
Jeśli naprawdę interesujesz się wydajnością i nie chcesz dwa razy powtarzać pętli, oto mniej piękna wersja:
źródło
Oto kolejna odpowiedź na ten problem.
(nowa wersja opublikowana 6/4/13).
Twoje zdrowie.
źródło
Jedynym zwycięskim ruchem jest nie grać.
Nie ma dla ciebie nieskończonej zmienności. Tylko skończona zmienność.
W SQL masz taką klauzulę:
W kodzie C # robisz coś takiego:
Zasadniczo więc, jeśli liczba wynosi 0, nie ma filtra i wszystko przechodzi. Jeśli liczba jest większa niż 0, wówczas wartość musi znajdować się na liście, ale lista została uzupełniona do pięciu z niemożliwymi wartościami (aby SQL nadal miał sens)
Czasami kulawe rozwiązanie jest jedynym, które faktycznie działa.
źródło