2010-03-02 17 views
6

Mam kod podobny do następującego w procedurze przechowywanej, która wstawia wiersz do tabeli, Chciałbym ustawić ostatnią kolumnę (FieldD) do @prmSomeValue, chyba że jest on zerowy, w przeciwnym razie wystarczy użyć wartości domyślnej zdefiniowane dla tej kolumny.Czy istnieje sposób warunkowego używania domyślnych wartości kolumny w instrukcji INSERT..SELECT?

IF (@prmSomeValue IS NULL) 
    INSERT INTO MyTable (fieldA,FieldB,FieldC) 
     SELECT A,B,C 
     FROM MyOtherTable 
ELSE 
    INSERT INTO MyTable (fieldA,FieldB,FieldC,FieldD) 
     SELECT A,B,C,@prmSomeValue 
     FROM MyOtherTable 

Działa, ale narusza zasadę DRY. Próbuję znaleźć sposób, aby to zrobić za pomocą pojedynczej instrukcji wstawiania. Coś wzdłuż linii następującego pseudokodu.

INSERT INTO MyTable (fieldA,FieldB,FieldC,FieldD) 
     SELECT A,B,C,ISNULL(@prmSomeValue,DEFAULT) 
     FROM MyOtherTable 

Ktoś ma jakieś pomysły?

Update - Jeszcze jeden skręt
Domyślne ograniczenie nie jest wartością dosłowne, ale funkcja, jak pokazano poniżej.

...DEFAULT (suser_sname()) FOR [FieldD] 

Aktualizacja
I wreszcie punted i wybrał mniejsze zło i po prostu kopiowane domyślną funkcję wartości do mojego zapytania zamiast spada aż do domyślnie skonfigurowany do kolumny. Nie podoba mi się to, ale wykonuje to zadanie z mniejszą liczbą powtórzeń w zapytaniu.

INSERT INTO MyTable (fieldA,FieldB,FieldC,FieldD) 
     SELECT A,B,C,ISNULL(@prmSomeValue,suser_sname()) 
     FROM MyOtherTable 

Odpowiedz

3

Ponieważ w istocie to, co robi SQL Server, można zrobić coś takiego, aby uniknąć przynajmniej dwa prawie identyczne wypowiedzi (pseudo-kod):

INSERT (columnA,B,C) ... ; 

IF @prmSomeValue IS NOT NULL 
    UPDATE ... ; 

Nie sądzę, że istnieje droga do COALESCE z wartością domyślną.

+0

Interesujący pomysł. Nie jestem pewien, czy jest to lepsze, ale zdecydowanie warte podniesienia. – JohnFx

+0

Dzięki JohnFx, myślę, że może być lepiej, gdy istnieje więcej niż jedna opcjonalna kolumna, która ma być traktowana w ten sposób. Wtedy możesz powiedzieć "JEŚLI nie jest NULL ORB lub NIE JEST NULL, UPDATE SET foo = COALESCE (@foo, foo), bar = COALESCE (@bar, bar) GDZIE" itp., Zamiast pisania instrukcji insert dla każdej możliwej kombinacji. –

+0

Użyj ISNULL zamiast COALESCE, COALESCE jest przeznaczony dla wielu argumentów. Nie pójdę do pola = podejście do parametrów/pola, zabije wydajność SQL, co utrudni optymalizację zapytań i wykorzystanie indeksów. Prosta instrukcja if byłaby znacznie wydajniejsza. – Zyphrax

0

Ten potęga praca zależy jeśli oznacza domyślną wartość określoną w domyślnej przymusu lub w kodzie? Jeśli "ograniczenie" nie powiedzie się, jeśli "kod" działa. Edytuj: masz na myśli ograniczenie. doh!

SELECT A,B,C,@prmSomeValue 
     FROM MyOtherTable 
     WHERE @prmSomeValue IS NOT NULL 
UNION ALL 
SELECT A,B,C,DEFAULT 
     FROM MyOtherTable 
     WHERE @prmSomeValue IS NULL 

Który kiedykolwiek sposób chcesz to zrobić, określając kolumny w klauzuli INSERT wymaga wartości.

Więc pierwsze rozwiązanie jest to, co masz zrobić ...

+0

