Aktualisieren Sie die Abfrage mithilfe der Unterabfrage in SQL Server

80

Ich habe eine einfache Tabellenstruktur wie diese:

Tabelle tempData

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

Und ich habe auch andere Tabellennamen wie tempDataView wie diese

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

Ich möchte die Tabelle aktualisieren tempDataView , indem Sie die Einstellung Marks auf die nach tempDataView - Namen verglichen mit TempData - Namen

Ja, lassen Sie mich Ihnen zeigen, was ich versucht habe. Ich habe versucht, dies mit dem Cursor zu lösen, und es ist perfekt gelöst, aber ich finde den Weg, es mit der Unterabfrage zu lösen

Hier ist es:

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

Eigentlich ist es für mich wie eine Hausaufgabe, sie mit der Unterabfrage zu lösen.

Narendra Pal
quelle

Antworten:

176

Sie können beide Tabellen auch bei UPDATEAnweisungen verbinden.

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

Definieren Sie für eine schnellere Leistung eine INDEXOn-Spalte marksin beiden Tabellen.

mit SUBQUERY

UPDATE  tempDataView 
SET     marks = 
        (
          SELECT marks 
          FROM tempData b 
          WHERE tempDataView.Name = b.Name
        )
John Woo
quelle
1
es ist richtig. aber bitte schlagen Sie mir eine Möglichkeit vor, dies mithilfe der Unterabfrage zu tun.
Narendra Pal
1
aktualisierte die Antwort mit subquery, aber ich benutze lieber JOINals SUBQUERY.
John Woo
1
Warum sollte man ein INDEXauf den marksSpalten definieren? Sollte es nicht auf den NameSpalten sein?
Lindelof
1
Es ist ein Fehler aufgetreten: Die Unterabfrage hat mehr als einen Wert zurückgegeben. Dies ist nicht zulässig, wenn die Unterabfrage folgt = ,! =, <, <=,>,> = Oder wenn die Unterabfrage als Ausdruck verwendet wird.
Pradip
1
Probieren Sie die Unterabfrage selbst aus und passen Sie sie an, bis Sie nur noch 1 Ergebnis erhalten. Wahrscheinlich ändern Sie SELECTzuSELECT TOP 1
vahanpwns
33

Da Sie gerade erst lernen, empfehle ich Ihnen, das Konvertieren von SELECT-Joins in UPDATE- oder DELETE-Joins zu üben. Zuerst schlage ich vor, dass Sie eine SELECT-Anweisung generieren, die diese beiden Tabellen verbindet:

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

Beachten Sie dann, dass wir zwei Tabellen-Aliase aund haben b. Mit diesen Aliasen können Sie einfach eine UPDATE-Anweisung generieren, um entweder Tabelle a oder b zu aktualisieren. Für Tabelle a haben Sie eine Antwort von JW. Wenn Sie aktualisieren möchten, lautet bdie Anweisung:

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

Um die Anweisung in eine DELETE-Anweisung zu konvertieren, verwenden Sie denselben Ansatz. Die folgende Anweisung wird anur aus (wobei b intakt bleibt) für die Datensätze gelöscht , die nach Namen übereinstimmen:

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

Sie können die von JW erstellte SQL-Geige als Spielplatz verwenden

cha
quelle
5
der richtige Weg zu lernen. +1 für den Weg zum Lernen zu zeigen. Danke
Narendra Pal
2

Hier in meinem Beispiel finde ich die Lösung dafür, weil ich das gleiche Problem mit Updates und Subquerys hatte:

UPDATE
    A
SET
    A.ValueToChange = B.NewValue
FROM
    (
        Select * From C
    ) B
Where 
    A.Id = B.Id
sfranco
quelle
1
Vielen Dank für diese Antwort! Können Sie schnell eine Erklärung hinzufügen, warum dieser Code das Problem löst, um anderen beim Lesen zu helfen?
RedBassett
0

Der Titel dieses Threads fragt, wie eine Unterabfrage in einem Update verwendet werden kann. Hier ist ein Beispiel dafür:

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
quelle
Ich bin mir nicht sicher, wie dies überhaupt kompiliert werden soll. Es gibt keine Gruppe, für die die Zählung (*) weiß, was zu zählen ist.
Paqogomez
@paqogomez probieren Sie es einfach aus - auf jeder Tabelle, die Datensätze enthält. z.B. Wählen Sie count (*) aus EventLog, wobei year = 2018
Graham Laight
Dann zählen Sie einfach die gesamte Tabelle. Ich stehe zu meiner Abwahl, das hat nichts mit der Frage zu tun (unabhängig vom Titel)
paqogomez
Das ist Ihr Vorrecht, aber der Titel dieses Threads lautet "Abfrage mit Unterabfrage aktualisieren", und mein Beispiel macht selbstverständlich genau das. fyi Ich zähle nicht "die gesamte Tabelle" - auf count (*) folgt eine "where" -Klausel - also werden Zeilen gezählt, die die "where" -Bedingung erfüllen.
Graham Laight
0

Hier ist eine schöne Erklärung des Update-Vorgangs mit einigen Beispielen. Es handelt sich zwar um eine Postgres-Site, die SQL-Abfragen gelten jedoch auch für die anderen DBs. Die folgenden Beispiele sind intuitiv zu verstehen.

-- 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;

Die zweite Abfrage kann jedoch zu unerwarteten Ergebnissen führen, wenn salesmen.id kein eindeutiger Schlüssel ist, während die erste Abfrage garantiert einen Fehler auslöst, wenn mehrere ID-Übereinstimmungen vorliegen. Wenn für einen bestimmten Eintrag in accounts.sales_id keine Übereinstimmung besteht, setzt die erste Abfrage die entsprechenden Namensfelder auf NULL, während die zweite Abfrage diese Zeile überhaupt nicht aktualisiert.

Daher ist für das gegebene Beispiel die zuverlässigste Abfrage wie folgt.

UPDATE tempDataView SET (marks) =
    (SELECT marks FROM tempData
     WHERE tempDataView.Name = tempData.Name);
Memin
quelle
Leider funktioniert das erste Formular in MS SQL Server nicht.
AntoineL