Zaktualizuj zapytanie za pomocą podzapytania w serwerze SQL

83

Mam prostą strukturę tabeli, taką jak ta:

Tabela tempData

╔══════════╦═══════╗
║   NAME   ║ MARKS ║
╠══════════╬═══════╣
║ Narendra ║    80 ║
║ Ravi     ║    85 ║
║ Sanjay   ║    90 ║
╚══════════╩═══════╝

Mam też inne nazwy tabel, takie jak tempDataView

╔══════════╦═══════╗
║   NAME   ║ MARKS ║
╠══════════╬═══════╣
║ Narendra ║       ║
║ Narendra ║       ║
║ Narendra ║       ║
║ Narendra ║       ║
║ Ravi     ║       ║
║ Ravi     ║       ║
║ Sanjay   ║       ║
╚══════════╩═══════╝

Chcę zaktualizować tabelę tempDataView , ustawiając znaczniki zgodnie z tempDataView - Nazwa w porównaniu z tempData - Nazwa

Tak, pozwól, że pokażę ci, czego próbowałem, próbowałem rozwiązać to za pomocą kursora i zostało rozwiązane idealnie, ale znajduję sposób, aby rozwiązać to za pomocą podzapytania

Oto ona:

Declare @name varchar(50),@marks varchar(50)
Declare @cursorInsert CURSOR
set @cursorInsert = CURSOR FOR
Select name,marks from tempData
OPEN @cursorInsert
FETCH NEXT FROM @cursorInsert
into @name,@marks
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE tempDataView set marks = @marks where name = @name
FETCH NEXT FROM @cursorInsert
INTO @name,@marks
END
CLOSE @cursorInsert
DEALLOCATE @cursorInsert

Właściwie to jak praca domowa, aby rozwiązać to za pomocą podzapytania.

Narendra Pal
źródło

Odpowiedzi:

180

możesz łączyć obie tabele nawet na UPDATEwyciągach,

UPDATE  a
SET     a.marks = b.marks
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

aby zwiększyć wydajność, zdefiniuj INDEXkolumnę markson w obu tabelach.

za pomocą SUBQUERY

UPDATE  tempDataView 
SET     marks = 
        (
          SELECT marks 
          FROM tempData b 
          WHERE tempDataView.Name = b.Name
        )
John Woo
źródło
1
prawda. ale proszę zasugeruj mi jakikolwiek sposób, aby to zrobić za pomocą podzapytania.
Narendra Pal
1
zaktualizowałem odpowiedź za pomocą subquery, ale wolę używać JOINthan SUBQUERY.
John Woo
1
Dlaczego należy definiować INDEXna markskolumnach? Czy nie powinno być na Namekolumnach?
lindelof
1
Wystąpił błąd: podzapytanie zwróciło więcej niż 1 wartość. Nie jest to dozwolone, gdy podzapytanie następuje po =,! =, <, <=,>,> = Lub gdy podzapytanie jest używane jako wyrażenie.
Pradip
1
Wypróbuj samo podzapytanie i dostosuj je, aż uzyskasz tylko 1 wynik. Prawdopodobnie zmiana SELECTnaSELECT TOP 1
vahanpwns
33

ponieważ dopiero się uczysz, proponuję przećwiczyć konwersję złączeń SELECT na złączenia UPDATE lub DELETE. Najpierw proponuję wygenerowanie instrukcji SELECT łączącej te dwie tabele:

SELECT *
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

Następnie zauważ, że mamy dwa aliasy tabel ai b. Korzystając z tych aliasów, można łatwo wygenerować instrukcję UPDATE w celu zaktualizowania tabeli a lub b. Do tabeli A masz odpowiedź udzieloną przez JW. Jeśli chcesz zaktualizować b, wyciąg będzie:

UPDATE  b
SET     b.marks = a.marks
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

Teraz, aby przekonwertować instrukcję na instrukcję DELETE, użyj tego samego podejścia. Poniższe stwierdzenie usunie atylko z (pozostawiając b nienaruszone) dla tych rekordów, które pasują według nazwy:

DELETE a
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

Możesz użyć SQL Fiddle stworzonego przez JW jako placu zabaw

cha
źródło
5
właściwy sposób uczenia się. +1 za wskazanie drogi do nauki. Dzięki
Narendra Pal
3

Tutaj w mojej próbce znajduję rozwiązanie tego, ponieważ miałem ten sam problem z aktualizacjami i podzapytaniami:

UPDATE
    A
SET
    A.ValueToChange = B.NewValue
FROM
    (
        Select * From C
    ) B
Where 
    A.Id = B.Id
sfranco
źródło
1
Dziękuję za tę odpowiedź! Aby pomóc innym to przeczytać, czy możesz szybko dodać wyjaśnienie, dlaczego ten kod rozwiązuje problem?
RedBassett
0

Tytuł tego wątku zawiera pytanie, w jaki sposób można użyć podzapytania w aktualizacji. Oto przykład:

update [dbName].[dbo].[MyTable] 
set MyColumn = 1 
where 
    (
        select count(*) 
        from [dbName].[dbo].[MyTable] mt2 
        where
            mt2.ID > [dbName].[dbo].[MyTable].ID
            and mt2.Category = [dbName].[dbo].[MyTable].Category
    ) > 0
Graham Laight
źródło
Nie jestem pewien, jak to by się w ogóle skompilowało, nie ma grupy według count (*), aby wiedzieć, co liczyć.
crthompson,
@paqogomez po prostu spróbuj - na każdym stole, który ma jakieś rekordy. na przykład. select count (*) z EventLog, gdzie rok = 2018
Graham Laight
Więc po prostu liczysz całą tabelę. Popieram swój głos
negatywny
To jest twój przywilej, ale tytuł tego wątku to "aktualizuj zapytanie przy użyciu podzapytania", a mój przykład najwyraźniej właśnie to robi. fyi Nie liczę „całej tabeli” - po policzeniu (*) następuje klauzula „gdzie” - czyli liczenie wierszy spełniających warunek „gdzie”.
Graham Laight
0

Oto ładne wyjaśnienie operacji aktualizacji z kilkoma przykładami. Chociaż jest to witryna Postgres, ale zapytania SQL są poprawne również dla innych DB. Poniższe przykłady są intuicyjne do zrozumienia.

-- Update contact names in an accounts table to match the currently assigned salesmen:

UPDATE accounts SET (contact_first_name, contact_last_name) =
    (SELECT first_name, last_name FROM salesmen
     WHERE salesmen.id = accounts.sales_id);

-- A similar result could be accomplished with a join:

UPDATE accounts SET contact_first_name = first_name,
                    contact_last_name = last_name
  FROM salesmen WHERE salesmen.id = accounts.sales_id;

Jednak drugie zapytanie może dać nieoczekiwane wyniki, jeśli salesmen.id nie jest unikalnym kluczem, podczas gdy pierwsze zapytanie gwarantuje wygenerowanie błędu, jeśli istnieje wiele zgodnych identyfikatorów. Ponadto, jeśli nie ma dopasowania dla określonego wpisu accounts.sales_id, pierwsze zapytanie ustawi odpowiednie pola nazw na NULL, podczas gdy drugie zapytanie w ogóle nie zaktualizuje tego wiersza.

Dlatego dla podanego przykładu najbardziej wiarygodne zapytanie jest takie jak poniżej.

UPDATE tempDataView SET (marks) =
    (SELECT marks FROM tempData
     WHERE tempDataView.Name = tempData.Name);
Memin
źródło
Niestety pierwsza forma nie działa na serwerze MS SQL.
AntoineL