mi chodziło domyślne ograniczenia zdefiniowane dla kolumny. Tak, jak zrobiłaby to pierwsza połowa mojego IF. Więc to nie zadziała. Uwaga: Nie jest bezwzględnie wymagane określenie kolumny w klauzuli INSERT. Mogę polegać na uporządkowaniu kolumn, jeśli jest to konieczne, chociaż wolę tego nie robić. – JohnFx

+0

JohnFx, jeśli pominiesz listę kolumn, będziesz musiał wybrać kolejną opcję z taką samą liczbą kolumn, które pasują do tabeli, w przeciwnym razie otrzymasz: "Msg 213, Poziom 16, Stan 1, Linia 1 Nazwa kolumny lub liczba podanych wartości nie pasuje do definicji tabeli. " Nawet gdyby to zadziałało, kradną bym bardzo ostrożny w powoływaniu się na kolejność kolumn (twój instynkt jest właściwy, IMHO). –

2

Powiedziałbym, że twoja metoda jest w porządku. Prosta kontrola, po której następuje jedna wkładka. Jeśli martwisz się o DRY, obuduj połączenie tak, aby było wywoływane wielokrotnie.

Powiedziałbym, że inserty/aktualizacje na db mogą być kosztowne na niektórych tabelach (zależy od celu projektu), więc jeśli musisz napisać dodatkowy kod, aby obsłużyć ten scenariusz, wtedy nie widzę problemu z kompromisem.

+0

+1, dobrze jest próbować zapobiegać duplikowaniu bloków kodu. Jednak wielu programistów próbuje zastosować do T-SQL swoje zasady OO i praktyki kodowania. Często powoduje to piękne, ale nieskuteczne zapytania. Czasami świetnym rozwiązaniem jest napisanie 5 dość podobnych zapytań zamiast 1 pół-dynamicznego - Zachowaj swój kod w niezmienionej postaci, scentralizowany w ramach jednej procedury przechowywanej, łatwy w utrzymaniu. – Zyphrax

+0

Czy nie wiesz, że biją te rzeczy w nasze głowy do punktu, w którym fizycznie boli, aby praktycznie ten sam kod był duplikowany na każdym końcu warunkowego? =) Możliwe, że masz rację, być może zbytnio to myślę. – JohnFx

+1

Gdy masz tylko A lub B, to zgadzam się, że może być dobrze, jak jest. Ale co się dzieje, gdy masz cztery takie kolumny? Liczba możliwych instrukcji INSERT, których potrzebujesz, na podstawie których parametry są NULL bardzo szybko wybucha. Czasami trzeba zrównoważyć wydajność i utrzymanie. –

0

Coś takiego może działać (tho niezbyt ładna):

INSERT INTO MyTable (fieldA,FieldB,FieldC,FieldD) 
SELECT A,B,C, 
    case when @prmSomeValue is null 
then 
     (SELECT text FROM syscomments WHERE id IN (SELECT cdefault FROM syscolumns 
      WHERE id = object_id('MyTable') AND cdefault > 0)) 
    else @prmSomeValue 
    end 
FROM MyOtherTable 
+2

Co stanie się, jeśli wartością domyślną jest rzeczywiście formuła (na przykład GETDATE() lub NEWID())? będzie interpretowany jako ciąg, prowadzący do błędu lub niepoprawnych danych, w zależności od typu danych kolumny. Czy nie chcesz się upewnić, że otrzymujesz właściwą kolumnę (może być więcej niż jedna kolumna, gdzie cdefault> 0, prowadząc do Msg 512 - podzapytanie zwróciło więcej niż jedną wartość)? W przypadku programu SQL Server 2008 nie należy używać widoków katalogu zamiast przestarzałych tabel systemowych? –

+0

Zastanawiałem się nad podobnym podejściem, ale byłem nieco zaniepokojony problemami ubocznymi lub problemami związanymi z używaniem tabel systemowych, ale sądzę, że jest wystarczająco solidny. Jakieś zastrzeżenia do zaoferowania w tej technice? – JohnFx

+0

Doh! Jeden poważny problem z tym podejściem. Jeśli domyślnie jest funkcją, po prostu wstawia nazwę funkcji, w moim przypadku "getdate()". Niezła próba. – JohnFx

Powiązane problemy